Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Script optimization

Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-03-2008 11:09
From: Tex Evans
I seem to remember a thread where Strife Onizuka mentioned that it is more efficient to write the following code:

integer x = 0;

as

integer x;
Inside a function, yes. At the global level these are identical.
From: Kenn Nilsson
Integers are interesting, as they will default-value to 0 for mathematical operations, but they will NOT default to a value of "FALSE".
If so, that's a bug. Not only that, I've worked on both the CIL and LSL2 code generators in the compiler before they were moved to the server and I am unable to imagine how the compiler could generate code for which "int == FALSE" and "int == 0" would produce different results, because internally FALSE is an integer constant zero.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
12-03-2008 11:14
From: Argent Stonecutter
Inside a function, yes. At the global level these are identical..

Functionally identical but it probably costs an extra 4 bytes or so of code space every time you do it.

Pre-mono, for a big script with lots of globals, I guess I can see avoiding explicitly setting things to their default value if their default is the same as the LSL default. (edit: ..., especially if Strife recommended it)
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-03-2008 11:37
From: Meade Paravane
Functionally identical but it probably costs an extra 4 bytes or so of code space every time you do it.
There is no code executed at the global level, just an initial value for every global, including ones that are not explicitly initialized:
CODE


// now we need space for the variable itself
LLScriptByteCodeChunk *value = new LLScriptByteCodeChunk(FALSE);
if (mAssignable)
{
mAssignable->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, value, heap, stacksize, entry, entrycount, NULL);
// need to put sneaky type conversion here
if (mAssignableType != mType->mType)
{
// the only legal case that is a problem is int->float
if (mType->mType == LST_FLOATINGPOINT && mAssignableType == LST_INTEGER)
{
S32 offset = value->mCurrentOffset - 4;
bytestream_int2float(value->mCodeChunk, offset);
}
}
}
else
{
if ( (mType->mType == LST_STRING)
||(mType->mType == LST_KEY))
{
// string and keys (even empty ones) need heap entries
chunk->addInteger(heap->mCurrentOffset + 1);
LLScriptLibData *data = new LLScriptLibData("");
U8 *temp;
S32 size = lsa_create_data_block(&temp, data, heap->mCurrentOffset);

heap->addBytes(temp, size);
delete [] temp;
delete data;
}
else if (mType->mType == LST_LIST)
{
chunk->addInteger(heap->mCurrentOffset + 1);
LLScriptLibData *data = new LLScriptLibData;
data->mType = LST_LIST;
U8 *temp;
S32 size = lsa_create_data_block(&temp, data, heap->mCurrentOffset);

heap->addBytes(temp, size);
delete [] temp;
delete data;
}
else if (mType->mType == LST_QUATERNION)
{
chunk->addFloat(1.f);
chunk->addFloat(0.f);
chunk->addFloat(0.f);
chunk->addFloat(0.f);
}
else
{
value->addBytes(LSCRIPTDataSize[mType->mType]);
}
}
chunk->addBytes(value->mCodeChunk, value->mCurrentOffset);


That is, if there is an an initial value, that value is put into the code space, otherwise a default value (ether null bytes or something like a null string, the <0,0,0,1> quarternion, etc) is put there.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Fynch Flanagan
Registered User
Join date: 7 Apr 2007
Posts: 1
It succeeds for me
12-03-2008 11:52
From: Kenn Nilsson
Integers are interesting, as they will default-value to 0 for mathematical operations, but they will NOT default to a value of "FALSE".


HOWEVER ...

CODE


integer x;

default
{
state_entry()
{
if(x != FALSE) llSay(0, "failed");
else llSay(0, "success");
}
}



...will say "failed".




Not initializing an integer gives me a result in agreement with x==0 and x == FALSE
In the following test I also added the if statement from the quoted script. This results in "success" when I try it. So I can't reproduce the bug mentioned.

CODE


integer x;
default
{
state_entry()
{
if (x==0) {llOwnerSay("x==0");} else {llOwnerSay("x==0 failed");}
if (x!=0) {llOwnerSay("x!=0");} else {llOwnerSay("x!=0 failed");}
if (x) {llOwnerSay("x");} else {llOwnerSay("x failed");}
if (!x) {llOwnerSay("!x");} else {llOwnerSay("!x failed");}
if (x==FALSE) {llOwnerSay("x==FALSE");} else {llOwnerSay("x==FALSE failed");}
if (x!=FALSE) {llOwnerSay("x!=FALSE");} else {llOwnerSay("x!=FALSE failed");}
if (x==TRUE) {llOwnerSay("x==TRUE");} else {llOwnerSay("x==TRUE failed");}

if(x != FALSE) llSay(0, "failed");
else llSay(0, "success");

}

}



Gives the following result:

[11:43] Object: x==0
[11:43] Object: x!=0 failed
[11:43] Object: x failed
[11:43] Object: !x
[11:43] Object: x==FALSE
[11:43] Object: x!=FALSE failed
[11:43] Object: x==TRUE failed
[11:43] Object: success
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-03-2008 12:40
From: Argent Stonecutter
I am unable to imagine how the compiler could generate code for which "int == FALSE" and "int == 0" would produce different results, because
internally FALSE is an integer constant zero.
That's why I found it hard to believe. I'm happy i was unable to reproduce the results.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
12-03-2008 14:39
From: Tex Evans
I seem to remember a thread where Strife Onizuka mentioned that it is more efficient to write the following code:

integer x = 0;

as

integer x;

My questions are:

Is it safe to assume that LSL will always assign 0 to an integer variable when it's declared?

On a similar note, is it safe to assume that LSL will always assign "" to a string variable when it is declared?


You have reversed it, it's better to set a value when you define it because otherwise the compiler will set a default value for you. So "integer x; x = 5;" is less efficient because it compiles to "integer x = default; x = 5;". It's just better to write "integer x = 5;" and be done with it.

It is safe to assume that LL will not change the default values lest they break code that depends on those default values. However if you are going to use the value of the variable before explicitly storing a value to it, you really should include a default value and not depend on the implicit default value; that way you know that the variables initial value is important (I'm thinking about global variables).

Strings, keys and lists (SKL) are different though, with global SKLs you may find it better to delay setting the initial values. There is no optimization for variables that are to share the same value, so if you need to have 8 keys all to NULL_KEY initially, it would be better to do them all at once "a = b = c = d = e = f = g = h = NULL_KEY;", this way you only have one copy of NULL_KEY floating about in the bytecode (not 8). Mono may do a better job of eliminating this wastage, I don't know.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Tex Evans
Registered User
Join date: 17 Oct 2006
Posts: 5
12-08-2008 20:56
Thanks everyone who replied. I appreciate your help.
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-09-2008 06:55
From: Strife Onizuka
Strings, keys and lists (SKL) are different though, with global SKLs you may find it better to delay setting the initial values. There is no optimization for variables that are to share the same value, so if you need to have 8 keys all to NULL_KEY initially, it would be better to do them all at once "a = b = c = d = e = f = g = h = NULL_KEY;", this way you only have one copy of NULL_KEY floating about in the bytecode (not 8). Mono may do a better job of eliminating this wastage, I don't know.
One clarification: that may be true for keys, but if you look at the code I quoted... for global strings and lists an explicit null string or empty list is put in the initial heap for every uninitialized string or list. Initializing them again is a waste of space.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-09-2008 08:11
From: Argent Stonecutter
One clarification: that may be true for keys, but if you look at the code I quoted... for global strings and lists an explicit null string or empty list is put in the initial heap for every uninitialized string or list. Initializing them again is a waste of space.


Not trying to be contentious, but relying on implicit behavior is dangerous.
Explicitly initializing your variables is not a waste of space. Just an opinion
born out of experience fixing broken code that relied on implicit behavior.
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
12-09-2008 08:19
WOOHOO! I am cured!!!!!!!!! I've made it through a whole optimization thread without throwing in my 2 cents worth :p
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-09-2008 08:35
From: Jesse Barnett
WOOHOO! I am cured!!!!!!!!! I've made it through a whole optimization thread without throwing in my 2 cents worth :p


lol ;)
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-09-2008 08:56
From: Jeredin Denimore
Not trying to be contentious, but relying on implicit behavior is dangerous.
I think you're in violent agreement with me. I was pointing out that the optimization that Strife suggested would not save any space for strings or lists, so you might as well initialize all of them.

However, I will note that when I pointed out that one of Strife's optimizations would be broken by the CIL code generator in the compiler, after examining the source for the same, Linden Labs changed the compiler to keep Strife's optimizations from breaking.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-09-2008 09:12
The problem is, since LSL isn't documented or defined, all behavior is "implicit". It does what it does, and in the future, it will do what it will do.

It's definitely safe to assume that integers are initialized to zero, strings are initialized to the empty string, and lists are initialized to the empty list. Vast numbers of scripts would be broken if this were to change. This behavior was even stated in the earliest offical LSL documentation, whcih is now gone.

