Jump to content


Photo

25 optimizing techniques for Game Maker.


  • This topic is locked This topic is locked
98 replies to this topic

#1 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 10:40 AM

25 Optimizing techniques for Game Maker.

I have collected some optimization techniques. There are a lot of techniques which are already mentioned in previous topics. But I just want to gather them in one topic. Inclusive my own optimization techniques.

1. "Synchronization to avoid tearing" (Global Game Settings -> Resolution)
Set this off if you don't really need it. It heavenly affects the CPU.


2. Execute_string,draw_Getpixel, variable_local_set() , surface_getpixel() ...
Those are quite heavy functions for GM. That doesn't mean you can't use them at all. Use them wisely, for example in loading screens or at the end of a game.


3.Instance destroying/deactivating
Destroy instances if you don't need them anymore (instance_destroy()). Deactivate instances if you don't need them now. (instance_deactivate())

This piece of code will first deactiviate everything outside the view 0 and then it activates everything inside the view.
instance_deactivate_region(view_xview[0], view_wview[0], view_hview[0], false, true);

instance_activate_region(view_xview[0], view_yview[0], view_wview[0], view_hview[0], true);



4. Precise collision checking (Sprites)
If you don't need precise pixel collision for a particular sprite, just turn it off.


5.Divisions and trig calculations.

Divisions need a lot more CPY cycles then multiplications or subtractions.
And trig calculations need even more CPU cyles. So avoid using them where possible.
You can try to find faster or other algorithms.

Example "unoptimized code"

player.x += variableA* (1/4) + sin(VariableB)/cos(VariableB)

You can easily optimize it into this:

player.x += 0.25*variableA + tan(VariableB) ;


6. Background Color
Like the Game Maker manual says: "If you have a covering background, make sure you switch off the use of a background color."


7. With construction
Don't underestimate this construction. You can use "with" when you are changing different variables or executing different functions from the same object.

Example "unoptimized code" (From a debug screen in draw event)
draw_text(view_xview[0]+10,view_yview[0]+10,"Speed: "+ string(obj_Player.Speed)) ;
draw_text(view_xview[0]+10,view_yview[0]+27,"direction:"+ string(obj_Player.direction)) ;
draw_text(view_xview[0]+10,view_yview[0]+44,"angle:"+ string(obj_Player.angle)) ;

You can optimize it into this:
with (obj_Player)
{
draw_text(view_xview[0]+10,view_yview[0]+10,"Speed: "+ string(Speed)) ;
draw_text(view_xview[0]+10,view_yview[0]+27,"direction: "+ string(direction)) ;
draw_text(view_xview[0]+10,view_yview[0]+44,"angle: "+ string(angle)) ;
}




9. Switch statement
A common mistake when beginners are programming something is this:

if (a = 5) 
{
//Do something
}
else
{
  if (a = 6)
  {
	//Do something
  }
  else
  {
 	if (a = 7)
	{
	//Do something
	} ...
  }
}

Change this into a switch statement (which is faster):

switch (a)
{
case 5: /*do something*/ break ;

case 6: /*do something else*/ break ;

case 7: /*do something else */ break ;

...
}


10. Crop sprites
Game Maker manual:
First of all, look carefully at the sprites and backgrounds you use. Animated sprites take a lot of memory and drawing lots of sprites takes a lot of time. So make your sprites as small as possible. Remove any invisible area around it (the command crop in the sprite editor does that automatically). The same applies to background images.


11. Avoid memory leaks.
It's a pain the ass if someone notices a memory leak in your software/game.

In Game maker they often occur when you keep creating new variables or when you forget to free memory.

Don't forget these functions: file_find_close(),surface_free(id),sprite_delete(ind), font_delete(ind).

Example of "Not really good code"

fileID = file_text_open_read("data.txt") ;

while (!file_text_eof(fileID)) do
{
execute_string(file_text_read_string(fileID)) ;
file_text_readln(fileID) ; 
}

If you keep executing this code, in the end it will result in a memory leak.
You always have to close the file (free memory). So adding file_find_close() should fix this leak.



12. Avoid allocation of variables.

In GM there are 3 different types of declaring a variable:

Type 1:
globalvar variableA
You can use the variableA wherever you want in the game. This needs some memory.


Type 2:
variableA = 10  ; //(10 can be any number)
You can use variableA in any code inside the instance. So don't expect to find it when dealing with another object (or another instance of the same object).
This needs less memory then type1.

Type 3:
var variableA ;
You can only use variableA in the current piece of code/script. This declaration of a variable is needs even less memory then type 2.

So don't use a variable of Type 1 if you can also use it as type 3.


13. Use surfaces

Regarding functions like draw_circle, draw_rectangle and draw_line first draw the primitive to a surface, then draw the surface to the screen. It's much faster that way but it also needs more memory.
Note (ramses12): The primitives must only be drawn once, when the surface is created.


14. Sample down sound/music.

Sound can take up a lot of memory and space, especially wavs and mp3s, so sample them down if you can. Ask yourself if the higher bitrate or extra channel is worth the hit!


15. Use tiles instead of objects.

Tiles are much, much faster than objects, so you should use them in place of objects whenever you can. You can actually do a lot of things with tiles, like create and destroy them, set their depth, get their position, etc. They're not completely static.
Background details that you don't actually interact with are perfect tile material.

16. Use DLL's

GML is a interpreted language. And interpreted languages are most of the time slower than a compiled language.
So use DLL's for performance critical code. They can be a lot faster.


17. Use constants
They are faster than dynamic variables. Use them where possible!



18. Use Arrays

Memory which is allocated for an array is linear. That means it's faster to get data from an array then using X different variables.

But keep an array as small as possible, so that you don't waste memory.



19. Use grids

Theoretically they have the same performance as a 2d array. But the region functions (like ds_grid_set_region, ds_grid_add_region, …) are a lot faster. So use grids instead of arrays if you need things like regions.



20. Use lists.

Game Maker manual:
They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.



21. Game priority (Global game settings --> Other)

Game Maker Manual:
You can set the priority of the game process. This priority indicates how much processor time is allotted to the game. In normal mode the operating system tries to give processor time to each process that needs it in some reasonable way. The higher you put the priority the more time is allotted to the game, making it run more smoothly and faster. But other processes get less time (also Windows processes so even the mouse might not move anymore). Use this with care.

22. Use texture_set_priority(texid,prio)

Game Maker Manual:
When there is too little video memory some will be removed temporarily to make room for others that are needed. The ones with lowest priority are removed first. Default, all have priority 0 but you can change the priority here. (Use positive values!)



23. Use texture_set_interpolation(linear)

Game Maker Manual:
Indicates whether to use linear interpolation (true) or pick the nearest pixel (false). Linear interpolation gives smoother textures but can also be a bit blurry and sometimes costs extra time. This setting also influence the drawing of sprites and background. Default is false. (This can also be changed in the global game settings.)



24. Use display_set_colordepth(coldepth)

Coldepth can be 16 or 32 (16 bit or 32 bit). All modern GPU's support 32-bit. But changing it to 16-bit will gain extra performance. A disadvantage is that the colors are quite ugly. So it's only useful when you're creating a non-game application.


25. Use your brain

Edited by cabreak, 07 July 2011 - 07:08 PM.

  • 22
Visit my website: http://www.di-martino.net

#2 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 07 July 2011 - 11:13 AM

Nice collection you've got in there.

1. "Synchronization to avoid tearing" (Global Game Settings -> Resolution)
Set this off if you don't really need it. It heavenly affects the CPU.

Syncronization doesn't affect the CPU slowing it down that way. It rather does not allow the process to refresh itself at a rate that would be faster than the screen buffer. Otherwise, the drawing area would only partially be copied into the buffer, resulting in a part of the previous frame still visible on the screen.

