Jump to content


Photo

Optimizing your game further


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

#1 kibblesbob

kibblesbob

    "Xarrot Studios"

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

Posted 08 March 2012 - 03:00 AM

Ok, so I was working with a giant loop, and I had many scripts running inside this loop at once, doing lots of calculations and drawing primitives and what not. I was trying to optimize it, shorten any code I could, and simplify every process that needed to be calculated. But I still wanted more. It didn't occur to me that I could actually be slowing my game down with using scripts, the length of the scripts name, and the content and format of the script itself, until I removed a script and replaced it with only GML. It increased my total FPS from 21-29, to around 24-36. I was amazed! The scripts being called, even though not much was going on in them, were slowing the game down!

Around this time, I decided to do a few tests, and I worked them out all under the same circumstances:
- No other programs running during all testing
- Kept the same room-size throughout each test ( 32x32 ), no drawing, black background
- Only made changes to the code in the create event of the one object I had in the room
- All tests were done seven times, consecutively
- Did not use the game_restart() function, just quit game and ran a new instance of the test
- Done in GM8 Registered

---Here are the tests ---


Test 1 : Executed the following piece of code WITHOUT the use of scripts

var t;
t = current_time;
repeat ( 25000 )
 { x = 0 ; y = 0 ; x = 0 ; y = 0 ; x = 0 ; y = 0 ; x = 0 ; y = 0; }
show_message((current_time-t));

Test 2 : Executed the following piece of code WITH a script called 'tst'

In this test, script 'tst' contained the following code:

repeat ( 4 )
 { x = 0 ; y = 0; }

The test was executed as follows:

var t;
t = current_time;
repeat ( 25000 )
 { tst(); }
show_message((current_time-t));


Test 3 : Executed the following piece of code WITH a script called 'tst'

In this test, script 'tst' contained the following code:

x = 0 ; y = 0;
x = 0 ; y = 0;
x = 0 ; y = 0;
x = 0 ; y = 0;

The test was executed exactly the same as Test 2


Test 4 : Executed the following piece of code WITH a script called 'tst'

In this test, script 'tst' contained the following code:

x = 0;
y = 0;
x = 0;
y = 0;
x = 0;
y = 0;
x = 0;
y = 0;

The test was executed exactly the same as Test 2 and Test 3


Test 5 : Executed the following piece of code WITH a script called 'tst'

In this test, script 'tst' contained the following code:

x = 0 ; y = 0 ; x = 0 ; y = 0 ; x = 0 ; y = 0 ; x = 0 ; y = 0;

The test was executed exactly the same as Test 2, Test 3, and Test 4


Test 6 : Executed the following piece of code WITH a script called 'one_big_gigantic_script_name_to_tst_this_scrpt_4real'

In this test, script 'one_big_gigantic_script_name_to_tst_this_scrpt_4real' contained the following code:

x = 0 ; y = 0 ; x = 0 ; y = 0 ; x = 0 ; y = 0 ; x = 0 ; y = 0;

The test was executed exactly the same as Test 2, Test 3, Test 4, and Test 5

---Here are the results ---


Test 1 : Average time to calculate: .11 seconds

Trial 1: .11s, Trial 2: .11s, Trial 3: .09s, Trial 4: .11s, Trial 5: .12s, Trial 6: .13s, Trial 7: .08s


Test 2 : Average time to calculate: 1.91 seconds

Trial 1: 1.89s, Trial 2: 1.93s, Trial 3: 1.90s, Trial 4: 1.92s, Trial 5: 1.90s, Trial 6: 1.86s, Trial 7: 1.97s


Test 3 : Average time to calculate: 1.84 seconds

Trial 1: 1.86s, Trial 2: 1.79s, Trial 3: 1.83s, Trial 4: 1.83s, Trial 5: 1.84s, Trial 6: 1.84s, Trial 7: 1.90s


Test 4 : Average time to calculate: 1.88 seconds

Trial 1: 1.98s, Trial 2: 1.83s, Trial 3: 1.93s, Trial 4: 1.79s, Trial 5: 1.84s, Trial 6: 1.92s, Trial 7: 1.86s


