These forums are CLOSED. Please visit the new forums HERE
How to optimize code and when not to. |
|
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
02-19-2006 07:51
That doesn't explain how performing that assignment inside the function rather than before it actually saves anything.
|
Iron Perth
Registered User
Join date: 9 Mar 2005
Posts: 802
|
02-19-2006 12:32
I had been doing this for awhile, variable recycling, but I've stopped it in SL because of some very very painful bugs I created when I did it.
I've basically given up optimizing for memory (though, obviously, not for performance) and I work hard to develop message based architectures. One advantage to message based architectures is that I now have function pointers, and therefore a type of inheritance / interface / classes, etc. edit: I have a personal limit of 10K .. anything going over (data structures included) is in the 'red zone'. |
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
|
02-20-2006 00:05
... run ith through a white-space stripper ... it leads to LSL files with no comments ... But what I mostly wanted was to be able to get my scripts to run faster, and be smaller if possible.
|
Folco Boffin
Mad Moo Cow Cultist
![]() Join date: 27 Feb 2005
Posts: 66
|
02-20-2006 06:23
I may be wrong here - but I'm about 97.2% confident that stripping whitespace and comments is completely unneccesary in SL.
Hehe, I'm 99.9% sure comments don't add to the size of the compiled code and that the permissions system prevents others from seeing my code. But since LSL doesn't support /* ... */ style comments, I strip my comments since I've taken up using my multi-line comments again. And I can't get a whole lot simpler in my process anyway. I code in "ESL", hit the compile button and preseto, my esl file gets run through the C++ pre-processor (which is what actually strips my comments I've fount out), run through the white space stripper (which makes a lot less blank lines to go through improving readability a bit), giving me a LSL file that gets run through lslint to find out what mistakes I've made that won't compile in game. Oh and it copies the entire script to my clipboard automatically for me too. ![]() _____________________
^-^
Signed, Gorgarath, Whom in this game called Second Life, plays the avatar Folco Boffin, and in this game called First Life, plays the avatar John McDonnell. |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-20-2006 06:52
I wrote the stripper, because when you have #if blocks and such, you end up with huge amounts of whitespace (the C preprocessor, keeps the lines but not the data when it processes the file). You are unlikely to hit the code max in the editor (64k i think), but it's a pain to have to scroll past 20 or 30 white empty lines; wouldn't it make you wish you had some program that would strip them off?
As to readability, i don't strip comments when i use ESL (consequently i don't use C multi-line comments). What it does... it leaves a single whitespace, where there was 1 or 4+ lines of whitespace, and leaves two where there were 2 or 3 lines of whitespace, it really only collapses the most egregious abuses of whitespace. If you want obfuscation, replace all the spaces and carriage returns with "#" _____________________
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 |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
Better memory handling OR how to abuse pass by refrence
02-22-2006 03:17
Time for some pure evil.
If you think strings or lists are pass by refrence, you are wrong*. (* they are pass by refrence but when they are used (in an expression or as a paramater), they duplicate the list or string and push a refrence to that copy into the stack. Since the refrence doesn't point to the origional, it's best to consider it pass by value.) Your script needs to work with big strings and lists, but they are temporary and need to be fed though many functions that are going to convert them. CODE
So we don't need the value of "in" after the function is called but what if we don't have enough memory? When this function above is running it will in effect have to deal with three copies of "in" in memory by teh time it returns.
What if we could release on of them... lets look at the facts
What it means? After we have passed "in" as the first paramater, we can do anything we want to "in" even if we hadn't deleted the first char of "in". This is because the value is copied into the stack. So we set it to something smaller. This approch lets us parse 50% bigger stings. CODE
other ways of doing this... sure it's cheating but who cares ![]() a + b is in bytecode push b, push a, pop 2 whatever, add them, push result a() + b() is in bytecode call b() and the result is left in the stack, call a() and the result is left in the stack, pop 2 whatever, add them, push result (whatever is defined at compile time). and likewise if a or b is an expression. b is always evaluated first. all operators work this way, comma is not an operator. CODE
Lets kill two birds with no ston- variable. CODE
_____________________
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 |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-22-2006 13:27
If you haven't scoffed at any of these "optimizations" now is your chance.
How to save 1 byte CODE
_____________________
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 |
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
02-22-2006 17:15
If you haven't scoffed at any of these "optimizations" now is your chance. |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-24-2006 07:35
Also, I don't see how performing that assignment inside the function rather than before it actually saves anything. As i didn't really answer this question. LL's assignment operators for everything but storing values at time of declaration of a variable result in a copy. CODE
CODE
If you dont' supply a default value when you declair a variable, the compiler will. It's a senseless waste not to. When proforming the operation inside the function we are able to save a few bytes by not having to pop the value off the stack and then right back on. As to the order the paramaters are evaluated, LL would drastricly have to change how thier code operated to screw this up, i see no advantage they would gain by doing so. _____________________
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 |
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-24-2006 13:03
Strife -whats your take on:
a) to what length should we try to avoid using lists - I've heard people say they're quite memory hungry - but with the tradeoff they can be just what is required & their usage makes for readable code b) use of functions to make code readable - does this increase memory usage much, noting you may be passing lists into them (stack get used no?) c) performance impact on sim when using some of the alternative comms which may involve timers which short durations - i..e always checking/polling for updates d) if there is a script which is a bit laggy - will this affect all other scripts in the sim in the same fashion, or would it have more of an impact on script within the same prim, object or objects of the same owner? tks |
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
02-24-2006 14:10
When proforming the operation inside the function we are able to save a few bytes by not having to pop the value off the stack and then right back on. As to the order the paramaters are evaluated, LL would drastricly have to change how thier code operated to screw this up, i see no advantage they would gain by doing so. |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-24-2006 14:16
Strife -whats your take on: a) to what length should we try to avoid using lists - I've heard people say they're quite memory hungry - but with the trade off they can be just what is required & their usage makes for readable code b) use of functions to make code readable - does this increase memory usage much, noting you may be passing lists into them (stack get used no?) c) performance impact on sim when using some of the alternative comms which may involve timers which short durations - i..e always checking/polling for updates d) if there is a script which is a bit laggy - will this affect all other scripts in the sim in the same fashion, or would it have more of an impact on script within the same prim, object or objects of the same owner? tks a) Lists are very useful, and in many situations they are the best solution. In most situations the gain from using strings instead of lists is mitigated by the hassle. It depends how you are going to use the data. I only use strings when i have to. b) Say you have a block of code that you use in 4 places in your code, (same code, but in for places in your script), and that block calls 4 functions, by making the block a function you reduce the number of functions in bytecode from 16 to 8. Of course you need to be conscious as to what exactly that function is parsing. If it's a huge list or string, you may run out of memory because of the local copy (i talk about wiping one from memory a couple posts up in the thread). Your code will be a bit slower because of the function call. When optimizing you code, there is almost always a cost. c) I haven't done a full study on sim impact (that I remember). The last time i used llKey2Name for a transport was... 18 months ago. I cringe when i read some of my code written then. d) If you write a laggy script it will impact other scripts. The impact will be hard to notice (in most cases). No one rain drop thinks he/she is responsible for the flood. If your script manipulates physics or other prims etc, you may find that the lag will be noticeable. As to how the script scheduler works exactly i do not know. Maybe some of the other scripters will chime in. _____________________
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 |
Tsuno Soyinka
Registered User
Join date: 28 Oct 2005
Posts: 15
|
02-25-2006 11:35
Well, okay, I guess it's not all: I'm also saying that you'll probably save yourself a lot of time and energy just breaking a script up into multiple scripts that fit comfortably within the script buffer. Your code will be more readable, and you won't get bitten two months down the road because a certain execution path happened to make your code keep too much data around at once and overrun the stack. I'm not saying that it's impossible to tell when something like that will happen (although often it can be difficult to see!), but I am saying that you can very often save a lot of time by just using multiple intercommunicating scripts, and your code will probably make a lot more sense, too. . would you be willing to give lessons on load balancing? how much of the processing do I put in each script? |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-27-2006 12:42
1. Unless I really need those bytes, I suspect I'll be much better off with more readable code. And more readable code makes it easier to understand and find higher level optimizations. 2. All they'd have to do is implement compile time expressions and a peephole optimiser, and order of evaluation goes out of the window unless they explicitly insert sequence points within expressions... and every sequence point reduces the effectiveness of the optimiser. 1. All depends where you are in the development process. And your right, you should look for the big ones first. 2. And thats why we have parentheses. Your compilers trash if it ignores parentheses. Your compiler is trash is it comes up with unpredictable results. Users don't like unpredictable results. The exception is floating point operations which if you have a good compiler will let you configure how predictable the results will be. _____________________
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 |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-27-2006 12:49
This just hit me while trying to cut a few more bytes out of a 14k script (thats 14k of bytecode, and this script is already pretty tight).
Instead of useing ZERO_VECTOR or ZERO_ROTATION or even a global variable storing them. Use ((rotation)"" ![]() and ((vector)"" ![]() they each cost 4 bytes ![]() Which is less then it takes to push a value into the stack. ![]() This is the point that using ESL rocks. Simple way to shave a few bytes. CODE
_____________________
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 |
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
02-27-2006 15:34
2. And thats why we have parentheses. Your compilers trash if it ignores parentheses. Parentheses effect order of evaluation, in the mathematical sense. There's no reason they need to effect order of execution. For example, changing the order of execution of function arguments can save re-pushing intermediate values. Or: a + b(y) + c(x) + b(a). This can be implemented, with the same order-of-evaluation results, as: push a push y call b push x call c push a call b add add add Or: push a dup call b push y call b push x call c add add add These are mathematically identical, they have the same "order of evaluation" in the mathematical sense, but if a dup is cheaper than a push the second one is faster. Now... what happens if b has side-effects? Compilers do even stranger things than this. |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
02-28-2006 16:32
you're confusing order of evaluation with order of execution. Parentheses effect order of evaluation, in the mathematical sense. There's no reason they need to effect order of execution. For example, changing the order of execution of function arguments can save re-pushing intermediate values. Or: a + b(y) + c(x) + b(a). This can be implemented, with the same order-of-evaluation results, as: push a push y call b push x call c push a call b add add add Or: push a dup call b push y call b push x call c add add add These are mathematically identical, they have the same "order of evaluation" in the mathematical sense, but if a dup is cheaper than a push the second one is faster. Now... what happens if b has side-effects? Compilers do even stranger things than this. 1. LSL currently does not support a dup bytecode. Though i'm sure CLI does (is that the right acronym? i can never remember) 2. I totaly agree, a + b(y) + c(x) + b(a) is ambiguous with reguards to order of operation, but (((a + b(y)) + c(x)) + b(a)) isn't. If the compiler does the above optimization for my example i'd be annoyed. 3. LSL would evaluate a + b(y) + c(x) + b(a) like...(see below); it would not nessesarily result in the same answer as your code. LSL evaluates equations right to left, not left to right. For LL to change this would require changing the yacc file; resulting in horrible ongoing drama when scripts were recompiled (this script worked just fine before i recompiled it). push a call b push x call c add push y call b add push a add _____________________
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 |
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
03-01-2006 06:11
I totaly agree, a + b(y) + c(x) + b(a) is ambiguous with reguards to order of operation, but (((a + b(y)) + c(x)) + b(a)) isn't. If the compiler does the above optimization for my example i'd be annoyed. (a+b)*c means "multiply the result of adding a to b by c". It doesn't mean "execute this operation, execute that operation". What you're talking about is called a "sequence point". The C programming language is a fairly typical language where this kind of thing is concerned, and it defines semicolons and block boundaries are sequence points. Making every operation a sequence point would severly limit the possible optimizations. Consider (a++ + a++ + a++). A naive translation of this requires 5 adds, three fetches, three stores, three pushes. In C this can legally be evaluated as: push a push 3 mul push a push 3 add store a Unless Linden Labs has explicitly stated that parentheses are sequence points in LSL, I'm not going to write code that depends on any stronger order of evaluation than C. LSL would evaluate a + b(y) + c(x) + b(a) like...(see below); it would not nessesarily result in the same answer as your code. LSL evaluates equations right to left, not left to right. For LL to change this would require changing the yacc file; resulting in horrible ongoing drama when scripts were recompiled (this script worked just fine before i recompiled it). |
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
03-01-2006 11:42
There are very few programming languages in which parentheses do more than control the order of evaluation in the mathematical sense. (a+b)*c means "multiply the result of adding a to b by c". It doesn't mean "execute this operation, execute that operation". What you're talking about is called a "sequence point". The C programming language is a fairly typical language where this kind of thing is concerned, and it defines semicolons and block boundaries are sequence points. Making every operation a sequence point would severly limit the possible optimizations. I've been writing code using yacc since 1979, and the exact same grammar can produce all three of the code examples we're talking about, depending on how the code generator works. When they go to mono they'll have a new code generator, as well as gain the ability to use 3rd party tools to optimise their code. Also, there's likely to be some script breakage at that point and scripts that will have to continue to be run using the old interpreter... so the impact of one more change would be mitigated. My hat is off for you; 27 years of experience. I've spent the last 10 min doing some catching up reading (and the last hour revising my responce); my formal education in language & compile design, is non existant. As two people who understand yacc & lex (ok so maybe yours is alot better then mine), we can both see that who ever wrote the LSL lex knew less then us (as is can be seen with how floats are read). LL has stated, when confronted with some simple optimizations, that they don't plan on changing the language till after Mono. Until Mono, everything is up in the air. We are tetering on the devide between LSL moving from a scripting language to a programing language. The way LSL is writen right now, it would probably be a simple excersize for yourself to rewrite the lex & modify yacc file to read the LSL bytecode and output LSL text. With the only loss being function, variable & state names (and not being able to tell the difference between ++a, a+=1 and a = a + 1, etc). I would find the task difficult but not impossible (i'm not to keen on doing it, being a quick study doesn't compair to experience). I'm sure you will agree, when optimizing code writen in a scripting language doing so is very hackish. But with a programing language user level optimization is about how data is structured and organized. I think we should start talking about how LSL3 should be designed (in a new thread). _____________________
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 |
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
03-01-2006 13:24
New thread it is...
(though I don't see why the hell they can't handle compile-time evaluation of constant expressions... the negative number parsing glitch that makes expressions like "a-1" illegal is clearly a hack to try and work around it) |
Lindsey Dassin
Fallen Angel
Join date: 14 Sep 2005
Posts: 33
|
03-01-2006 14:17
Twenty-seven years... nearly as long as i've been alive... i knew there had to be something behind that simple and elegant light switch code.
![]() My experience with flex/lex is that it's really only a tokenizer, meant to take complex input patterns and tranlate them into simpler ones for bison/yacc. Its job is to tell bison/yacc, "okay, this glob of bytes is the reserved word 'float', and the next glob of of bytes is a string 'foo', and the next glob of bytes is an integer 65536, ..." Flex/lex is awesome for its regular expressions, but will it even do binary data? Argent? _____________________
:wq
|
Zepp Zaftig
Unregistered Abuser
Join date: 20 Mar 2005
Posts: 470
|
03-01-2006 14:38
What would be the point in developing LSL3 rather than just using any of the many languages that work with Mono?
|
Strife Onizuka
Moonchild
![]() Join date: 3 Mar 2004
Posts: 5,887
|
03-01-2006 17:46
What would be the point in developing LSL3 rather than just using any of the many languages that work with Mono? Good point, i have no plan on using LSL once I can use C. (though I don't see why the hell they can't handle compile-time evaluation of constant expressions... the negative number parsing glitch that makes expressions like "a-1" illegal is clearly a hack to try and work around it) ^_^ I suspect who ever wrote LSL didn't take anything past the 101 level compiler design course. BTW i handn't heard of sequence points before you pointed them out (at which point i looked them up in the ISO C standard). _____________________
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 |
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
|
03-03-2006 03:35
What would be the point in developing LSL3 rather than just using any of the many languages that work with Mono? IMO, LSL.MONO (or whatever) is a neccesary bridge before LL develop and release a MONO API. |
Argent Stonecutter
Emergency Mustelid
![]() Join date: 20 Sep 2005
Posts: 20,263
|
03-03-2006 06:55
Flex/lex is awesome for its regular expressions, but will it even do binary data? Argent? |