2. Execute_string and draw_Getpixel.
Those are quite heavy functions for GM. That doesn't mean you can't use them at all. Use them wisely, for example in loading screens or at the end of a game.

And of course, here are included all the similar functions, like execute_file(), variable_local_set() and similar, or surface_getpixel().

7. With construction
Don't underestimate this construction. You can use "with" when you are changing different variables or executing different functions from the same object.

Example "unoptimized code" (From a debug screen in draw event)

draw_text(view_xview[0]+10,view_yview[0]+10,"Speed: "+ string(obj_Player.Speed)) ;
draw_text(view_xview[0]+10,view_yview[0]+27,"direction:"+ string(obj_Player.direction)) ;
draw_text(view_xview[0]+10,view_yview[0]+44,"angle:"+ string(obj_Player.angle)) ;

You can optimize it into this:
with (obj_Player)
{
draw_text(view_xview[0]+10,view_yview[0]+10,"Speed: "+ string(Speed)) ;
draw_text(view_xview[0]+10,view_yview[0]+27,"direction: "+ string(direction)) ;
draw_text(view_xview[0]+10,view_yview[0]+44,"angle: "+ string(angle)) ;
}

You should be aware that those two codes do something different. One draws the info just once, and the other repeats for every instance of obj_Player. Also, if there's no instance of objPlayer in the room, the first code would probably throw an error.

It's a pain in the ass if someone notices a memory leak in your software/game.

This sentence made me smile :)

12. Avoid allocation of variables.

In GM there are 3 different types of declaring a variable:

Type 1:

globalvar variableA
You can use the variableA wherever you want in the game. This needs some memory.


Type 2:
variableA = 10  ; //(10 can be any number)
You can use variableA in any code inside the instance. So don't expect to find it when dealing with another object (or another instance of the same object).
This needs less memory then type1.

Type 3:
var variableA ;
You can only use variableA in the current piece of code/script. This declaration of a variable is needs even less memory then type 2.

So don't use a variable of Type 1 if you can also use it as type 3.

Now this is something I hardly consider as a real fact. Where did you find that global variables need more memory than local ones?
Plus, variables don't slow the game down at all, it has nothing to do with CPU.

13. Use surfaces

Regarding functions like draw_circle, draw_rectangle and draw_line first draw the primitive to a surface, then draw the surface to the screen. It's much faster that way.

That's true, but you must mention that the primitives must only be drawn once, when the surface is created. Otherwise, if the program executes the drawing every step it would be far worse.


- Ramses
  • 3

#3 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 11:23 AM

1. Everything goes first to the CPU. And the CPU has to wait for the synchronization to end. So it actually really affect the CPU :).

2. Yes ofcourse, there are more expensive functions than these two. I will add those. Thank you.

7. Indeed, it's a small difference. But for this case it does the same and it's faster. It's just the concept (example) of using the with construction.

12. Well, using local variables are faster for the CPU, that's for sure. Globalvars are working slower than local. But about the memory, I was also doubting about that, but the Game Maker Manual has convinced me.

Sometimes you want variables only within the current piece of code or script. In this way you avoid wasting memory and you are sure there is no naming conflict. It is also faster than using global variables.


13.You're right about that! I will edit it soon.

Edited by cabreak, 07 July 2011 - 11:28 AM.

  • 0
Visit my website: http://www.di-martino.net

#4 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 11:29 AM

Nice collection you've got in there.


Thank you. There are a lot techniques written by myself.

Edited by cabreak, 07 July 2011 - 11:29 AM.

  • 0
Visit my website: http://www.di-martino.net

#5 ramses12

ramses12

    6

  • GMC Member
  • 5769 posts
  • Version:GM8.1

Posted 07 July 2011 - 11:54 AM

1. Everything goes first to the CPU. And the CPU has to wait for the synchronization to end. So it actually really affect the CPU public/style_emoticons/default/smile.gif.

Actually, this should be the the job of the graphics card.

But for this case it does the same and it's faster. It's just the concept (example) of using the with construction.

I'm curious about why would it be faster to call the statements in another instance. Posted Image I think that you mean that it is faster to with(obj)draw_something() than using draw_something() in the draw event of obj.

In this way you avoid wasting memory

That doesn't mean that code variables are smaller in size, but that they are freed after a short time. A local variable remains there as long as the instance whom it belongs to remains alive. But they are the same. It's only a matter of freeing it.
Anyway, as an integer variable uses only four bytes, it is less likely that anyone will ever consume with variables more space than say 2k :P
  • 0

#6 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 11:58 AM

1. Everything goes first to the CPU. And the CPU has to wait for the synchronization to end. So it actually really affect the CPU public/style_emoticons/default/smile.gif.

Actually, this should be the the job of the graphics card.

But for this case it does the same and it's faster. It's just the concept (example) of using the with construction.

I'm curious about why would it be faster to call the statements in another instance. Posted Image I think that you mean that it is faster to with(obj)draw_something() than using draw_something() in the draw event of obj.

In this way you avoid wasting memory

That doesn't mean that code variables are smaller in size, but that they are freed after a short time. A local variable remains there as long as the instance whom it belongs to remains alive. But they are the same. It's only a matter of freeing it.
Anyway, as an integer variable uses only four bytes, it is less likely that anyone will ever consume with variables more space than say 2k :P


1. That's true. But it also affects the CPU. http://en.wikipedia..../Screen_tearing

2. It's about the variables (obj_Player.angle) . I've benchmarked it, it's faster.

3. Well, I'm sure it's faster. But like I said, I doubt if it uses more memory.
  • 0
Visit my website: http://www.di-martino.net

#7 paul23

paul23

    GMC Member

  • Global Moderators
  • 4147 posts
  • Version:GM:Studio

Posted 07 July 2011 - 01:05 PM

Good list, though I question quite a few things you covered. (Not saying they're bad, but speedwise they seem to hardly give any advantage). First thing you should notice is that memory has little effect on the speed of a program. (Well reading & writing on the stack is much faster, but you can't control that with gamemaker). But generally memory consumption has no effect on the speed of a program.


7. With construction

Speed difference is mostly neglectable when using a with statement

9. Switch statement

Did you test this? In gamemaker I doubt there's any real gain (each case has to be evaluated anyways). (Though switch often makes more sense for readability).

18. Use Arrays

Memory which is allocated for an array is linear. That means it's faster to get data from an array then using X different variables.

But keep an array as small as possible, so that you don't waste memory.

Uhm what? Where does it say the memory is linear? And how does this make accessing them faster?



19. Use grids

Theoretically they have the same performance as a 2d array. But the region functions (like ds_grid_set_region, ds_grid_add_region, ) are a lot faster. So use grids instead of arrays if you need things like regions.

On the other hand getting/writing variables to a specific position is much more slowly than using arrays.



20. Use lists.

Game Maker manual:
They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

Well apart for algorithms this isn't true, like with grid accessing data inside the list is slow in GM.
  • 0

#8 Tepi

Tepi

    GMC Member

  • Global Moderators
  • 4248 posts
  • Version:GM:Studio

Posted 07 July 2011 - 01:11 PM

Yeah now you need to point out a source to #5 (and tell us why it applies to Game Maker). Preferably some kind of a benchmark program that would support your claims.

Most of the list seemed to be just made up so that the list would be longer. Some of those aren't even optimization techniques. Some are utterly insignificant, and your list is also missing some important techniques such as using repeat loops instead of others when it's possible.

Although obvious, one really important technique is mathematical simplification. However, many people can't seem to recognize how lengthdir_x(point_distance(x1,y1,x2,y2), point_direction(x1,y1,x2,y2)+90) simplifies.
  • 0

#9 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • GMC Elder
  • 9603 posts
  • Version:GM:Studio

Posted 07 July 2011 - 01:22 PM