Test 5 : Average time to calculate: 1.82 seconds

Trial 1: 1.79s, Trial 2: 1.84s, Trial 3: 1.76s, Trial 4: 1.84s, Trial 5: 1.81s, Trial 6: 1.84s, Trial 7: 1.86s


Test 6 : Average time to calculate: 1.86 seconds

Trial 1: 1.87s, Trial 2: 1.86s, Trial 3: 1.92s, Trial 4: 1.78s, Trial 5: 1.86s, Trial 6: 1.83s, Trial 7: 1.89s


---Conclusions/What I learned ---


The most important thing I picked up from doing this test, is that scripts can slow down your game, albeit not by much. If you are using nested-loops and running scripts nested in scripts in those nested-loops, you may want to just bite the bullet and type it out into the code editor and ditch the scripts.

Secondly, make sure you condense your code as much as possible. That doesn't mean fit everything into one line, but make sure if you have extra lines at the end of your code or scripts, remove them! Of course, as usual, keep your code readable, neat, and most importantly, to your liking. Just keep the lines of code to a minimum.

Lastly, keep your script names shorter. As you can see, the only difference between Test 5 and Test 6, is that Test 6 has a longer ( and more ridiculous ) name. Script names, according to this test, affect their calling speed. It makes sense; long name = long call times. So be sure to shorten the names, but also keep them recognizable, especially if it is an example or engine other users will be working with.

My final words on this would be, keep everything short, sweet, and to the point. It will save your processor some unneeded calculations, and will increase its performance, especially in cases where loops are used often. I hope this helps someone, somewhere! :cool:
  • 4

#2 DanRedux

DanRedux

    GMC Member

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

Posted 08 March 2012 - 05:37 AM

This is until Game Maker is converted to some sort of Byte Code format (which is long overdue). Then silly things like length of names/functions won't matter.
  • 0

#3 kibblesbob

kibblesbob

    "Xarrot Studios"

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

Posted 08 March 2012 - 06:28 AM

my face when that happens: :woot:
  • 1

#4 Gamer3D

Gamer3D

    Human* me = this;

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

Posted 17 March 2012 - 04:54 PM

GM's slow scripts have been a well-known fact for a while, as has the solution.

Script name does not affect performance. You are merely putting too much emphasis on an insignificant time difference.

Results of a similar test with 10000000 repetitions: Inline: 9641 ms, Short (sht): 29016 ms, Long (veryverylongscriptnamenoreallyitistoolongforallpracticalpurposes): 29001 ms

Edited by Gamer3D, 17 March 2012 - 04:54 PM.

  • 0

#5 kibblesbob

kibblesbob

    "Xarrot Studios"

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

Posted 22 March 2012 - 04:46 PM

I've heard of inlining, it's a neat idea. Honestly though, I just tend to use scripts as little as possible anymore :thumbsup:
  • 0

#6 slayer 64

slayer 64

    Slayer of gingers

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

Posted 29 March 2012 - 12:41 AM

make your loop 250 and see if there's a difference in speed
  • 0

#7 Desert Dog

Desert Dog

    GMC Member

  • GMC Elder
  • 6409 posts
  • Version:Unknown

Posted 29 March 2012 - 02:04 AM

Give this a test, and see how it compares to your other tests.

script_to_call();
var t;
t = current_time;
repeat ( 25000 )
 { tst(); }
show_message((current_time-t));

tst();
//pick your poison.

Call code:
script_to_call();

  • 0

#8 Yal

Yal

    Gun Princess

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

Posted 23 April 2012 - 11:22 AM

While it's been known for a long time that Game Maker's scripts are slow, the main reason I try to use scripts as often as possible is because of enhanced readability, and to remove the possibility of overlooking changing code at places.


