Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Memory Optimization Tips

blaze Spinnaker
1/2 Serious
Join date: 12 Aug 2004
Posts: 5,898
09-01-2005 15:17
Post your memory optimization tips here. I'll start

integer i;
for(i=1;i<len;i++) takes up more memory than

integer i=1;
for(;i<len;i++) which takes up more memory than

integer i=0;
for(;i++<len;)

which takes up more memory than

for(i=0;i++<len;)

(make i a global variable since there are no race conditions..)
_____________________
Taken from The last paragraph on pg. 16 of Cory Ondrejka's paper "Changing Realities: User Creation, Communication, and Innovation in Digital Worlds :

"User-created content takes the idea of leveraging player opinions a step further by allowing them to effectively prototype new ideas and features. Developers can then measure which new concepts most improve the products and incorporate them into the game in future patches."
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
09-01-2005 15:43
I'm interested in knowing what the memory usage difference is between those variants. I'm so used to writing/thinking...

CODE
for (i = 0; i < len; i++)


... for loops that personally I'd like to use that just for clarity (to me) and reduced errors (mine) :) So I'm curious about what the tradeoff is, i.e. exactly how much I'm losing by writing the loop that way.

Also, an explanation of why i++<len is faster than i<len;i++ would also be helpful. Superficially, both involve an increment and a comparison, so it's not obvious to me why one is faster than the other. I understand that the compiler won't optimize them both to the same code, but an in-depth explanation of what the compiler will do in both cases would help me, and others, I would think.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
09-01-2005 17:17
It all really depends on the data your processing with the loop.
For example if you will always run the loop once, then a do-while is a good choice.
CODE

integer i = len;
do
{}
while(--i);


Or if len's value isn't critical past this loop you can use it as the counter
CODE

do
{}
while(--len);


oh and using --i or ++i saves 6 bytes over i-- and i++

LSL has 3 jump commands, two are conditional jumps
CODE

//while(a)
@b;
if-false(a)jump(c);
{
//inside while
}
jump b;
@c;

//if
if-false(a)jump(d);
{
//inside while
}
jump m;
@d;
//else if(f)
if-false(f)jump(e);
{
//inside while
}
jump m;
@e;
//else
{
//inside while
}
@m;

//do
@g;
{
//inside while
}
//while(a)
if-true(a)jump(g);


LL could have designed while more efficiantly, instead they constantly parse 5 extra bytes each iteration (since the jump is critical to while loop above, but is only used once below).

CODE

//while(a)
jump i;
@h;
{
//inside while
}
@i;
if-true(a)jump(h);


I've been meaning to write an optimization guide to the wiki but with Mono looming, I was biding my time and write it targeted for Mono.

For optimized scripts I almost never use for, I usualy use while.

Try not to use implicit typecasting for integer to floats for constants.

CODE

func()
{
vector bad = <0,0,0>; // 21 bytes (not counting the store which adds an extra 5)

//good
vector good = <0.0,0.0,0.0>; // 15 bytes (not counting the store which adds an extra 5)

//say you have 20 vectors using implicit in your script, thats 120 wasted bytes.
}
_____________________
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
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
09-01-2005 17:25
From: Ziggy Puff
I'm interested in knowing what the memory usage difference is between those variants. I'm so used to writing/thinking... "for (i = 0; i < len; i++)" for loops that personally I'd like to use that just for clarity (to me) and reduced errors (mine) :) So I'm curious about what the tradeoff is, i.e. exactly how much I'm losing by writing the loop that way.


Just a few bytes (six, actually). The 16K memory allocated for each script is shared between its stack, heap and bytecode, so the change here is in the size of the bytecode. To check this use something like:

CODE

if (j == 1) { for (i = 0; i < 10; i++) {} }
else if (j == 2) { for (i = 0; ++i < 10 ) {} }