For #13, you should mention that although this will save processing power, it uses up more memory (the surface requires memory), so it's a trade-off between processing speed and memory usage.

-IMP ;) :)
  • 0

:GM123: Are you an artist who likes creating original creature designs? Maybe you can help out with Elementa here! Give it a look; you might like the idea :)

:bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny:


#10 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 01:34 PM

Good list, though I question quite a few things you covered. (Not saying they're bad, but speedwise they seem to hardly give any advantage). First thing you should notice is that memory has little effect on the speed of a program. (Well reading & writing on the stack is much faster, but you can't control that with gamemaker). But generally memory consumption has no effect on the speed of a program.


7. With construction

Speed difference is mostly neglectable when using a with statement

9. Switch statement

Did you test this? In gamemaker I doubt there's any real gain (each case has to be evaluated anyways). (Though switch often makes more sense for readability).

18. Use Arrays

Memory which is allocated for an array is linear. That means it's faster to get data from an array then using X different variables.

But keep an array as small as possible, so that you don't waste memory.

Uhm what? Where does it say the memory is linear? And how does this make accessing them faster?



19. Use grids

Theoretically they have the same performance as a 2d array. But the region functions (like ds_grid_set_region, ds_grid_add_region, ) are a lot faster. So use grids instead of arrays if you need things like regions.

On the other hand getting/writing variables to a specific position is much more slowly than using arrays.



20. Use lists.

Game Maker manual:
They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

Well apart for algorithms this isn't true, like with grid accessing data inside the list is slow in GM.


7. Like I said, don't underestimate it. There is clearly a speed difference. Even if it's small.
9. To be honest, I didn't test this. But I think it really has a performance gain (In C# it has for example).
18. They are for example faster in using loops. That's basic knowledge of computer science. Also, a one dimensional array uses linear memory.
19. Don't know about that, but I wrote: "Use grids instead of arrays if you need things like regions"
20. That's nonsense.
  • 0
Visit my website: http://www.di-martino.net

#11 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 01:42 PM

Yeah now you need to point out a source to #5 (and tell us why it applies to Game Maker). Preferably some kind of a benchmark program that would support your claims.

Most of the list seemed to be just made up so that the list would be longer. Some of those aren't even optimization techniques. Some are utterly insignificant, and your list is also missing some important techniques such as using repeat loops instead of others when it's possible.

Although obvious, one really important technique is mathematical simplification. However, many people can't seem to recognize how lengthdir_x(point_distance(x1,y1,x2,y2), point_direction(x1,y1,x2,y2)+90) simplifies.


About the benchmark: I will.

And it's not about "so that the list would be longer.". Every small thing will help.
It's not only about optimization (title is kinda misleading), but also about gaining extra performance where needed.
Ofcourse, there are plenty of other optimizations.

The mathematical simplification is indeed a optimization. But like you said, many people can't simplify algorithms. It's all about algebra.

Edited by cabreak, 07 July 2011 - 01:42 PM.

  • 0
Visit my website: http://www.di-martino.net

#12 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 01:45 PM

For #13, you should mention that although this will save processing power, it uses up more memory (the surface requires memory), so it's a trade-off between processing speed and memory usage.

-IMP ;) :)


Hmm, that's indeed right. Thank you!
Let me fix this.
  • 0
Visit my website: http://www.di-martino.net

#13 Medusar

Medusar

    GMC Member

  • GMC Member
  • 1228 posts
  • Version:GM:Studio

Posted 07 July 2011 - 03:21 PM

For #16: yes, but not always... there is an overhead for calling DLL functions you know.

#25 is probably the most important one; why did you put it last on the list?
  • 0

Posted Image

Q: Why do programmers always get Christmas and Halloween mixed up?
A: Because DEC 25 = OCT 31

#14 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 03:44 PM

For #16: yes, but not always... there is an overhead for calling DLL functions you know.

#25 is probably the most important one; why did you put it last on the list?


Yeh, that's true. But it's not that much.

And about 25: Do you think anybody is interesting in that tip ? Don't take me wrong, but it's indeed the most important one. Happy that someone mentions it.
  • 0
Visit my website: http://www.di-martino.net

#15 PurpleFuzzy

PurpleFuzzy

    Punk Rock Princess

  • GMC Member
  • 1589 posts
  • Version:None

Posted 07 July 2011 - 05:00 PM

Number 25 is more important than any of the preceding 24.

8. Fewer collision checks
Objects that have collision events are much slower than objects that don't. So place those events in the objects which will have the fewest instances. A good example is the player versus the 100 bullets. You obviously have to do a collision check between the two objects. Make sure that event goes in the player object instead of the 100 bullets.


Or better yet, use a parent object for all the bullets, and define the damage in the collision with the player object. 101 bullet objects, only a single collision event.

Nice list.

-PF
  • 0

#16 Medusar

Medusar

    GMC Member

  • GMC Member
  • 1228 posts
  • Version:GM:Studio

Posted 07 July 2011 - 06:16 PM

Oh I forgot about this one for #8: if collision checks are necessary, don't use precise collisions.
  • 0

Posted Image

Q: Why do programmers always get Christmas and Halloween mixed up?
A: Because DEC 25 = OCT 31

#17 Erik Leppen

Erik Leppen

    GMC Member

  • GMC Member
  • 2751 posts
  • Version:GM:Studio

Posted 07 July 2011 - 06:31 PM

8. Fewer collision checks
Objects that have collision events are much slower than objects that don't. So place those events in the objects which will have the fewest instances. A good example is the player versus the 100 bullets. You obviously have to do a collision check between the two objects. Make sure that event goes in the player object instead of the 100 bullets.

Nonsense.

I read this every now and then, although much more often in the GM6 era than nowadays, but I tested it back then and it didn't hold. I tested it now again, and it doesn't hold. At least, not on my computer. Have you actually tested this?

I did the following test: I created two objects having the same sprite, and then did this from a third object:
repeat 5000 {
  instance_create(random(room_width), random(room_height), objectA)
}
repeat 50 {
  instance_create(random(room_width), random(room_height), objectB)
}

I put a Collision event in A doing something simple. Then I ran the game and wrote down the FPS. Then, I switched the 50 and 5000 in the code above so there were 5000 B and 50 A. I re-ran the game and wrote down the FPS.

Here are the results.
5000x A and 50x B, precise checking ON (which means 5000 instances having a collision event): 20 fps.
50x A and 5000x B, precise checking ON (which means 50 instance having a collision event): 18 fps.
5000x A and 50x B, precise checking OFF (which means 5000 instances having a collision event): 22 fps.
50x A and 5000x B, precise checking OFF (which means 50 instance having a collision event): 20 fps.
For the fun of it, I removed the collision event out of A: 85 fps.

As you can see, there's no real difference, and if you do count the 2 fps difference, then it's the other way around! Also as you can see the precise checking option doesn't really matter that much either.

And if you think about it, (using tip 25) it's actually pretty logical. Having 50 instance check for collisions against 5000 others, would cost about the same amount of time as having 5000 instances check for collision against 50 others. Namely, 50 x 5000 times the time it costs for checking for one collision between two instances. By the way, given that that are 250000 pairs that need to be checked, this is actually pretty fast.


Game Maker manual:
[Lists] are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

This is only true if you're actually using the list functions. If all you're doing is just moving around data, then you're better off using arrays. However ds_list_shuffle is a lot faster than if you were to write your own array shuffle function, because ds_list_shuffle is compiled. That's the difference. But if you're not using that difference, than it doesn't matter. Of course, lists have other advantages, but I assume this topic is about execution speed.
  • 0

promo_briquidmini_500x150.png


#18 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 06:47 PM

8. Fewer collision checks
Objects that have collision events are much slower than objects that don't. So place those events in the objects which will have the fewest instances. A good example is the player versus the 100 bullets. You obviously have to do a collision check between the two objects. Make sure that event goes in the player object instead of the 100 bullets.

