GMS 2.3+ Optimisation Tips for Array Loops.

erayzesen

Member
Hi. Firstly I want to explain with samples what's my problem.

I have vec2 based point object, just like that;

GML:
function physics_point(_x,_y,_r,_mass):vec2() constructor{
    x=_x;
    y=_y;
    old_x=x;
    old_y=y;
    r=_r;
static update_velocities=function (){
        //Verlet
        vx=(x-old_x);
        vy=(y-old_y);

        vx+=mass*get_gravity_x();
        vy+=mass*get_gravity_y();
       
        old_x=x;
        old_y=y;
       
        x+=vx;
        y+=vy;
    }
obj_physics_system.points[array_length(obj_physics_system.points)]=self;
}
I store all these point objects that I created in the room in an array; obj_physics_system->points

And I make a loop and call in step event of an game object.

Code:
//Step Event
var point_count=array_length(points);
for(i=point_count;i>-1;i--){
    var point=points[i-1];
    point.update_volecities();
}
In my test, every time I click with the mouse, it creates 4 points and adds it to the array.

And every time I click it drops incredibly more real-fps. I can not understand how it fell this much. Isn't that so strange in your opinion?

What should I do for this, please guide me. Generally, I consider the performance of the game maker sufficient, but I had serious disappointments in this project.

In the past, I wouldn't even count how many loops, how many queries, how many functions I run simultaneously in Adobe Flash. I hope I'm doing something wrong.
 
Last edited:

TsukaYuriko

☄️
Forum Staff
Moderator
In my test, every time I click with the mouse, it creates 4 points and adds it to the array.

And every time I click it drops incredibly more real-fps. I can not understand how it fell this much. Isn't that so strange in your opinion?
That entirely depends on what kind of drop we're talking about here. Please provide a concrete example. A drop in FPS is perfectly normal and expected when your game has to process more every frame.

Quite often, FPS "issues" are merely a misunderstanding of how FPS (and especially real FPS) is calculated, leading to FPS drops feeling way out of proportion when they are in reality minimal.
 

erayzesen

Member
That entirely depends on what kind of drop we're talking about here. Please provide a concrete example. A drop in FPS is perfectly normal and expected when your game has to process more every frame.
Ok. I'm testing the game.
Empty room: 6000-7000
First click: 4000 fps -4 point
2th click: 3200 fps - 8 point
3th click: 2500 fps - 12 point
...
40th click: 300 fps - 120 point

Is it normal for 120 objects to use this many fps for such a simple loop? Isn't there a way to do this?

I did a test with Box2d built in, filled the screen with boxes and I guess there are tens of thousands of compute cycles. Even so, the real fps is over 1000. How can this be? I have reviewed Box2d codes and it has an incredibly large number of loops.

Generally, isn't there a solution for such multiple loops?

Quite often, FPS "issues" are merely a misunderstanding of how FPS (and especially real FPS) is calculated, leading to FPS drops feeling way out of proportion when they are in reality minimal.
I understand, but when this value falls below 60, the fps value of the game also decreases. I see this as the potential fps we have outside of the game's frame rate. Am I thinking wrong?
 

TsukaYuriko

☄️
Forum Staff
Moderator
What are get_gravity_x and get_gravity_y? Please post their code as well.

The code you've shown so far shouldn't be using much of anything unless it's being ran on an ancient system, so I'll tentatively agree that something seems weird about it. To find out which part of the code is using up the most performance, please run your game in debug mode, turn on the profiler while you have a lot of points already spawned and let us know the results.
 

erayzesen

Member
What are get_gravity_x and get_gravity_y? Please post their code as well.

The code you've shown so far shouldn't be using much of anything unless it's being ran on an ancient system, so I'll tentatively agree that something seems weird about it. To find out which part of the code is using up the most performance, please run your game in debug mode, turn on the profiler while you have a lot of points already spawned and let us know the results.
get_gravity_x is;
GML:
function get_gravity_x(){
    if(!instance_exists(obj_physics_system)){
        show_debug_message("PHYSICS ERROR: obj_physics_system doesn't findd in the room!");
    }else{
        return obj_physics_system.gravity_x;
    }   
}
This is an unnecessary process, it has to be done differently, but when I remove it, nothing much changes.

My profiler caps;
Screen Shot 2020-11-30 at 20.06.42.png
Screen Shot 2020-11-30 at 20.06.58.png

I gues "anon_physics_point_gml_....1392" is my update_velocities function.
 

GMWolf

aka fel666
Don't measure things in FPS. Because fps is 1/frame time you get steep drops at high FPS.

Measure frame time instead:

4000fps is 0.00025 seconds dt. (4 Points)
2500fps is 0.0004 seconds dt (12 Points)
300fps is 0.003333... seconds dt. (120 Points)
It looks pretty linear to me.
So by adding 116 points you increased your frame time by 0.003 seconds.
Which means you can add about 644 points before you no longer run at 60fps.

Granted, not great. But maybe enough for what you need?
Also have you tried the YYC?

Note that methods are going to be slow because they are polymorphic.
Rather than have point.update_velocities, try doing update_velocities( point ).
 

erayzesen

Member
Don't measure things in FPS. Because fps is 1/frame time you get steep drops at high FPS.

Measure frame time instead:

4000fps is 0.00025 seconds dt. (4 Points)
2500fps is 0.0004 seconds dt (12 Points)
300fps is 0.003333... seconds dt. (120 Points)
It looks pretty linear to me.
So by adding 116 points you increased your frame time by 0.003 seconds.
Which means you can add about 644 points before you no longer run at 60fps.
Hmm... I understand you. So we always have to use maximum nearly 1/60*1000=16 ms for per frame if we use 60 fps in the game.

Granted, not great. But maybe enough for what you need?
Also have you tried the YYC?
Yep, I tried. It gives me more performance but it's not enough. I think there is an abnormal situation here that I have not experienced before.

Although what I've done so far is not enough, it has made a difference. I have to find different ways with gms.

But I will figure it out. If I have a remarkable improvement, I'll write it here.

Perhaps in this process, other friends can share tips for such crowded loops.
 

Gradius

Member
Seems like you're wasting time checking if an object is inn existence within the individual functions within the loop instead of just checking once outside of the functions. If you passed the gravity variables into the update function instead, looping through 200 points would reduce 400 instance checks, 400 if statements, and 400 reads to variables in other objects down to... well 1 of the first 2 and 2 of the last one. Or you could just skip the headache and make the gravity into a global variable, which is perfectly appropriate when you've got data that a ton of different objects are going to want to access anyway.

There's also always the possibility of storing your point objects as just an array or list (you can use enums to allow you to still use named 'variables' for the properties), which is likely going to be a bit faster than working with any sort of object.
 
Top