which will show only the change in working memory. If we did this in a stack-based bytecode with a really simple compiler, we would see something similar (an extra load and a pop are introduced in the normal form). This is an appropriate optimization for a compiler to make (even Sun's Java bytecode compiler does that much).

As a human, avoid it unless you absolutely need the memory. You are wasting your time.
_____________________
Ignorance is fleeting, but stupidity is forever. Ego, similar.
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
09-01-2005 17:44
Thanks. I figured it was bytecode, didn't see why stack or heap would be affected. I also don't have a feel for "how much script code translates into how much bytecode memory". I should probably run memory checks on scripts of different sizes and find out for myself. So I'm never really sure how close I'm running to the 16K limit... I'm assuming it's not very close for simple scripted objects.

Do library function calls add the full function's bytecode into the script's bytecode usage, or is that a jump into a 'kernel' that doesn't count against the script's own memory usage? And while on that topic, is there a website that discusses more in-depth issues like this? For instance, Strife's post about what the interpreted code looks like - is that information available anywhere? I haven't found anything in the Wiki that covers this kind of stuff. I doubt I'll be writing anything that requires this kind of optimization for a while, but it's good to have some understanding of how the underlying engine works.
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
09-01-2005 19:49
Optimizing your for loops like that is nearly pointless. It will just make your code hard to read, and for what? 6 bytes? Blech.

If you're running into memory problems, optimize your data structures, not your for loops.
a lost user
Join date: ?
Posts: ?
09-01-2005 23:53
Yes I agree with Keknehv. However, it is interesting to see how the system handles all of this junk. :) hehe

Another interesting thing is that when the script *cough* compiles *cough*, it replaces all the constants you have used with their true values. So in this case:
if(llAvatarSitOnTarget() != NULL_KEY) // a very common use for NULL_KEY

what it looks like after it is compiled is:
if(llAvatarSitOnTarget() != "00000000-0000-0000-0000-000000000000";)

Which eats up more memory than you might realise. So if you are going to use the NULL_KEY constant a lot in your script, you might want to think about creating your own null-key variable:
key null_key = NULL_KEY;

This way, whenever you use your own null_key variable, the script references the global variable, rather than replacing the constant variable everytime. It only replaces the constant ONCE, when you declare the key.


And.. yes.. if you are having memory problems, all of this few bytes stuff isn't going to help a lot.. but it is fun to explore :)
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
09-02-2005 00:18
The Mono migration will introduce a completely new bytecode and far better (as in non-zero) optimization of the bytecode and the running code. As Strife noted, producing an optimization guide now would be a lot of work that will become useless shortly.

CIL and Mono introduce a whole variety of *other* problems, which will be worth talking about once we see which LL have in their implementation. CIL is incredibly more complex than it has any realistic reason to be. This just happens to make a trivial compiler/AOT/JIT easier and higher performance, so a performance advantage over Sun's Java VM could be advertised early. Unfortunately, it also makes good speed and size optimizations more difficult, which hurts them on average code produced by average programmers.
_____________________
Ignorance is fleeting, but stupidity is forever. Ego, similar.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
09-02-2005 00:37
i'm just worried they won't optimize the new lsl compiler.

Simple stuff like using ++i; instead of i++;

CODE

//Replacing
//If(test) jump a;
if-false(test)jump(b);
jump a;
@b;
//stuff here
@a;

//with
if-true(test)jump(a);
//stuff here
@a;
_____________________
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
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
09-02-2005 00:46
From: Strife Onizuka
i'm just worried they won't optimize the new lsl compiler.
The Mono AOT/JIT already implements enough optimizations that you don't need to worry about the trivial stuff. Rough list under here.
_____________________
Ignorance is fleeting, but stupidity is forever. Ego, similar.
a lost user
Join date: ?
Posts: ?
09-02-2005 00:58
Just out of interest.. Do you think that, with the advnet of Mono in Second Life, that it will be possible to get some URML visual modelling tools for setting up projects for use in Second Life? I mean.. put simply, you could set up your entities and have communication links between them and set it all up like you would with a relational database, then let the tool generate the skeleton code for you.

CODE

Server<---email-----------||------------email----->Slave
Item Item List
Person_ID Transaction_ID
Transaction_ID