Nonsense.

I read this every now and then, although much more often in the GM6 era than nowadays, but I tested it back then and it didn't hold. I tested it now again, and it doesn't hold. At least, not on my computer. Have you actually tested this?

I did the following test: I created two objects having the same sprite, and then did this from a third object:
repeat 5000 {
  instance_create(random(room_width), random(room_height), objectA)
}
repeat 50 {
  instance_create(random(room_width), random(room_height), objectB)
}

I put a Collision event in A doing something simple. Then I ran the game and wrote down the FPS. Then, I switched the 50 and 5000 in the code above so there were 5000 B and 50 A. I re-ran the game and wrote down the FPS.

Here are the results.
5000x A and 50x B, precise checking ON (which means 5000 instances having a collision event): 20 fps.
50x A and 5000x B, precise checking ON (which means 50 instance having a collision event): 18 fps.
5000x A and 50x B, precise checking OFF (which means 5000 instances having a collision event): 22 fps.
50x A and 5000x B, precise checking OFF (which means 50 instance having a collision event): 20 fps.
For the fun of it, I removed the collision event out of A: 85 fps.

As you can see, there's no real difference, and if you do count the 2 fps difference, then it's the other way around! Also as you can see the precise checking option doesn't really matter that much either.

And if you think about it, (using tip 25) it's actually pretty logical. Having 50 instance check for collisions against 5000 others, would cost about the same amount of time as having 5000 instances check for collision against 50 others. Namely, 50 x 5000 times the time it costs for checking for one collision between two instances. By the way, given that that are 250000 pairs that need to be checked, this is actually pretty fast.


Game Maker manual:
[Lists] are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

This is only true if you're actually using the list functions. If all you're doing is just moving around data, then you're better off using arrays. However ds_list_shuffle is a lot faster than if you were to write your own array shuffle function, because ds_list_shuffle is compiled. That's the difference. But if you're not using that difference, than it doesn't matter. Of course, lists have other advantages, but I assume this topic is about execution speed.


About the array: Yeh, I should have mention that. It's a little unclear indeed.

But I'm actually stunned about the "Fewer Collision checks". This is very interesting.
I'm going to set up a benchmark by myself. I didn't wrote this one anyway.
  • 0
Visit my website: http://www.di-martino.net

#19 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 25708 posts
  • Version:GM:Studio

Posted 07 July 2011 - 07:02 PM

Out of curiosity I just did a quick test using the exact system that erik used and got a steady 35 fps no matter what. So (and common sense agrees) it matters not where the collision event goes.