I would not chide the coder who relies on these assumptions, nor would I chide on the coder who does not. However, relying on the assumptions in certain cases uses less byte code and runs faster. In most cases, this efficiency gain is insignificant. (Global variables are more efficient than local variables, but that won't keep me from using locals unless absolutely necessary!)
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-09-2008 09:25
From: Lear Cale
However, relying on the assumptions in certain cases uses less byte code and runs faster.
For the specific cases I was referring to, relying on the assumptions does not save code or heap space. You might as well go ahead and initialize everything at the global level.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
12-09-2008 09:37
From: Lear Cale
(Global variables are more efficient than local variables, but that won't keep me from using locals unless absolutely necessary!)

Are they really? I always thought languages (in general) were more efficient with locals..
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-09-2008 10:09
From: Argent Stonecutter
I think you're in violent agreement with me. I was pointing out that the optimization that Strife suggested would not save any space for strings or lists, so you might as well initialize all of them.

However, I will note that when I pointed out that one of Strife's optimizations would be broken by the CIL code generator in the compiler, after examining the source for the same, Linden Labs changed the compiler to keep Strife's optimizations from breaking.


Heh, I stand corrected on initialization... we do agree.

And as for changing the compiler to NOT break ... ewwwwwww. I may be anal
about this topic (hah @ may), but any compiler that embraces implicitness is
encouraging ingrained bad practices in my opinion.

From: Lear Cale

I would not chide the coder who relies on these assumptions, nor would I chide on the coder who does not.


Heck, I'm not "chiding" anyone for doing what they want to do. Feel free to
code any way that works for you... just expressing my own opinions on the
matter. Individual projects with one coder it won't matter anyway. It's when
an implicit programmer and an explicit programmer get on the same team
when things get ugly.
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-09-2008 10:20
From: Meade Paravane
Are they really? I always thought languages (in general) were more efficient with locals..

In a multi-threaded language (or multi-threading friendly language anyway), global variables have to be stored back to memory after every operation, or at least at thread synchronization points. Local variables, on the other hand, might be optimized away completely by the compiler, or kept entirely in registers, or at least stored back to memory (the stack) infrequently.

Single-threaded languages may be able to optimize global variables almost as well as local ones, though they'll probably always store to memory at least when returning from functions.
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
12-09-2008 10:24
From: Meade Paravane
Are they really? I always thought languages (in general) were more efficient with locals..

Damn you Meade!!!!! :mad: I was being good and everything and you just HAD to keep throwing the bait out to a hungry fish. See post #33.

Just depends entirely in what context efficiency is used. Is it being applied to the run time environment or to the process of writing/debugging the code? You also have to throw in a very healthy dose of what language is the dominant language for the individual programmer.
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-09-2008 11:02
From: Jeredin Denimore
And as for changing the compiler to NOT break ... ewwwwwww. I may be anal about this topic (hah @ may), but any compiler that embraces implicitness is encouraging ingrained bad practices in my opinion.
I agree. In fact I had previously warned Strife that his optimization was likely to break because it depended on the order of evaluation of expressions. :)

No, I wasn't digging through it looking for justification, it was months later I noticed it.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-09-2008 11:07
From: Meade Paravane
Are they really? I always thought languages (in general) were more efficient with locals..
It depends on the level of optimization and the concurrency support defined by the language. For example, in a simple stack compiler a global variable may be loaded with:

LD R1,#address_of_global
LDI R2,R1

Whereas a local would need to be loaded with:

LD R1,#offset_of_local
ADD SP,R1
LDI R2,R1

With more complex language constructs (such as displays or continuations) there may need to be several steps to locate the approriate context for the local.

On the other hand, with an optimizing compiler the local variable can be kept in a register all the time, and the global has to go to memory.

But neither version of LSL (LSL2 or Mono) is an optimizing compiler.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-09-2008 20:24
From: Meade Paravane
Are they really? I always thought languages (in general) were more efficient with locals..


There are so many variations that it doesn't make sense to generalize here. Compiled languages vs. interpreted languages being a huge one, and the details of the "machine" language for a compiled language. LSL is a hybrid: a compiled/interpreted language. That is, LSL gets compiled into a byte code which gets interpreted.

And my statement was an overgeneralization. Globals always take space; locals only take space when they're used. I was thinking only of time optimization, and I made a possibly unwarranted assumption (that LSL creates variables when they're declared, rather than all at once at the start of a function, as many compilers do ... or used to do ...

Hewee is correct about multithreaded, compiled languages, but overgeneralizing for single-threaded. In my career, I've done a lot of work where I wrote in high level compiled language and debugged in machine code (hopefully disassembled, but often not), and in virtually all cases, globals were either more efficient to access or the same, and didn't have to be "optimized" to be the same as locals, *unless the locals are optimized by keeping them in registers*. Without this optimiztion, locals have to be accessed indirectly through a register ("frame pointer";), whereas globals can be accessed directly. Of course, globals always take space

Bottom line? Write clear code. For the small minority of code that has to be optimized, prove that your optimizations help (by testing or inspecting byte code). Or take the words of the wizards and hope you understand them correctly. For the rest, don't bother trying to optimize. It's a huge waste of time.

OPTIMIZE ALGORITHMS, NOT CODE!
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-09-2008 20:25
Argent, my understanding is that Mono is a heavily optmizing compiler.
Klug Kuhn
Registered User
Join date: 7 Sep 2007
Posts: 126
12-09-2008 22:08
From: Lear Cale
OPTIMIZE ALGORITHMS, NOT CODE!


Agreed. :)

We're in SL, even if you have the most optimized code, the object sitting next to you lags it big time... what's the point ..
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-10-2008 03:54
From: Lear Cale
Argent, my understanding is that Mono is a heavily optmizing compiler.
It's not a compiler at all. Mono is a heavily optimizing *interpreter* for a bytecode, implemented by recompiling the bytecode to native code. The actual compiler that produces that bytecode, however, is the same one regardless of whether the end code is LSL2 or CIL bytecode, and it performs NO optimizations at all.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-10-2008 06:53
Thanks for the info, Argent.
1 2 3