Yeh.. obviously visual stuff is easier to setup :P hehe.. but you can see what I mean hopefully. Would be great to be able to setup the skeleton code quickly, visually and logicaly, then let the tool do all the skeleton work and leave you with something useful to work with.
Jesrad Seraph
Nonsense
Join date: 11 Dec 2004
Posts: 1,463
09-02-2005 01:12
Fascinating stuff :)
_____________________
Either Man can enjoy universal freedom, or Man cannot. If it is possible then everyone can act freely if they don't stop anyone else from doing same. If it is not possible, then conflict will arise anyway so punch those that try to stop you. In conclusion the only strategy that wins in all cases is that of doing what you want against all adversity, as long as you respect that right in others.
blaze Spinnaker
1/2 Serious
Join date: 12 Aug 2004
Posts: 5,898
09-02-2005 01:12
Unfortunately, when you live in a 16K code, 6 bytes can sometimes mean the difference between doing a massive rewrite or not.

And - trust me, the data structures were optimized a very long time ago.

Thanks strife for the bit about the --.

But the
i=1;
{


} while(++i<len)

takes the same memory as

for(i=0;++i<len)
}

I think for iterative loops, the latter is slightly more readable.


The jumps are something I can look at though. There are cases I bet I can use those.


One thing I do worry about Mono is that it might take up more byte code memory. I always leave at least 4K buffer in all my scripts in case an upgrade screws them like that (so really, I live in a 12K world) .. hopefully Mono won't.
_____________________
Taken from The last paragraph on pg. 16 of Cory Ondrejka's paper "Changing Realities: User Creation, Communication, and Innovation in Digital Worlds :

"User-created content takes the idea of leveraging player opinions a step further by allowing them to effectively prototype new ideas and features. Developers can then measure which new concepts most improve the products and incorporate them into the game in future patches."
a lost user
Join date: ?
Posts: ?
09-02-2005 01:29
From: blaze Spinnaker
One thing I do worry about Mono is that it might take up more byte code memory. I always leave at least 4K buffer in all my scripts in case an upgrade screws them like that (so really, I live in a 12K world) .. hopefully Mono won't.


True.. looking at the way they are designing the script qeueing system is a bit cocnerning too because to me that sounds like they are going to keep the 16k limit in favor of allowing people to use many scripts to work aorund it, and then just limit the processing on each script to maintain a fixed Sim FPS. Not really sure on how the system handles all of the memory..

if there are an average of 500 scripts running at full capacity (16k) on a sim, that's 8meg of memory being utilised. Each sim, as far as I am aware, has 512meg of memory.. but has to do alot more with that memory than just process scripts of course. Even with 500 active scripts, defintiely not all running at full capacity in the current environment, it seems that the sims are unable to handle it. So it begs the question that if there is going to be a fixed FPS limit, just how slow are these scripts going to be running? And would having say, 32k per script and potentially reducing the amount of fragmented scripts, actually help more?
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
09-02-2005 02:11
From: Gaz Hornpipe
Just out of interest.. Do you think that, with the advnet of Mono in Second Life, that it will be possible to get some URML visual modelling tools for setting up projects for use in Second Life?


Spent a bit of time playing with it, but I'm holding off on more investment until I know how the Mono integration is going to turn out. If you feel like search fodder, the traditional approach is the ROOM notation (Real-Time Object-Oriented Model, originally from Rational, now part of IBM). More recent stuff tends to be based on the UML2 state machine and component diagrams.

To contribute something that is actually useful for more people: Lists and strings are passed and referenced by a pointer. This means that using a list or string as a parameter or return of a function incurs about the same overhead as an integer. Because they are immutable ("value can not be changed";), appending, prepending or inserting still requires a new copy of the list or string be created. (This is still pass by value, so the Wiki list "Re-Answer" is not technically wrong, just horribly misleading)