One vital thing your post didn't make clear: are you using GM8.0 or GM8.1? In GM8.1 scripts were sped up since Game Maker won't pass 16 arguments anymore but only as many as needed. (You'd have to enable an option in the Global Game Settings for this, but it would default be on if you started a new project in GM'81... I think it would default to off if you load an older file, though)
Apparently the main reason the procedure of calling a script itself takes time is because passing the arguments and making room for 16 variables of data takes time, so if that is skipped altogether with argumentless scripts I'd say there should be a less signficant difference between the script and the inline expansion way of doing it.
  • 0

#9 Desert Dog

Desert Dog

    GMC Member

  • GMC Elder
  • 6409 posts
  • Version:Unknown

Posted 23 April 2012 - 08:34 PM

I use to avoid scripts because 'they were slow', or so I heard. Now I embrace them (or try to!!). It's just smart programming.
  • 0

#10 The2Banned2One

The2Banned2One

    BANNED

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

Posted 24 April 2012 - 03:28 AM

I use scripts to organize my code. I mostly use them to organize initialization code so speed doesn't matter that much there.
If I am doing something every step I try not to use scripts.

Edited by The2Banned2One, 24 April 2012 - 03:29 AM.

  • 0

#11 Yal

Yal

    Gun Princess

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

Posted 25 April 2012 - 08:02 AM

I realized something... when you need to pass loads of arguments to a script just for the script versatility, couldn't you just use event_perform_object() to call an unused event (e.g. an User Defined Event of a parent object) and save some speed? I'm thinking about making a 2D platformer engine, and to draw the platforms I'd use a script called something like draw_block(x1,y1,z1,x2,y2,z2,sidetexture,fronttexture,toptexture,bottomtexture,siderepeat,frontrepeat,toprepeat,bottomrepeat) which, as you can see, would use a whopping 14 arguments... and practically every single object would call this. Then I got the idea to use the event_user() of some dummy object instead of a script to save the argument passing business (the user event would refer to variables all blocks would have, namely all the things I called the arguments in the script above, rather than to arguments), giving this object "script events" for blocks, cylinders, wedges and so on so that I could make all sorts of platforms from a "blueprint" I could change if need be.
  • 0

#12 GStick

GStick

    All Secrets Exposed

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

Posted 25 April 2012 - 08:42 PM

^That sounds like a great method for doing something that a large number of objects share. Does it only save on all the annoying argument passing (and repeated code) or has it also improved execution time?
  • 0

#13 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 21723 posts
  • Version:GM:Studio

Posted 25 April 2012 - 08:51 PM

I realized something... when you need to pass loads of arguments to a script just for the script versatility, couldn't you just use event_perform_object() to call an unused event (e.g. an User Defined Event of a parent object) and save some speed? I'm thinking about making a 2D platformer engine, and to draw the platforms I'd use a script called something like draw_block(x1,y1,z1,x2,y2,z2,sidetexture,fronttexture,toptexture,bottomtexture,siderepeat,frontrepeat,toprepeat,bottomrepeat) which, as you can see, would use a whopping 14 arguments... and practically every single object would call this. Then I got the idea to use the event_user() of some dummy object instead of a script to save the argument passing business (the user event would refer to variables all blocks would have, namely all the things I called the arguments in the script above, rather than to arguments), giving this object "script events" for blocks, cylinders, wedges and so on so that I could make all sorts of platforms from a "blueprint" I could change if need be.


You do realise that this is exactly what parenting does? You create a parent object for everything with the code in the draw event and then have everything use event_inherited()... Although I'd still be interested to see what kind of speed differences are involved with using scripts, object holders (as you suggest) and parents, as well as seeing how many instances can be on screen at a time while using these methods...
  • 0

#14 Yal

Yal

    Gun Princess

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

Posted 26 April 2012 - 08:33 AM

The main idea with an "object holder" (that's a better name) would be that objects that are not childs of some ancestor object call still inherit some "script" from them. For instance in a 3D platformer game you might have blocks with items in that fall off the screen when you hit them, and it'd be nicer to make those draw using an object holder user event than to have to make a parent or duplicate the code for them.

My main plan with the object holders was actually to let both cylinder, wedge and block platforms inherit from one parent, but draw themselves using different sub-events from the parent. That'd be a lot let hassle than having to make an ancestor for each one of them.
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users