Game Development Community

Global Vars vs. Script objects

by Guy Lewis · in Torque Game Builder · 03/27/2007 (8:26 pm) · 12 replies

I have been tinkering around with a little project I have in mind to sharpen my TGB knowledge and ran into a problem that brought up an interesting question for me.

I need to create several (20 or so) variables that need global access. That got me thinking, what if I stored them in a script object as dynamic fields?

So the question is which is more efficient?

#1
03/28/2007 (1:08 am)
I don't know which is more efficient, but the way I see it it's a matter of use, not efficiency.

I use globals for variables that are a major part of the game but whose values are not needed once the player leaves the game. The actual score of a level, the elapsed time, level time, etc, are globals.

I use script objects if I need organization and to save the objects, for instance, all player profile related information, like name, avatar, score, achievements, yada yada yada.

But don't take my word for it. :)
#2
03/28/2007 (9:54 am)
@Guy, there's actually a thread that goes into quite a bit of detail over the performance difference between the two ... for the sake of 20 variables, you won't really notice any difference, unless your looping through the code hundreds or thousands of times per frame ....

But generically, global vars are more performance tuned that ScriptObjects, due to the way in which Script Object Dynamic Fields are stored, and how you access them ... if you look at the C++ ... there is probably about 10-20 different C++ methods that are called to retrieve the value of a single Dynamic Field ... where as, with a global var, it's more or less just stored in a memory stack and accessed fairly quickly ... the difference being maybe 10-15 blocks of code between the two ...

As I said, for the sake of 20 variables ... and depending on your usage and access timing ... you probably wouldn't notice a difference ...

When we bench marked it in the other thread, I believe we had to get up to around 1000+ loop interations before the timing was calculatably different, and you'd have to get to around 1,000,000 iterations before it's visibly noticable (at which point, you shave a few seconds off ... but your games non-responsive in both cases ;p)

I can't remember the thread title, otherwise I'd post a link ...
#3
03/28/2007 (10:19 am)
Interesting to notice that the variables I described above as globals are more used than the script object ones. Comparing this to what David described, I believe it's a nice method.
#4
03/28/2007 (11:07 am)
Quote:As I said, for the sake of 20 variables ... and depending on your usage and access timing ... you probably wouldn't notice a difference ...

Very true... and I found your tests (and the tests of others) in that other thread very interesting. What would be an interesting test would be to flood a ton of global variables and see how that effects consistent memory usage. Considering a globalVar is simply stored in a globalVar hash table the lookup times for globalVars are pretty quick vs. accessing on an object. On the other hand the globalVar could get quite large when you start storing most of your values in it. In any case a test for another thread.

As far as cleaner looking code I'd definitely say a ScriptObject... values attached to data storing objects always look much cleaner and also can help you manage the values later (it also means you can do a .save() and dump them out to file easily as well). Though global vars do have their uses... and you can distinguish them using various characters... such as "::"...

$gameData::blah = "blah";

etc... though I'm a fan of

new ScriptObject(gameData):

gameData.blah = "blah";
#5
03/28/2007 (11:23 am)
Thanks for the feedback! Those were the basic conclusions I was coming to as well.

I think I am going to go with the script object approach because as Matt said

Quote:
As far as cleaner looking code I'd definitely say a ScriptObject

The stuff I am playing around with right now isn't intense at all and I am sure even a very low end system wouldn't have problems with it.

@Dave
Now that you mention it, I do remember the other thread! My memory ain't what it used to be
Remember search is my friend :)

Hopefully I will have it in a state soon where I feel comfortable sharing it and get some feedback.
#6
03/28/2007 (11:27 am)
If it helps, I use ScriptObjects where ever possible -- unless it does actually affect performance in a noticeable fashion ... I do this, largely because of the .save() functionality ... although, you can do the same with global vars, but it's just not as clean looking ...
#7
03/28/2007 (11:44 am)
@David: yeah, using the export function for large amounts of data and/or data that needs to be fairly organized always makes me feel hacky lol.
#8
03/28/2007 (12:00 pm)
Good clean code, though not always as performance tuned as it can be, is almost always better then ugly hard to read code -- unless the code is really causing a problem with performance, the 'clean' approach should be adhered too ... thats my personal philosophy anyhow ...

I've run into a few different things with TorqueScript where ... This is Faster, This looks Better ... and it's always a "do I need it to be faster? is the performance gain noticeable? is it worth making the code unreadable?" debate ... I usually just say screw it ... and go for the clean approach, which is sometimes ugly and unreadable at first ... :)