(PS: cabreak, don't double post! Use the >edit< button... Posted Image)
  • 0

U1FVsm3.png

40799.png


#20 cabreak

cabreak

    GMC Member

  • New Member
  • 93 posts

Posted 07 July 2011 - 07:07 PM

Out of curiosity I just did a quick test using the exact system that erik used and got a steady 35 fps no matter what. So (and common sense agrees) it matters not where the collision event goes.

(PS: cabreak, don't double post! Use the >edit< button... Posted Image)


I did another benchmark and yeh I got the same result. Didn't knew it at all!

Sorry about double posting. It's because I'm in an hurry.
  • 0
Visit my website: http://www.di-martino.net

#21 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 4301 posts
  • Version:GM:Studio

Posted 07 July 2011 - 10:06 PM

"Use Your Brain" that solves all the performance problems, lols
  • -1

5y5rs3d.pngfg0UQNL.png


#22 Gamer3D

Gamer3D

    Human* me = this;

  • GMC Member
  • 1819 posts
  • Version:GM:Studio

Posted 08 July 2011 - 01:48 AM

1. "Synchronization to avoid tearing" (Global Game Settings -> Resolution)
Set this off if you don't really need it. It heavenly affects the CPU.

He's actually right about this (or was right back during GM7 at least). Judging by CPU use, GM waits for frames using a loop, which occupies 100% of the available CPU cycles during that time.


5.Divisions and trig calculations.
Divisions need a lot more CPY cycles then multiplications or subtractions.
And trig calculations need even more CPU cyles. So avoid using them where possible.
You can try to find faster or other algorithms.

Even in compiled code, division takes about the same amount of time as multiplication. Trig functions are also quite fast.

In GM, calling a script, function, or operation is so much slower than the compiled code referenced that any differences are negligible.


9. Switch statement

Compiled languages accept only integers as switch statement inputs, and use a table to optimize this. GM performs the same comparisons whether you use switch or if statements.

12. Avoid allocation of variables.

In GM there are 3 different types of declaring a variable:

Type 1:

globalvar variableA
You can use the variableA wherever you want in the game. This needs some memory.


Type 2:
variableA = 10  ; //(10 can be any number)
You can use variableA in any code inside the instance. So don't expect to find it when dealing with another object (or another instance of the same object).
This needs less memory then type1.

Type 3:
var variableA ;
You can only use variableA in the current piece of code/script. This declaration of a variable is needs even less memory then type 2.

So don't use a variable of Type 1 if you can also use it as type 3.

I call shenanigans. The three scopes of variables that you have written all use the same amount of memory and are, if GM is done right, equally fast.


17. Use constants
They are faster than dynamic variables. Use them where possible!

In GM? Probably not.


18. Use Arrays

Memory which is allocated for an array is linear. That means it's faster to get data from an array then using X different variables.

But keep an array as small as possible, so that you don't waste memory.

You have no idea what an array is, do you?

BTW, it'll be minutely slower to look up N entries in a GM array than to look up the same with N variables.


19. Use grids

Theoretically they have the same performance as a 2d array. But the region functions (like ds_grid_set_region, ds_grid_add_region, ) are a lot faster. So use grids instead of arrays if you need things like regions.

20. Use lists.

Game Maker manual:
They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

Last I checked, grids and lists were noticeably slower than arrays,
and I know for sure that GM's priority queues are awful.

This is because calling a function in GM is a lot slower than most operations, so the speed gains you might get will be removed completely, often resulting in a slower program.

As a rule of thumb, use grids/lists if you want to give/get an array to/from a function or otherwise need a handle for an array. Use built-in arrays otherwise.

23. Use texture_set_interpolation(linear)

Game Maker Manual:
Indicates whether to use linear interpolation (true) or pick the nearest pixel (false). Linear interpolation gives smoother textures but can also be a bit blurry and sometimes costs extra time. This setting also influence the drawing of sprites and background. Default is false. (This can also be changed in the global game settings.)

It's done in the graphics card. If you have trouble that this helps with, then you're using too high of a resolution or are drawing over the same pixels many times (which is going to cause trouble anyway).
  • 2
Fast Priority Queues - Game Maker's priority queues are O(n). Mine do everything that Game Maker's do, but in O(log n) time.
Dual-Quaternion Skinning - Modifying vertexes in GM is slow. This simple vertex shader does the job both quickly and well.

#23 MasterOfKings

MasterOfKings

    The True Master

  • GMC Member
  • 4888 posts
  • Version:GM8

Posted 08 July 2011 - 02:11 AM

12. Avoid allocation of variables.

I doubt a globalvar uses more memory, because it's the same data type, so the same amount of memory is given to it. The difference is in scope.
Such...
int var;
int func() {
    int var2;
}
int func2() {
    int var3;
}
In something like C++, 'var' can be used in either func or func2, but func2 cannot use var2, just as func cannot use var3. However, the variables all use the same amount of memory.

GM uses scope differently (or, less obviously).

16. Use DLL's

GML is a interpreted language. And interpreted languages are most of the time slower than a compiled language.
So use DLL's for performance critical code. They can be a lot faster.

Although, take note of the overhead of calling the dll function. Some things executed in a dll could end up being slower than being executed with pure GML.

18. Use Arrays

Memory which is allocated for an array is linear. That means it's faster to get data from an array then using X different variables.

But keep an array as small as possible, so that you don't waste memory.



19. Use grids

Theoretically they have the same performance as a 2d array. But the region functions (like ds_grid_set_region, ds_grid_add_region, …) are a lot faster. So use grids instead of arrays if you need things like regions.



20. Use lists.

Game Maker manual:
They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

Just because the allocation is in a straight line, doesn't mean it's faster. An array is simply a chunk of memory with various slots. All that means is the memory addresses with be one after another; but it has to work from the beginning of the array, then determine the slot address.

In relations to lists and whatnot, they are generally faster when you don't access them very often. However, if you grab something from them every step or two, you'll find an array will work faster (I've tried and proven this).

25. Use your brain

Brain? What's a brain? :P

-MoK

Edited by MasterOfKings, 08 July 2011 - 02:23 AM.

  • 0

Did I help you? If so, help me by pressing the + button above here.


bannersyd.png

banner22z.png


#24 PurpleFuzzy

PurpleFuzzy

    Punk Rock Princess

  • GMC Member
  • 1589 posts
  • Version:None

Posted 08 July 2011 - 06:31 AM

Regarding fewer collisions, wouldn't it be wise to parent objects when possible just to make your code easier to navigate? Isn't that in a sense "optimizing" things?

-PF
  • 0

#25 Medusar

Medusar

    GMC Member

  • GMC Member
  • 1228 posts
  • Version:GM:Studio

Posted 08 July 2011 - 11:10 AM

Even in compiled code, division takes about the same amount of time as multiplication. Trig functions are also quite fast.

Intel have some documentation about the number of clock cycles certain instructions take. I'm sure AMD and other manufacturers do, too. I'm pretty sure that division uses more clock cycles than multiplication.

Regarding fewer collisions, wouldn't it be wise to parent objects when possible just to make your code easier to navigate? Isn't that in a sense "optimizing" things?

Easier to read is not always faster. For code readability, yes, parents are great and I use them all the time. But think of it this way: whenever you use parenting, the system has to look up the inheritance tree to determine whether a certain object is an ancestor of another. Does that sound like more work to you? I don't know how this affects performance, but I can imagine that parenting is a little slower.
  • 0

Posted Image

Q: Why do programmers always get Christmas and Halloween mixed up?
A: Because DEC 25 = OCT 31

#26 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 08 July 2011 - 11:37 AM

Why is everybody bit twiddling?

Also - GM has constant collapsing (though I don't think it collapses actual constants - only when you enter the number in the code - I think mike posted this on the constant collapsing topic)

Therefore:

1 / 4

is the same as

0.25

is the same as

MY_CONSTANT_THAT_HOLDS_THE_NUMBER_ZERO_POINT_TWO_FIVE

but they are all faster than

1 / MY_CONSTANT_THAT_HOLDS_THE_NUMBER_FOUR

...

but still ... you guys are bit twiddling.
  • 0

The first thing I would do with infinite power would be to make myself a cave where I could look at my shadow forever.

 

The destination is much harder to reach when you don't want to walk towards it.


#27 Medusar

Medusar

    GMC Member

  • GMC Member
  • 1228 posts
  • Version:GM:Studio

Posted 08 July 2011 - 02:53 PM

The point is: does GM treat constants like variables that simply generate an error when you try to change them, or does it use "proper" constants? I'm afraid it's the former.
  • 0

Posted Image

Q: Why do programmers always get Christmas and Halloween mixed up?
A: Because DEC 25 = OCT 31

#28 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 08 July 2011 - 03:07 PM

no, I think they are proper constants.

Citation

Edited by Docopoper, 08 July 2011 - 03:13 PM.

  • 0

The first thing I would do with infinite power would be to make myself a cave where I could look at my shadow forever.

 

The destination is much harder to reach when you don't want to walk towards it.


#29 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 08 July 2011 - 07:27 PM

I'm not sure about the access speed of a variable/array.... Some statements would be true in a compiled language. But this all depends on the way the interpreter is designed; ei, internally, globals, locals, arrays, var declared variables may be all in the global heap for all we know.

item 20 is just wrong. no data structure is faster than arrays unless you intend to use the array for anything other than storing,holding,fetching data to/from a list (like sorting/removing items);
v = arr[i] is faster than v = ds_list_find_value(l,i)


I have GMBenchmark Everything in my tools page which you can test your assumptions
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#30 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • GMC Elder
  • 9603 posts
  • Version:GM:Studio

Posted 08 July 2011 - 08:44 PM

item 20 is just wrong. no data structure is faster than arrays unless you intend to use the array for anything other than storing,holding,fetching data to/from a list (like sorting/removing items);
v = arr[i] is faster than v = ds_list_find_value(l,i)

Ah, yes, but I'd assume ds_list_find_index(...) would be quicker than a manual array implementation, right? Because the required slow linear search code would be compiled in the runner here?

-IMP ;) :)
  • 0

:GM123: Are you an artist who likes creating original creature designs? Maybe you can help out with Elementa here! Give it a look; you might like the idea :)

:bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny:


#31 YellowAfterlife

YellowAfterlife

    GMC Member

  • Global Moderators
  • 4157 posts
  • Version:GM:Studio

Posted 08 July 2011 - 09:32 PM

Ah, yes, but I'd assume ds_list_find_index(...) would be quicker than a manual array implementation, right? Because the required slow linear search code would be compiled in the runner here?

-IMP ;) :)

Indeed, the few cases when developer should use a ds_list instead of array[] are the value look-up and sorting.

For example...
It is possible to store strings in ds_list's. However noone seems to use this feature.
As well it is possible to create one-line string index look-up using that.
If I would care a little bit less about Lite edition users, I would probably plug data-structures into 1/3 of my examples, just for perfomance.

In all other cases... since you can't read a section of data-structure into variable(s) or commands, using arrays is better, because plain array access speed is faster.
  • 0
If my posts contain broken links, try looking around my website. I gradually make blog posts for any examples I make.
_.png_.gif

#32 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 18181 posts
  • Version:GM:Studio

Posted 08 July 2011 - 09:41 PM

Ah, yes, but I'd assume ds_list_find_index(...) would be quicker than a manual array implementation, right? Because the required slow linear search code would be compiled in the runner here?

-IMP ;) :)


that would fall in the unless part of the factors. Pretty sure ds_ implementation of find_index is also linear... Yep... a sorted array and log2 search would possibly be faster
  • 0

gmcbanner.pnggmcbanner_tools.png

ICU Live Tutoring Through Slack or Skype | My Tools Page follow.png

I FRANTICALLY MADE MY 18000 POST TOPIC BEFORE MIKE ANNOUNCED A DELAY...
Now I'm squirming not to hit that reply button


#33 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • GMC Elder
  • 9603 posts
  • Version:GM:Studio

Posted 09 July 2011 - 02:31 AM


Ah, yes, but I'd assume ds_list_find_index(...) would be quicker than a manual array implementation, right? Because the required slow linear search code would be compiled in the runner here?

-IMP ;) :)


that would fall in the unless part of the factors. Pretty sure ds_ implementation of find_index is also linear... Yep... a sorted array and log2 search would possibly be faster

OK :) . And I figured it would be linear, which is why I said "required". It'd still be faster going through a long list for this than running an interpreted loop to do the same. Though with reasonably-sized lists traversed only occasionally, I'd say the benefits would be negligible. Still, if it's faster and easier to use, you might as well.

And of course a binary search would be faster, but to do that you have to first sort the list, which sacrifices the very value-index associations you're trying to find.

-IMP ;) :)
  • 0

:GM123: Are you an artist who likes creating original creature designs? Maybe you can help out with Elementa here! Give it a look; you might like the idea :)

:bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny:


#34 paul23

paul23

    GMC Member

  • Global Moderators
  • 4147 posts
  • Version:GM:Studio

Posted 09 July 2011 - 03:37 AM


Ah, yes, but I'd assume ds_list_find_index(...) would be quicker than a manual array implementation, right? Because the required slow linear search code would be compiled in the runner here?

-IMP ;) :)


that would fall in the unless part of the factors. Pretty sure ds_ implementation of find_index is also linear... Yep... a sorted array and log2 search would possibly be faster

They are obviously linear (lists don't have to be ordered). Though I doubt for realistic measures a log2 search (through GML) would be faster.. Might be only with 1025+ items.

Though what was worse was the naive implementation of priority queues, many operations were linear instead of log(O) in speed.


9. To be honest, I didn't test this. But I think it really has a performance gain (In C# it has for example).

Test it I'd say: those languages have a limitation on with statements: the cases have to be constants. The program can take advantage of this knowlenge to speed up execution. In GM this isn't really possible.

18. They are for example faster in using loops. That's basic knowledge of computer science. Also, a one dimensional array uses linear memory.

Since when? This entirelly depends on the compiler/interpreter.
On top of that, what does it matter where the memory is located? You're talking about Random Access Memory here. It's not a tape where reading values next to each other is faster.

20. That's nonsense.

"ok".... Well like icuurd12b46 already explained arrays are faster for data acces.
  • 0

#35 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • GMC Elder
  • 9603 posts
  • Version:GM:Studio

Posted 09 July 2011 - 04:17 AM

...many operations were linear instead of log(O) in speed.

I'm not too familiar with big-O notation. Is log(O) the same as O(log n)?

-IMP ;) :)
  • 0

:GM123: Are you an artist who likes creating original creature designs? Maybe you can help out with Elementa here! Give it a look; you might like the idea :)

:bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny:


#36 paul23

paul23

    GMC Member

  • Global Moderators
  • 4147 posts
  • Version:GM:Studio

Posted 09 July 2011 - 04:24 AM

...many operations were linear instead of log(O) in speed.

I'm not too familiar with big-O notation. Is log(O) the same as O(log n)?

-IMP ;) :)

typo on my hand there, meant O(log) / O(log n) - a logarithmic growth with the size.
  • 0

#37 Erik Leppen

Erik Leppen

    GMC Member

  • GMC Member
  • 2751 posts
  • Version:GM:Studio

Posted 09 July 2011 - 12:57 PM

"Use Your Brain" that solves all the performance problems, lols

True. As there's quite a lot of discussion, the only sensible thing to do is testing it. Shouting "X is faster than Y" is of no value at all if there's no example showing that it is true (and if so, showing the actual speed difference).

Shall we agree from now on that whoever says that something is faster, can post an example that we can all test? Then we can get the facts down. :)
  • 2

promo_briquidmini_500x150.png


#38 gmx0

gmx0

    The Messenger

  • GMC Member
  • 1220 posts
  • Version:GM:Studio

Posted 19 July 2011 - 09:01 PM

Global variables almost essentially object variables. They are the same as creating a "obj_global" object and setting a variable for it and then calling "obj_global.variable=x". In fact, self(id:-1), other(id:-2), global(id:-3), and noone(id:-4) ARE special objects. Memory is the same.

And the "switch" statement is definitely faster than "if" if(no pun intended) "switch" uses the "break" statement.

Edited by gmx0, 19 July 2011 - 09:04 PM.

  • 0

#39 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • GMC Elder
  • 9603 posts
  • Version:GM:Studio

Posted 19 July 2011 - 09:23 PM

And the "switch" statement is definitely faster than "if" if(no pun intended) "switch" uses the "break" statement.

And how does that make it faster?

if (vari==1) { something(); }
else if (vari==2) { somethingElse(); }
else if (vari==3) { whatnot(); }
else { defaulted(); }
switch (vari) {
  case 1: something(); break;
  case 2: somethingElse(); break;
  case 3: whatnot(); break;
  default: defaulted();
}

The same comparisons are executed and ignored in both, so why would break make the switch statement any faster?

-IMP ;) :)
  • 0

:GM123: Are you an artist who likes creating original creature designs? Maybe you can help out with Elementa here! Give it a look; you might like the idea :)

:bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny: :excl: :bunny:


#40 YellowAfterlife

YellowAfterlife

    GMC Member

  • Global Moderators
  • 4157 posts
  • Version:GM:Studio

Posted 19 July 2011 - 09:32 PM

And the "switch" statement is definitely faster than "if" if(no pun intended) "switch" uses the "break" statement.

And how does that make it faster?

if (vari==1) { something(); }
else if (vari==2) { somethingElse(); }
else if (vari==3) { whatnot(); }
else { defaulted(); }
switch (vari) {
  case 1: something(); break;
  case 2: somethingElse(); break;
  case 3: whatnot(); break;
  default: defaulted();
}

The same comparisons are executed and ignored in both, so why would break make the switch statement any faster?

-IMP ;) :)

"Inside", switch statement would perform only a single value retrieval, with subsequent comparisons to other values (in case of good programming, while keeping it in stack\register). So maybe it'd be a bit faster.
  • 0
If my posts contain broken links, try looking around my website. I gradually make blog posts for any examples I make.
_.png_.gif

#41 redspark

redspark

    GMC Member

  • GMC Member
  • 156 posts
  • Version:GM:Studio

Posted 31 July 2011 - 04:07 AM

18. They are for example faster in using loops. That's basic knowledge of computer science. Also, a one dimensional array uses linear memory.



Since when? This entirelly depends on the compiler/interpreter.
On top of that, what does it matter where the memory is located? You're talking about Random Access Memory here. It's not a tape where reading values next to each other is faster.


I'm not sure how it works in GM, but I was under the impression that calculating the position of an array element is more intensive than accessing a single variable address. The variable is the pointer to the value within memory while an array element within linear memory must be calculated from the index value (ArrayPointer + Index * Sizeof(element)). An array that is not allocated linearly, would have poor performance compared to a linear array. Non-linear arrays would require your to sequentially loop all prior elements to find the memory address of the index that you are looking for. A linear array just uses math to jump directly to the address.
  • 0

#42 LSnK

LSnK

    NaN

  • GMC Member
  • 1188 posts

Posted 31 July 2011 - 09:47 PM

Some of the stuff on this list is counter-productive or plain wrong. Optimisation isn't something you get right by guessing or applying generalities to. You have to test everything. Intuition won't help you and what matters in other languages might not matter in GML. It has some weird characteristics.

5.Divisions and trig calculations.
Divisions need a lot more CPY cycles then multiplications or subtractions.

Wrong. In GML all fundamental operations are effectively equal in performance. Addition, division, modulo, bit-shifts; all alike. How is that possible, you ask? Because GML is incredibly slow, the actual calculation takes up about 1/400th of the time taken to execute an operation. The vast majority is interpreter overhead. A benchmark:

Expression     Time     Cycles
x = y * 0.5    0.279us  836
x = y / 2      0.278us  833
x = y << 1     0.292us  887
Yes, ~830 cycles for one multiply. It takes the CPU between 1 and 3 cycles to do the actual multiplication, the rest is the interpreter scratching its butt.


And trig calculations need even more CPU cyles. So avoid using them where possible.
You can try to find faster or other algorithms.

Doesn't matter at all in GML. Trig functions are almost as fast as the fundamental operations and are among the fastest of all functions in the runner. Again, the computation time is greatly outweighed by interpreter overhead:

Expression     Time     Cycles
x = sqr(y)     0.461us  1382
x = sin(y)     0.501us  1502


12. Avoid allocation of variables.