Want more memory? Design your script well, and you will be able to separate it into interacting components. Factor components out into separate scripts as necessary, and off you go. Yup, that is a challenge to any of the "OMG I need to save every byte" people to e-mail me an example that can not possibly be refactored.
_____________________
Ignorance is fleeting, but stupidity is forever. Ego, similar.
Eggy Lippmann
Wiktator
Join date: 1 May 2003
Posts: 7,939
09-02-2005 02:24
LSL was designed for parallelization. One of the reason why scripts have so little memory is because the intended use of LSL is something like "one function per script".
In theory, if you wanted to make a poseball that shows and hides itself, and gives a notecard on touch, you should be using 3 scripts for those 3 functions: a generic "animate on sit" script, a generic "give notecard" script, and a general purpose "show/hide" listener. This drag and drop modularity was LL's idea of making scripts usable for the masses, users were supposed to be mixing scripts around without knowing its contents.
For complex projects with mutually dependent parts, link messages are indeed a bit of a pain, but at this point in time, any serious scripter has already abstracted from them into a sort of generic RPC platform, and abstracted from storage issues, and email delays, the works.
If you have a mission critical need for large scale storage, then you should really look into getting a MySQL database. LSL can be successfully used for large scale projects as a thin client interface around a weblication.
Jesrad Seraph
Nonsense
Join date: 11 Dec 2004
Posts: 1,463
09-02-2005 02:48
If parallelization is the goal, why does dropping a folder of scripts in a prim make them NoRun ?
_____________________
Either Man can enjoy universal freedom, or Man cannot. If it is possible then everyone can act freely if they don't stop anyone else from doing same. If it is not possible, then conflict will arise anyway so punch those that try to stop you. In conclusion the only strategy that wins in all cases is that of doing what you want against all adversity, as long as you respect that right in others.
Eggy Lippmann
Wiktator
Join date: 1 May 2003
Posts: 7,939
09-02-2005 02:58
From: Jesrad Seraph
If parallelization is the goal, why does dropping a folder of scripts in a prim make them NoRun ?

I think that's a bug, and I thought that was only if you had many copies of the same script?
Use llRemoteLoadScriptPin and do an installer script that will setup the access pin and message a server.
blaze Spinnaker
1/2 Serious
Join date: 12 Aug 2004
Posts: 5,898
09-02-2005 03:27
From: someone

Want more memory? Design your script well, and you will be able to separate it into interacting components. Factor components out into separate scripts as necessary, and off you go. Yup, that is a challenge to any of the "OMG I need to save every byte" people to e-mail me an example that can not possibly be refactored.


Refactoring into IPC is simply an invitation for bugs. Instead of deterministic programming and compile time checking you are now in a world of pain where everything is call back, messages can come in at different times, not at all, different orders, or other events may fire in between messages that you didn't expect. Did this variable change? Did I copy all my constants around properly?

Avoiding this insanity with tight code seems dead obvious to me.

The fact is- llMessageLinked is not 100% reliable. Not to mention that if you make your objects modifiable, people can link to them and snoop the link messages.

Write a lot of content and some complex, secure objects, and then we'll talk.

And btw, trust me, I make heavy heavy usage of llMessageLinked. But just because I have a hammer doesn't mean I'm stupid enough to think all the world is a nail.

Note.. if we had script upload then I would probably use IPC more because I could add language features which would create compile time checking. However, I'd still write tight code in hopes of avoiding it because I like everything to be deterministic if it can.
_____________________
Taken from The last paragraph on pg. 16 of Cory Ondrejka's paper "Changing Realities: User Creation, Communication, and Innovation in Digital Worlds :

"User-created content takes the idea of leveraging player opinions a step further by allowing them to effectively prototype new ideas and features. Developers can then measure which new concepts most improve the products and incorporate them into the game in future patches."
Eggy Lippmann
Wiktator
Join date: 1 May 2003
Posts: 7,939
09-02-2005 03:56
Clearly, you have no idea who you're talking to (or what you're talking about) so let's just leave it at that :)
blaze Spinnaker
1/2 Serious
Join date: 12 Aug 2004
Posts: 5,898
09-02-2005 04:00
Eggy, have you ever even taken a senior level algorithm prooving class?

Go talk to any PHD or Practical programmer and ask them

Would you prefer IPC or deterministic c style programming to get a job done?

Give me a break!

But.. yeah, who am I talking to? Someone who thinks

"Clearly, you have no idea who you're talking to (or what you're talking about) so let's just leave it at that"

Is meanginful in any way.

You're right .. I have no idea who I'm talking to. Neither do you. Neither do I care one iota. A genius can say something stupid, a moron can say something ingenius.

I take everything at face value. You kinda have to, in SecondLife.
_____________________
Taken from The last paragraph on pg. 16 of Cory Ondrejka's paper "Changing Realities: User Creation, Communication, and Innovation in Digital Worlds :

"User-created content takes the idea of leveraging player opinions a step further by allowing them to effectively prototype new ideas and features. Developers can then measure which new concepts most improve the products and incorporate them into the game in future patches."
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
09-02-2005 04:41
From: blaze Spinnaker
Eggy, have you ever even taken a senior level algorithm prooving class?