You don't even want to know how many times I've revisited the Dungeon Builder code and went ... "WTF WAS I THINKING?!" ... I think I finally have it down to a nice clean base ... though, I'm still questioning whether or not it's going to be performance tuned enough to 'render' large numbers of sprites to the screen ... since it basically relies on deleting the contents of the scenegraph, then rebuilding the view from scratch ... but it only does this when the player moves and the view changes ... but it has to create and add upwards around 100+ sprites to the scenegraph in one call ... while still giving the user a "smooth" feel ...

I've though about breaking some of the code out into objects ... possibly store a reference to different things ... and 'copy' those objects ... so I don't have to create them from scratch each time ... though, they'll probably be a whole discussion thread about the performance differences between creating sprites from scratch or copying sprites coming up soon when I get to that point ... but if I opt to go that route, I'd have an scriptObject that stored all the objects in a SimSet/Group with accessor functions added to it ... "getPerspecticeRightWall", "getPerspectiveLeftWall", "getPerspectiveCeiling", etc, etc ... "getPerspectiveObject(rock)" ... lar lar lar ...
#9
03/28/2007 (12:30 pm)
I hear ya. Clean code is always easier to debug and more so, understand when you go back to it 6 months later and try to figure out why you did something.

I too am constantly going through the juggling faster/cleaner. I always say cleaner and if you need to go back and optimize it is much easier. I have really gotten into the habit of using objects myself for most tasks. They are just so much cleaner and manageable. Plus I hail from the old school C world where commandment #1 was "Thou Shalt not create a global var!" :)

Thanks for all the pointers guys. I will let you know how things go.
#10
03/28/2007 (3:06 pm)
Ok,
I couldn't resist running a couple of tests to see the impact of a script obj vs a global var.

here are the results
baseline
      mem usage 18980k (this is just from taskmgr so it is a rough mem usage)
      base script that does not create a canvas. 

10000 variables
    scriptobj
       mem usage 19624k
       time to create 64ms
    global vars
       mem usage 19692k
       time to create 32ms

100000 variables
    scriptobj
       mem usage 25636k
       time to create 5188ms
    global vars
       mem usage 25880k
        time to create 486ms

150000 variables
    scriptobj
       mem usage 28780k
       time to create 19546ms
    global vars
       mem usage 29940k
       time to create 640ms

The results definately show a significant time penalty using a script object. But then again how often are you writing something that needs a 100000 variables :)

Mem usage was write on par using either method.

Another interesting test I did was to time the reads. Funny thing, it is taking roughly 10% longer for the reads than it is for the writes. That is using either method.

here is the code I used
$MAXITR = 150000;

function enumscriptobj()
{
	
   if (!isObject (GameModeEnum))
	   new ScriptObject (GameModeEnum)
   		{
			None = 0;
		};
	

    %start1 = getRealTime();
    
    for (%i = 0;  %i < $MAXITR;  %i++)
	    GameModeEnum.None[%i] = 0;
    
    %end1 = getRealTime();

echo ("scriptObj create" @ %start1 @ " to " @ %end1 @ ": " @ (%end1 - %start1));

    %start1 = getRealTime();
    
    for (%i = 0;  %i < $MAXITR;  %i++)
	    %y = GameModeEnum.None[%i];
    
    %end1 = getRealTime();

echo ("scriptObj read" @ %start1 @ " to " @ %end1 @ ": " @ (%end1 - %start1));    
}

function enumglobal()
{
    %start2 = getRealTime();
        for (%j = 0;  %j < $MAXITR;  %j++)
		%x[%j] = 0;

	%end2 = getRealTime();
	echo ("Global var create" @ %start2 @ " to " @ %end2 @ ": " @ (%end2 - %start2));

    %start2 = getRealTime();
        for (%j = 0;  %j < $MAXITR;  %j++)
		%y = %x[%j];

	%end2 = getRealTime();
	echo ("Global var read" @ %start2 @ " to " @ %end2 @ ": " @ (%end2 - %start2));

}

I called the functions from the console prompt. Restarting TGB between each test.
#11
03/28/2007 (7:37 pm)
You can't use TaskMgr to determine memory usage, it shows an average amount, and windows preallocates memory on a per-application basis and displays preallocated memory in Task Mgr ... you need to use a 'real' memory tool to get the actual memory used ...

As for the read/write timing differences ... makes sense ... there's more function calls in a read then there is in a write, go figure, :)
#12
03/28/2007 (9:19 pm)
Ya, I didn't want to get into doing an indepth test. I used taskmgr because it showed that either method used roughly the same amount of memory. I was just looking for some real ballpark figures. It sufficed.