GMS 2 Bizarre performance decreasing, random-number related Issue

Fluury

Member

I had posted a thread earlier about my issues, but unfortunately to no avail.

Given there was a lot of information to write, I just put it in a video.

The gist is that as it appears, in some context, using random number generation just seems to cause some internal, permanent (until you close the game atleast) slowdown. I don't know if there is something I can do to fix this given the earlier thread didn't seem to really resolve, but it really just came down to me trying to replicate the "general area" of the issue until I noticed that after I set the "lines" to be a random length long, the performance started to go down the drain the more times I'd reset the level (or well, barcode in this case.)

PROJECT DOWNLOAD TO TINKER WITH: https://www.dropbox.com/s/lm7zycbwzl104vk/GenPerfProblem.rar?dl=0

As I said in the video, I am 100% clueless as to what is going on - if this is a bug, if I forgot something obvious - I do not know what to think of this.

If you have any ideas or thoughts, please post 'em.
 

Nidoking

Member
May I guess that the non-random length you set for your testing was closer to 100 than 200? I saw the same results you described in the video using random (dropping FPS) and a constant max of 100 (steady FPS), but when I set the constant max to 200, I see the same performance hit. It's not the randomization, but the increased number of instances. Even though they have no code, they're still drawing to the screen and still calculating movement, and that's what's taking up all that processing (according to the Profiler, which I recommend checking out). Why it increases over time even when you stop generating the lines, I don't know, but it's likely some internal Game Maker thing, like garbage collection that's way behind the destruction of instances, or something to do with exceeding a number of active instances that spills over a threshold from which there is no return.
 

obscene

Member
It's definitely related to instance_create_layer(). Commenting out that line seemed to stabilize the FPS for me. The random functions seemed to have no impact.

I made a script to average the FPS over 10,000 frames at a time so it was easier to monitor since the FPS will be running wild if you comment out the instance creation. I saw no downward trend even after a few minutes.

If you agree, it's probably unfortunately a bug in GMS2.
 

Fluury

Member
May I guess that the non-random length you set for your testing was closer to 100 than 200? I saw the same results you described in the video using random (dropping FPS) and a constant max of 100 (steady FPS), but when I set the constant max to 200, I see the same performance hit. It's not the randomization, but the increased number of instances. Even though they have no code, they're still drawing to the screen and still calculating movement, and that's what's taking up all that processing (according to the Profiler, which I recommend checking out). Why it increases over time even when you stop generating the lines, I don't know, but it's likely some internal Game Maker thing, like garbage collection that's way behind the destruction of instances, or something to do with exceeding a number of active instances that spills over a threshold from which there is no return.
The non random-length I used to test was 150 afaik, but as I said in the video I was very unsure about it. Of course if you set it to 200, the FPS will be lower by default. The point of the video is that despite being seed 0, coming back to seed 0 you end up with less performance than before if you were to generate a bunch of instances over the timeframe, and then wipe them.

I believe I had tested the interaction with a set amount of max instances for each walker and a random amount, and the FPS would would not decrease in the case of set, but *would* decrease in the case of random max. I will test this again later.

The big issue at hand is mostly the permanent performance loss as you had stated, which is quite a big deal to me.

It's definitely related to instance_create_layer(). Commenting out that line seemed to stabilize the FPS for me. The random functions seemed to have no impact.

I made a script to average the FPS over 10,000 frames at a time so it was easier to monitor since the FPS will be running wild if you comment out the instance creation. I saw no downward trend even after a few minutes.

If you agree, it's probably unfortunately a bug in GMS2.
I am personally speculating that it seems to be a combination of both - and to be quite frank, if it really is 100% related to the creation of instances I... don't exactly know how to circumvent that issue? Doesn't this imply that if you have a project create a bunch of instances, that after some threshold it will create a permanent burden on the project - if only gradually? Where even is that threshold?
 

Fluury

Member
Just tested it again. It has to be related to the random number generation at the start of oWalker that determines how many tiles each walker gets to create. Doing this with a set number for the max amount of walkers does not result in a permanent performance loss, it only seems to happen if you use random number generation for the max amount of instances each walker spawns.

If you want to test this yourself, do the following:
- Replace the random-generation with a set number. I personally used 200.
- Generate a barcode for seed 0, note down your FPS. Mine was 390~.
- Now, generate a bunch of barcodes for (still) different seeds. The max length will be the same for every walker.
- Stop. Go back to seed 0. Generate the seed 0 barcode, and check your FPS. Mine was still at around 390, despite having generated barcodes for 10 minutes or so.

In comparison when I set it back to the random number max-length, even after 3 minutes of generating the FPS tanked by 100 as demonstrated in the video.

@obscene
 

Yal