Go talk to any PHD or Practical programmer and ask them

Would you prefer IPC or deterministic c style programming to get a job done?

Give me a break!


Since you asked: in the third year of a Ph.D. in dynamically reconfigurable distributed systems, with a focus on source and binary compatibility with industrial C++. And have three years of experience in industrial coding and research. Veteran of the ACM ICPC world finals.

To tag in for Eggy: Took programming language semantics courses as both undergraduate and graduate levels. Prefer highly structured component-based programming with strict stateful interfaces. Where would you like said break?

Now back to productive: Have a string building example that I need to test a little, then will stick it in the Wiki (really speed rather than memory, so somewhat OT). I would have thought it to be fairly common, but I have not noticed anyone doing recursive list or string processing to save concat time. Basically:

CODE

list foo(list xs, integer beg, integer end) {
if (end - beg > THRESHOLD) {
integer mid = (beg + end) / 2;
return foo(xs, beg, mid) + foo(xs, mid + 1, end);
}
integer i;
list out;
for (i = beg; i < end; ++i) {
out += /* RESULT OF PROCESSING xs */
}
return out;
}
_____________________
Ignorance is fleeting, but stupidity is forever. Ego, similar.
blaze Spinnaker
1/2 Serious
Join date: 12 Aug 2004
Posts: 5,898
09-02-2005 04:47
(sigh)

You make me so angry because clearly you're smart. You're probably one of a very few around here who can get on my nerves.

And, quite frankly, I have no desire to alienate smart people. WE need them around here desperately. Everything you are trying to do (yeah, I"ve looked through your threads) I have tried to do as well at some point, but gave up for various reasons.

But, anyways. I think this is obviously something I'm not going to convince you of and will probably just frustrate me very deeply in trying.

If you want to discuss this further, let's open a new thread. This one was really just intended for memory optimization techniques. Not a discussion on IPC.

But if you are a PHD student, go look at your text book on alg prooving. Try proving something simple like getting all the items from a list using LSL versus something using non determictic IPC.

Which do you think would be easier to prove correctness?
_____________________
Taken from The last paragraph on pg. 16 of Cory Ondrejka's paper "Changing Realities: User Creation, Communication, and Innovation in Digital Worlds :

"User-created content takes the idea of leveraging player opinions a step further by allowing them to effectively prototype new ideas and features. Developers can then measure which new concepts most improve the products and incorporate them into the game in future patches."
blaze Spinnaker
1/2 Serious
Join date: 12 Aug 2004
Posts: 5,898
09-02-2005 04:55
CODE

list foo(list xs, integer beg, integer end) {
if (end - beg > THRESHOLD) {
integer mid = (beg + end) / 2;
return foo(xs, beg, mid) + foo(xs, mid + 1, end);
}
integer i;
list out;
for (i = beg; i < end; ++i) {
out += /* RESULT OF PROCESSING xs */
}
return out;
}


Memory is everything in SL. The stack that this would consume would be a nightmare.
_____________________
Taken from The last paragraph on pg. 16 of Cory Ondrejka's paper "Changing Realities: User Creation, Communication, and Innovation in Digital Worlds :

"User-created content takes the idea of leveraging player opinions a step further by allowing them to effectively prototype new ideas and features. Developers can then measure which new concepts most improve the products and incorporate them into the game in future patches."
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
09-02-2005 05:08
So far we've had three memory-relevent techniques: for-loop conversions, a quick note for our rookies about strings and lists and IPC. While I'm at work: How much space does each element in a list occupy? Is this space affected by the type of value therein? Made a quick check, and it looks like a rotations in a list takes up more space than integers, though they may just be a bug in my test. Should probably also see if vectors and rotations are stored as pointers (I assumed they were values).

Re the foo routine: Try it (I will later). Given a list of length N, it should consume something on the order of 40*log(N) bytes to reduce the runtime from O(N^2) from O(N log N).

<edit>And yes, having seen comments regarding you editing posts, and having seen it happen, you had better believe I will quote you asking for it. "I did not" my eyeballs.</edit>
_____________________
Ignorance is fleeting, but stupidity is forever. Ego, similar.
1 2