This section is silly. You keep talking about memory usage, but that has zero impact on performance unless you run out. If memory is actually a problem then sparing a few bytes isn't going to help. We're talking about videogames here; applications which spend millions of times more memory on resources than on variables, primarily on a platform with gigabytes of memory available! Optimising stuff like this is a waste of time.

Some performance trivia: Script-local variables can be accessed slightly faster than object-local ones:
Expression     Time     Cycles
x = [var]      0.198us  595
x = [local]    0.206us  618
But it's not worth talking about. The difference is miniscule.


13. Use surfaces
Regarding functions like draw_circle, draw_rectangle and draw_line first draw the primitive to a surface, then draw the surface to the screen. It's much faster that way but it also needs more memory.

This is good advice sometimes (assuming you mean many shapes, not one) but it doesn't always apply. On a netbook with a crappy GMA 950 GPU it would flush performance down the toilet.


17. Use constants
They are faster than dynamic variables. Use them where possible!

Someone cast doubt on this claim earlier. Actually it's true, constants / numeric literals are accessed ~30% faster than object-local variables. That said, the difference is tiny in absolute terms.

Expression       Time     Cycles
[var] = [const]  0.156us  469
[var] = [local]  0.199us  599


18. Use Arrays
Memory which is allocated for an array is linear. That means it's faster to get data from an array then using X different variables.

Wrong. Accessing arrays in GML is considerably slower than accessing variables. Things like cache locality and prefetching don't matter in GML because the interpreter is so slow its overhead dominates everything.

Expression             Time     Cycles
[var] = [local array]  0.320us  961
[var] = [local]        0.199us  600
Again, in absolute terms the difference is hardly worth mentioning. But it sure ain't faster.

Amusing trivia: Look at the sin(x) execution time from before. That's right. In GML computing the sine is only slightly slower than simply accessing an array element. Haha.


20. Use lists.
Game Maker manual:
They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself.

They're much faster for sorting/searching/shuffling etc, but bear in mind that they're slower for plain access and assignment because of function call overhead. Like grids, whether you can leverage them for better performance is dependent on how they're used.


23. Use texture_set_interpolation(linear)

The manual is wrong, it doesn't really matter at all. Linear interpolated texel fetches are as inexpensive as nearest-neighour ones. Maybe it mattered 15 years ago, but not now.



You also missed some important factors in GML's performance. For example, calling a script costs a non-negligable amount of time, so it's often worthwhile to manually perform inline function expansion for scripts in loops. Here's an example:

<script>, a piece of code with a script call in its loop:
var i,a,ra,rb;
ra = random(1);
rb = random(1);

for (i=0; i<64; i+=1)
{
   a[i] = lerp( ra, rb, i/64 );
}

<Inline>, where I inlined it:
var i,a,ra,rb;
ra = random(1);
rb = random(1);

for (i=0; i<64; i+=1)
{
   a[i] = ra + ((rb-ra) * (i/64));
}

Results:
Expression  Time      Cycles
<script>    190.75us  572238
<Inline>    77.41us   232233
A substantial difference. This is the kind of thing you should worry about, not minutia that can barely be detected. It would be even worse in GM 7 or older, where calling a script was about three times more expensive.



For the record, the benchmarks above were done by repeating each expression 10 million times and taking the average. I used the HPET for timing. I subtracted the benchmark's loop overhead to make the results directly comparable.

Edited by LSnK, 31 July 2011 - 09:53 PM.

  • 11

#43 redspark

redspark

    GMC Member

  • GMC Member
  • 156 posts
  • Version:GM:Studio

Posted 01 August 2011 - 12:11 PM

You also missed some important factors in GML's performance. For example, calling a script costs a non-negligable amount of time, so it's often worthwhile to manually perform inline function expansion for scripts in loops. Here's an example:
<script>, a piece of code with a script call in its loop:

var i,a,ra,rb;
ra = random(1);
rb = random(1);

for (i=0; i<64; i+=1)
{
   a[i] = lerp( ra, rb, i/64 );
}

<Inline>, where I inlined it:
var i,a,ra,rb;
ra = random(1);
rb = random(1);

for (i=0; i<64; i+=1)
{
   a[i] = ra + ((rb-ra) * (i/64));
}

Results:
Expression  Time      Cycles
<script>    190.75us  572238
<Inline>    77.41us   232233
A substantial difference. This is the kind of thing you should worry about, not minutia that can barely be detected. It would be even worse in GM 7 or older, where calling a script was about three times more expensive.

For the record, the benchmarks above were done by repeating each expression 10 million times and taking the average. I used the HPET for timing. I subtracted the benchmark's loop overhead to make the results directly comparable.



These are interesting benchmarks. Thank you.

In your final benchmark for calling scripts, if we discount nested script calls and scripts within loops -- we're just talking about a simple game loop, would the 10,000,000 iterations equate to a savings of 120μs per script called in the main game loop over 46 (10,000,000/60/60/60) hours worth of play time for a game that is running at 60 fps? If that is true, how many script calls would we have to make before the overhead actually impacts performance?
  • 0

#44 LSnK

LSnK

    NaN

  • GMC Member
  • 1188 posts

Posted 01 August 2011 - 07:20 PM

In your final benchmark for calling scripts, if we discount nested script calls and scripts within loops -- we're just talking about a simple game loop, would the 10,000,000 iterations equate to a savings of 120μs per script called in the main game loop over 46 (10,000,000/60/60/60) hours worth of play time for a game that is running at 60 fps? If that is true, how many script calls would we have to make before the overhead actually impacts performance?

Could you restate the question? I'm not quite sure what you mean.

I'll try to answer anyway... The benchmark took about 45 minutes to run of which almost 19 minutes was script overhead. But that was calling a script in a loop. The difference is much less pronounced when only calling it once, and isn't such a big deal. You have to consider what parts of your game are worth optimising - I singled out looped scripts because it's a relatively large, easily solved waste of CPU time.

Whether you'll see slowdown because of this in practise depends on too many factors to give a straight answer. It's safe to say that if you call a lot of scripts every step it will have a significant impact. It's pretty easy to reach 1000 or more calls, which would consume nearly 2ms of the 16ms available per step in a 60hz game, just on overhead. (On my pretty-fast computer. On a netbook or other device with a slow CPU, it would be drastically more severe).

Well, enough speculation. Here are some numbers: the time taken to execute an empty script for each GM version. This represents the minimum possible overhead of calling a script.
Expression       Time     Cycles
empty() (gm70)   3.852us  11555
empty() (gm80)   1.423us  4270   (version used in tests)
empty() (gm81)   1.898us  5694
It's typically a little worse in practise because assigning values to the arguments takes extra time. Accounting for that, the result correlates closely with the difference in the inline-vs-script comparison above.


As an aside, I should mention that it's often worthwhile to suck up the performance penalty and leave the script calls purely to keep your code readable. Unmaintainable code sucks, and you can always inline it later.
  • 2

#45 redspark

redspark

    GMC Member

  • GMC Member
  • 156 posts
  • Version:GM:Studio

Posted 02 August 2011 - 12:33 AM

That answers my question. Thank you.

EDIT: I wonder what GM4Mac is like. I work mostly in OSX. I wonder if it is better or worse than GM7.

Edited by redspark, 02 August 2011 - 12:49 AM.

  • 0

#46 jhanley

jhanley

    GMC Member

  • GMC Member
  • 85 posts
  • Version:GM:Studio

Posted 04 January 2013 - 05:46 AM

This thread is somewhat dated, but still very useful and timely.

I wasn't experiencing any performance problems or slow downs in my TDS, but I still implemented several of the suggestions here for the sake of efficiency and best practice. Most notably "Precise collision checking"; I disabled it for all of my sprites as it wasn't needed. I believe this setting is only intended for pixel perfect collisions. I also disabled the background color as my background image occupies the whole screen. Finally, I wasn't using surface_free() after drawing my surface.