🐧 *penguin noises*
GMC Elder
This is starting to sound like it belongs in a bug report. Creating instances dynamically is essential to basically every project, it shouldn't cause slowdown. I'd recommend reporting this to Yoyo, including the example project file and a link to this topic.

One final straw to grasp at first, though: does instance_create_depth() also have the slowdown? Maybe the get-layer-by-string functionality leaks the string data or something while the "just check depths" version doesn't?
 

Fluury

Member
This is starting to sound like it belongs in a bug report. Creating instances dynamically is essential to basically every project, it shouldn't cause slowdown. I'd recommend reporting this to Yoyo, including the example project file and a link to this topic.

One final straw to grasp at first, though: does instance_create_depth() also have the slowdown? Maybe the get-layer-by-string functionality leaks the string data or something while the "just check depths" version doesn't?
I plan to tinker around with this program a bit more later today and will report on the findings. The reason why I am so confused is that this seems like a massive deal - why... did no one else seemingly report this already? As you said, this is something that should happen in quite literally every project if said project creates a bunch of instances (using random number generation(?))

As for your suggestion, I have not tried instance_create_depth() yet, I can however confirm that if instead of the layer-by-string you use a value that stored the layer id using layer_get_id(), this issue still occurs.

If all fails, how would I be to report this issue to Yoyo? Is there a specific bug-report forum/form or is it just the classic "Submit a request" over at the support forum? From googling it seems to be the latter, but I'd like to be sure.
 

Yal

🐧 *penguin noises*
GMC Elder
If all fails, how would I be to report this issue to Yoyo? Is there a specific bug-report forum/form or is it just the classic "Submit a request" over at the support forum? From googling it seems to be the latter, but I'd like to be sure.
Inside Game Maker, Help --> Report A Bug should open the correct page in your default browser.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I would report this as a bug. I have spent a good hour studying your example and testing various different things and the only conclusion I can come to is that there is an issue with the random functions. When you file the bug, please link to this topic, link to the video you made, and also include the link to the project you've made and explain how it works, mentioning specifically that it looks like something is wrong with the random functions, as using a fixed value instead of using the random ones does not show the performance decrease.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Okay, so, after a chat with one of the devs, we have a solution to the issue.

It appears that reusing a layer like this is the issue. If you move the controller onto a different layer then modify the code so it is this:

GML:
if(auto_generate and !instance_exists(oWalker)){
    layer_destroy(layer_get_id("Instances"));
    layer_create(0, "Instances");
    instance_destroy(oTile);
    if(!set_seed)randomize();
    else random_set_seed(0);
    alarm[0] = 1;
}
The issue is resolved. It seems that there is some underlying issue with layers not cleaning up internal structures correctly, possibly exacerbated by the use of the random functions... So, still file the bug, but now you can at least point to precisely what the issue is (and work around it in your games).
 

saffeine

Member
does this also apply to instances created with depth, or just layers?
i'm not sure if instances added with depth are added to the same layer as the instance that called it, so clarification would be great.
 

Fluury

Member
Okay, so, after a chat with one of the devs, we have a solution to the issue.

It appears that reusing a layer like this is the issue. If you move the controller onto a different layer then modify the code so it is this:

GML:
if(auto_generate and !instance_exists(oWalker)){
    layer_destroy(layer_get_id("Instances"));
    layer_create(0, "Instances");
    instance_destroy(oTile);
    if(!set_seed)randomize();
    else random_set_seed(0);
    alarm[0] = 1;
}
The issue is resolved. It seems that there is some underlying issue with layers not cleaning up internal structures correctly, possibly exacerbated by the use of the random functions... So, still file the bug, but now you can at least point to precisely what the issue is (and work around it in your games).
Ah shucks, I submitted the bug like 10 minutes ago. Well, I did link the thread.

Still, an absolutely massive thank you. After submitting the bug I was just kinda sitting there wondering how I should circumvent this issue, but it being related to layers and the random functions somehow making the problem even *worse* is interesting to me. More importantly, I just wonder how many projects are affected by this, without the developers even knowing what's going on. This seems like quite the significant bug!

Thank you again. I will implement this later, which should hopefully deal with the performance problems my original project was facing.

does this also apply to instances created with depth, or just layers?
i'm not sure if instances added with depth are added to the same layer as the instance that called it, so clarification would be great.
In all the projects (and in the original project) I worked on I was working with layers exclusively, I don't know if addition via depths would circumvent this issue. It's worth trying out for sure.
 
Last edited:

Fluury

Member
Okay, so, after a chat with one of the devs, we have a solution to the issue.

It appears that reusing a layer like this is the issue. If you move the controller onto a different layer then modify the code so it is this:

GML:
if(auto_generate and !instance_exists(oWalker)){
    layer_destroy(layer_get_id("Instances"));
    layer_create(0, "Instances");
    instance_destroy(oTile);
    if(!set_seed)randomize();
    else random_set_seed(0);
    alarm[0] = 1;
}
The issue is resolved. It seems that there is some underlying issue with layers not cleaning up internal structures correctly, possibly exacerbated by the use of the random functions... So, still file the bug, but now you can at least point to precisely what the issue is (and work around it in your games).
Welp, I came around to actually try your suggestion and unfortunately it did not fix anything for me. I made a new layer over the old Instances layer, placed the Controller object in there and then modified the code as you suggested.

The performance still goes down the drain after generating a bunch of walkers over and over again :( I triple checked that I did everything correctly given there isnt exactly a lot of room for error when it comes to just adding two lines, a new layer and moving an object from one layer to a different one.

Can someone else in the thread test this? Because my performance goes from 500 to 350 after like 2 minutes of generating.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
That's interesting... I was getting fairly steady 560fps after applying this... Oh well, let's just wait and see what the guys in tech support have to say!!!
 

Fluury

Member
I'm mostly interested if that means the problem is on my side somehow. Given this, well, kinda halts the development of the project I am working on in a lot of ways given I wouldn't want to keep working on it while this issue persists and I am still iffy on what exactly causes it.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Can't you work on other parts, like UI or something for a day or two until you get a reply back?
 

Fluury

Member
I feel like something worth mentioning is that this issue also happens if, instead of a random function, you instead of use (for example) 100 + get_timer() mod 100;.

Moving the random function over to oController and using with() with the new walker instance doesnt fix the issue either.

I suppose it's finally time for me to pass the torch to the tech guys and wait until then and stop wasting me time trying to dance around this.
 

Yal

🐧 *penguin noises*
GMC Elder
I feel like something worth mentioning is that this issue also happens if, instead of a random function, you instead of use (for example) 100 + get_timer() mod 100;.
Does it happen if you don't use mod specifically? Basic random number generators are usually modulo-based (add a prime number to the current seed, modulo by a different prime number, return the remainder) so maybe the random issue is caused by mod leaking memory?
 

Fluury

Member
Does it happen if you don't use mod specifically? Basic random number generators are usually modulo-based (add a prime number to the current seed, modulo by a different prime number, return the remainder) so maybe the random issue is caused by mod leaking memory?
As said earlier, the "bug" doesn't happen if you use a fixed number. Unless you are implying I should try out writing something up that would simulate a random function without using mod, where I'll be frank with you I wouldn't really know where to begin with :V
 

Yal

🐧 *penguin noises*
GMC Elder
As said earlier, the "bug" doesn't happen if you use a fixed number. Unless you are implying I should try out writing something up that would simulate a random function without using mod, where I'll be frank with you I wouldn't really know where to begin with :V
I'm not suggesting that, I'm just saying that if both GM mod and random functions exhibit the same issue, it might be because the leak is in mod specifically (which could help solve the bug faster).
 

Fluury

Member
I'm not suggesting that, I'm just saying that if both GM mod and random functions exhibit the same issue, it might be because the leak is in mod specifically (which could help solve the bug faster).
I see! That sounds very plausible! That would actually make even more sense; I have a lot of functions in the level gen which use mod over and over in some steps. That might be why the performance goes down even after only generating 5 levels, because of the sheer frequency of mod being used.
 

Yal

🐧 *penguin noises*
GMC Elder
We could actually replace mod with a script like this, now when you mention it...
GML:
///mood(num,divisor)
return argument0 - (argument0 div argument1)*argument1;
It's going to be a pretty messy transition since you need to change the calling syntax from a mod b ---> mod(a,b) but it could be an interesting check to test if mod specifically has the issue.
(Fixing the random numbers is gonna be a bit more tedious, though, and I don't have any quick-and-dirty answers for that)
 

Fluury

Member
We could actually replace mod with a script like this, now when you mention it...
GML:
///mood(num,divisor)
return argument0 - (argument0 div argument1)*argument1;
It's going to be a pretty messy transition since you need to change the calling syntax from a mod b ---> mod(a,b) but it could be an interesting check to test if mod specifically has the issue.
(Fixing the random numbers is gonna be a bit more tedious, though, and I don't have any quick-and-dirty answers for that)
Gave it a shot. Performance still goes down the drain interestingly enough. Sure hope the tech lads leave a reply this week because man this is weird.
 

Fluury

Member
I wouldn't want to be awfully pushy about this, especially considering the current situation, but uuh, how long does it usually take for the tech lads to reply to a bug report..?

EDIT: Aaand caught, cheers!
 
Last edited:
Top