As for disabling "Synchronization to avoid tearing". Tearing might not be noticeable when playing in a window, but it's extremely distracting in full screen so if you're game isn't overtaxing the CPU you should definitely enable it.
  • 0
Be sure to check out my first game: Battle for Plangoria

#47 dannyjenn

dannyjenn

    GMC Member

  • GMC Member
  • 2736 posts
  • Version:Mac

Posted 04 January 2013 - 01:51 PM

To revisit the switch vs. if, I have tested it before and switch is a lot faster (for what I was doing anyway). I tested it in GM7 so I don't know if it has changed at all in Studio with the compiler and all that, but if anyone wants to see my code then I could post it. It has 256 cases so perhaps it's only noticably faster when you have a lot.


Also, I've got some more optimization techniques (again, not sure if these all apply to Studio) if anyone's interested:
- for memory optimization, make all resources external and load them in-game / delete them from memory as needed
- in-line code is always faster than scripts, so if you only have the code in a few places then copying and pasting it would be more optimal (although in most cases it's not noticable, so it's probably not worth the cost of decreased readability / editablility)
- going along with that, iterative functions are always faster than recursive functions, so if writing it iteratively is practical then don't do it recursively.
- loops:
if you are only looping for a set number of iterations (as in, not looping until a condition becomes true) then repeat loops are fastest. Also, if the loop will always loop for the same number of iterations, it's faster to actually copy and paste the code several times rather than put it into a loop at all. Of course, this also destroys readability / editability, so this should only be done as a last resort (and even then, it's usually not that much fatser)
- operations:
the bitwise operators are typically (slightly) faster than using the mathematical operators to do the same thing (e.g. (when working with integers) A<<1 is slightly faster than A*=2, A&1==0 is slightly faster than (A mod 2)==0, also e.g. $FF|$FF00 is slightly faster than $FF+$FF00). You can use this to your advantage at times.
- for memory optimization, at the cost of speed, you can store several small numbers in a single real and use the bitwise shift / bitwise and to extract them. For example, if A was always an integer between 0 and 255, and B was always between 0 and 65535, you can store A inside of B by doing B=(A<<8)|(B&$FFFF), then whenever you need to access A you'd do B>>8 and to get B you'd do B&$FFFF
- you can use a similar technique to make data smaller (so if you're sending certain variables to other players or the server in an online game, less data needs to be transferred... also it can be used in a saving script to decrease the size of save files)

Edited by dannyjenn, 04 January 2013 - 02:22 PM.

  • 0

#48 Guest_Experimenator_*

Guest_Experimenator_*
  • Guests

Posted 11 January 2013 - 10:29 AM

Optimization is what you do to improve the performance of your game/application.
So you probably have seen topics like this or websites like http://forums.tigsou...hp?topic=3747.0

But before you try it, know this: Optimization must be ONLY done where it needs to be done!
Optimizing something that does not need to be optimized is an evil waste of programmer's time to concentrate on development instead of optimization only + there is no gain in speed whatsoever
(Actually, there is. It's measured in micro seconds!!)

The worse comes when the programmer starts thinking about optimization all the time so he wastes even more time by fixing every single little mistake.
Eventually, He becomes so obsessed with the optimization that he cannot even create a variable properly without thinking "No, there has to be a better way of declaring variables"
And that, is when you know you need to cut off and stop this!

If you have been infected by the disease of optimization, in the extreme, take these first few steps that will help you get rid of this:

1. Don't care about declaring variables.
A variable won't slow down the game in anyway (Computer can declare 100s of MB in a second) nor will it take a barely any memory (8bytes actually).
Besides, every computer has a behavior to declare variables and use them, it just works like that.

Some people just don't like to create variables so instead they do everything on a single line thus decreasing readability, and, more importantly, make it slower than it should have been with several lines. (I know cause I was one of them)

2. Don't care about the performance Arithmetic operations.
Arithmetic functions are so low level and basic that they only use 1 CPU cycle on pure machine code.
Remember Game Maker works 500 times slower than machine code, and when it can still do 100.000 of these operations a second. Can you see now the speed of which computers calculate things?

3. Don't care about the performance Mathematical functions.
Many would say that functions like: sqrt sin cos tan ln exp power asin acos atan,
are slow to and they are right, they are hard to calculate accurately.
But modern day processors have those accelerated inside themselves, which means that programs don't need to calculate them themselves, CPU will do it for them!

4. Don't be afraid to use data structures.
I have seen some people that say that they won't use data structures because "they're not efficient" and that they are "big memory consumers". Entirely the opposite!
DS work closer to the CPU than GML code thus they are faster,
And they have inside themselves nothing more than a variable that is saying the size of it and an array for the elements, that's all.

Also, in GM you won't feel lag until you start declaring 40000 variables a second, thus you can relax using Data Structures.

5. Don't care about the code style for the sake of optimization
It doesn't matter how you use any programming language (including GML) while the syntax is correct and working.
Every code style will work the same way however you write it.
//ex.
if (a==5) {dsa=4;}                   //this
if a=5 dsa=4                         //is absolutely the same as this
switch (a) {case 5: dsa=4; break;}   //and this
Nor you should care about shrinking the code!
a = 1/4+4*sin(direction*pi/180)/cos(direction*pi/180); //this
a = 0.25+tan(degtorad(direction)); //can be written as this
// but it doesn't matter!!

final: Don't care about optimization/efficiency until it's needed!
Don't think ahead about the performance! Because that's how you will get addicted to this!
First start making a game and when it happens that your game is becoming slow, only then try something to do about it
ex. deactivate the instances, reduce the resource number, shrink the huge loops, improve the code...
But don't do the slight optimizations listed above in this topic!

Eventually, optimization is good if you know what you're doing.
But if you are going to do those slight little oprimizations, and improving something that is already good, just remember this: IT IS POINTLESS!!

Edited by Experimenator, 11 January 2013 - 10:34 AM.


#49 paul23

paul23

    GMC Member

  • Global Moderators
  • 4147 posts
  • Version:GM:Studio

Posted 11 January 2013 - 12:30 PM

Merged a topic into this discussion: I'd like to keep all discussion about optimization & it's usefulness inside 1 topic.


Anyways, back to the topic, I'm shocked we haven't heard one of the most profound quotes of the guru of programming

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil
- Donald Knuth


  • 0

#50 dannyjenn

dannyjenn

    GMC Member

  • GMC Member
  • 2736 posts
  • Version:Mac

Posted 11 January 2013 - 05:28 PM

I agree with some of what Experimenator is saying, but some of it is just wrong:

1. While that is true for the most part (in GameMaker anyway), that's the sort of attitude that leads to memory leaks which could have easily been prevented...
Not declaring variables is nothing more than being lazy. It's not difficult to do (one extra line of code with a three-letter keyword followed by the variable name...) and if you're in the habit of doing it (which you should be) then it's not even something you think about. There's no reason not to do it...

2. Most operations take more than just one cycle in machine code... it really depends on the operation as well as the operands. They are fast though, however, if you are using them in a very long loop then it actually can be noticable. I once wrote a (slow) function that took an extra few seconds to finish running before I went back and optimized it by removing unnecessary operations (although this is sort of what Experimenator was getting at in his final point... make optimizations in places that it matters)

5. The switch statement is actually not the same and has always ran faster whenever I tested it. Still, it won't make much difference unless speed matters e.g. if you use it in a very long loop then it'll make a difference.

Final. True, until you finish making your game and discover it's so inefficient that it's not even playable and you have to go back and re-write nearly the entire game for efficiency, lol j/k, but it does save you some work in the end, as long as you don't obsess so much over it that it takes you ten times as long to write any code at all.

Edited by dannyjenn, 11 January 2013 - 05:30 PM.

  • 0