Difference between revisions of "User:Omei Qunhua"
Omei Qunhua (talk | contribs) (List storage requirements) |
Omei Qunhua (talk | contribs) |
||
(22 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
' | == Checking that a Notecard exists in object inventory == | ||
Results from my own tests in December 2012 | |||
Code such as the following is commonly use | |||
<lsl> | |||
string NotecardName = "config"; | |||
if (llGetInventoryType(NotecardName) != INVENTORY_NOTECARD) | |||
{ | |||
llOwnerSay("Missing notecard <" + NotecardName + ">"); | |||
etc. | |||
</lsl> | |||
However the following is more thorough, as also checks that the notecard is not a default "never-saved" nc, but won't work for a no-mod nc. | |||
<lsl> | |||
string NotecardName = "config"; | |||
if ( llGetInventoryType(NotecardName) == INVENTORY_NOTECARD) | |||
if ( llGetInventoryKey(NotecardName) ) | |||
{ | |||
.... start reading nc | |||
return; | |||
} | |||
llOwnerSay("Notecard <" + NotecardName + "> missing or not saved" ); | |||
... etc. | |||
</lsl> | |||
== Validating a String of Hexadecimal Characters == | |||
The following examples will verify that a string contains only characters from the ranges 0-9, A-F, and a-f | |||
a) Example for a string of known length - in this case 4 characters | |||
<lsl> | |||
StringOf4Hex(string test) | |||
{ | |||
return ( (integer) ("0x1" + test) >= 65536); | |||
} | |||
</lsl> | |||
b) for a string of length 1 to 7 | |||
<lsl> | |||
VarStringIsHex(string test) | |||
{ | |||
integer limit = (integer) llPow(16.0, (float) llStringLength(test) ); | |||
return ( (integer) ("0x1" + test) >= limit); | |||
} | |||
</lsl> | |||
Longer strings could be checked with a loop taking, say, 4 characters at a time. | |||
== Mono Code Size Measurements == | |||
'''Results from my own tests in December 2012''' | |||
1) Accessing a local integer variable | |||
'''Results ordered by size''' | |||
<pre> | <pre> | ||
Instruction ByteCode size | Instruction ByteCode size | ||
(x); 2 | |||
(~x); 3 | |||
x+x 4 | |||
x^y; 4 | |||
x=~x; 5 | |||
x=-x; 5 | |||
x==y; 5 | |||
++x; 6 | ++x; 6 | ||
x=x+x; 6 | |||
x=-~x; 6 equates to ++x | |||
x=~-x; 6 equates to --x | |||
x=x^x; 6 equates to x=0 | |||
x = !x; 7 | x = !x; 7 | ||
if (~x); 7 | if (~x); 7 if (x != -1) | ||
x++; 8 | x++; 8 | ||
x=1; 8 | x=0; 8 | ||
x=9; 8 | |||
x^1; 8 | |||
x!=y; 8 | |||
x=-~-~x; 8 equates to x+=2 | |||
x=-9; 9 Oh !! Does it load a +9 then negate it? | |||
x==1; 9 | |||
x+=1; 10 | x+=1; 10 | ||
x-=x; 10 | |||
x=x=x; 10 | |||
x=x*2; 10 | |||
x*=2; 10 | |||
if(!~x) 10 if (x == -1) | |||
x *= -1; 11 | x *= -1; 11 | ||
x<<1; 12 | x<<1; 12 | ||
x!=1; 12 | |||
if(x<0); 13 | if(x<0); 13 | ||
if(x==-1); 14 | if(x==-1); 14 | ||
x=x<<1; 14 | |||
</pre> | |||
2) Accessing a local integer variable | |||
'''Results grouped by functionality''' | |||
<pre> | |||
Instruction Size Assumed operations | |||
negate x:- | |||
x=-x; 5 (load x, negate, store) | |||
x*=-1; 11 | |||
zeroise x:- | |||
x=0; 8 | |||
x=x-x; 10 | |||
x-=x; 10 | |||
x=x^x; 6 (load x, xor with x, store) | |||
double x:- | |||
x=x*2; 10 | |||
x=x<<1; 14 | |||
x=x+x; 6 (load x, add x, store) | |||
x+=x; 6 | |||
increment x by 1 | |||
++x; 6 | |||
x++; 8 (because it has to preserve what it knows about x from before the increment) | |||
x=-~x; 6 (equates to ++x, not x++, so no size advantage) | |||
x+=1; 10 | |||
increment x by 2 | |||
x=-~-~x; 8 equates to x+=2 | |||
x+=2; 10 | |||
Test equality | |||
x==y; 5 | |||
x==1; 9 | |||
Test inequality | |||
x!=y; 8 | |||
x^y; 4 | |||
x!=1; 12 | |||
x^1; 8 | |||
</pre> | </pre> | ||
'''List storage Requirements in Mono''' | '''List storage Requirements in Mono''' | ||
These figures differed from those that had been shown on http://wiki.secondlife.com/wiki/LSL_Script_Memory. I've now updated that page to reflect these findings. | |||
Maybe Mono has been tightened up a bit. | |||
<pre> | |||
Integer 16 bytes each | |||
Float 16 bytes each | |||
String 18 each plus 2 bytes per character | |||
Key (valid keys) | |||
(stored as keys) 102 bytes (!!) per key | |||
Key (valid keys) | |||
(stored as strings) 90 bytes per key | |||
(key) "" 30 bytes | |||
Vector 24 bytes each | |||
Rotation 28 bytes each | |||
</pre> | |||
'''Getting the length of a local list (Mono)''' | |||
len = llGetListLength(MyList)--------44 bytes ... independent of length of list | |||
len = (MyList != [] )------------------14 bytes ... but 2.5 times slower than llGetListLength() | |||
'''Auto-casting of integers to floats (Mono)''' | |||
<pre> | <pre> | ||
llSetTimerEvent(0) is 3 bytes shorter than llSetTimerEvent(0.0) | |||
llSetText(message, <1, 1, 1>, 1) is 12 bytes shorter than llSetText(message, <1.0, 1.0, 1.0>, 1.0) | |||
</pre> | </pre> | ||
'''Adding single items to a list (Mono)''' | |||
For ByteCode space-saving, don't form the new item into a list itself before adding. | |||
example: | |||
<pre> | |||
list MyList; | |||
MyList += "a"; is 10 bytes shorter than MyList += ["a"]; | |||
MyList += 1; is 15 bytes shorter than MyList += [1]; | |||
15 byte savings also apply when adding floats, vectors and rotations. | |||
</pre> | |||
== Keeping an Efficient Visitor List etc. == | |||
Storing UUIDs in a list is frightfully inefficient as the figures above for holding keys in lists in Mono show, even if storing them as strings helps a bit (keys 102 byte per entry, strings 90 bytes per entry). So I decided to look at other ways of storing identifications of visitors to a SIM etc. One way would be to use uuid compression routines, as can be found in this Wiki. However I recently analysed over 1300 legacy avatar names (which, by design, have to be unique) and found that the average name was 11.5 character long (after stripping " Resident" off any such names). So, as strings require 18 bytes overhead plus 2 bytes per character as a list entry, each name on average would require 41 bytes of list space, enabling over twice as many avatars to be held in a list compared to holding UUIDs, with almost no scripting overhead. Of course, if you must have UUIDs this won't help! But my remit was purely to find the number of individuals who visited a SIM. I hit a stack-heap collision after 1350 names were stored. | |||
I've just developed a means of storing an avatar key losslessly in a quarternion, with help from work by [[User:Strife_Onizuka|Strife]] and [[User:Pedro_Oval|Pedro]]. So that gives the chance to hold keys accurately in a list at just 28 bytes per key. Watch this space! |
Latest revision as of 01:31, 13 May 2014
Checking that a Notecard exists in object inventory
Code such as the following is commonly use <lsl> string NotecardName = "config";
if (llGetInventoryType(NotecardName) != INVENTORY_NOTECARD) { llOwnerSay("Missing notecard <" + NotecardName + ">"); etc.
</lsl>
However the following is more thorough, as also checks that the notecard is not a default "never-saved" nc, but won't work for a no-mod nc. <lsl> string NotecardName = "config";
if ( llGetInventoryType(NotecardName) == INVENTORY_NOTECARD) if ( llGetInventoryKey(NotecardName) ) { .... start reading nc return; } llOwnerSay("Notecard <" + NotecardName + "> missing or not saved" ); ... etc.
</lsl>
Validating a String of Hexadecimal Characters
The following examples will verify that a string contains only characters from the ranges 0-9, A-F, and a-f
a) Example for a string of known length - in this case 4 characters
<lsl> StringOf4Hex(string test) {
return ( (integer) ("0x1" + test) >= 65536);
} </lsl>
b) for a string of length 1 to 7 <lsl> VarStringIsHex(string test) {
integer limit = (integer) llPow(16.0, (float) llStringLength(test) ); return ( (integer) ("0x1" + test) >= limit);
} </lsl>
Longer strings could be checked with a loop taking, say, 4 characters at a time.
Mono Code Size Measurements
Results from my own tests in December 2012
1) Accessing a local integer variable
Results ordered by size
Instruction ByteCode size (x); 2 (~x); 3 x+x 4 x^y; 4 x=~x; 5 x=-x; 5 x==y; 5 ++x; 6 x=x+x; 6 x=-~x; 6 equates to ++x x=~-x; 6 equates to --x x=x^x; 6 equates to x=0 x = !x; 7 if (~x); 7 if (x != -1) x++; 8 x=0; 8 x=9; 8 x^1; 8 x!=y; 8 x=-~-~x; 8 equates to x+=2 x=-9; 9 Oh !! Does it load a +9 then negate it? x==1; 9 x+=1; 10 x-=x; 10 x=x=x; 10 x=x*2; 10 x*=2; 10 if(!~x) 10 if (x == -1) x *= -1; 11 x<<1; 12 x!=1; 12 if(x<0); 13 if(x==-1); 14 x=x<<1; 14
2) Accessing a local integer variable
Results grouped by functionality
Instruction Size Assumed operations negate x:- x=-x; 5 (load x, negate, store) x*=-1; 11 zeroise x:- x=0; 8 x=x-x; 10 x-=x; 10 x=x^x; 6 (load x, xor with x, store) double x:- x=x*2; 10 x=x<<1; 14 x=x+x; 6 (load x, add x, store) x+=x; 6 increment x by 1 ++x; 6 x++; 8 (because it has to preserve what it knows about x from before the increment) x=-~x; 6 (equates to ++x, not x++, so no size advantage) x+=1; 10 increment x by 2 x=-~-~x; 8 equates to x+=2 x+=2; 10 Test equality x==y; 5 x==1; 9 Test inequality x!=y; 8 x^y; 4 x!=1; 12 x^1; 8
List storage Requirements in Mono
These figures differed from those that had been shown on http://wiki.secondlife.com/wiki/LSL_Script_Memory. I've now updated that page to reflect these findings.
Maybe Mono has been tightened up a bit.
Integer 16 bytes each Float 16 bytes each String 18 each plus 2 bytes per character Key (valid keys) (stored as keys) 102 bytes (!!) per key Key (valid keys) (stored as strings) 90 bytes per key (key) "" 30 bytes Vector 24 bytes each Rotation 28 bytes each
Getting the length of a local list (Mono)
len = llGetListLength(MyList)--------44 bytes ... independent of length of list
len = (MyList != [] )------------------14 bytes ... but 2.5 times slower than llGetListLength()
Auto-casting of integers to floats (Mono)
llSetTimerEvent(0) is 3 bytes shorter than llSetTimerEvent(0.0) llSetText(message, <1, 1, 1>, 1) is 12 bytes shorter than llSetText(message, <1.0, 1.0, 1.0>, 1.0)
Adding single items to a list (Mono)
For ByteCode space-saving, don't form the new item into a list itself before adding.
example:
list MyList; MyList += "a"; is 10 bytes shorter than MyList += ["a"]; MyList += 1; is 15 bytes shorter than MyList += [1]; 15 byte savings also apply when adding floats, vectors and rotations.
Keeping an Efficient Visitor List etc.
Storing UUIDs in a list is frightfully inefficient as the figures above for holding keys in lists in Mono show, even if storing them as strings helps a bit (keys 102 byte per entry, strings 90 bytes per entry). So I decided to look at other ways of storing identifications of visitors to a SIM etc. One way would be to use uuid compression routines, as can be found in this Wiki. However I recently analysed over 1300 legacy avatar names (which, by design, have to be unique) and found that the average name was 11.5 character long (after stripping " Resident" off any such names). So, as strings require 18 bytes overhead plus 2 bytes per character as a list entry, each name on average would require 41 bytes of list space, enabling over twice as many avatars to be held in a list compared to holding UUIDs, with almost no scripting overhead. Of course, if you must have UUIDs this won't help! But my remit was purely to find the number of individuals who visited a SIM. I hit a stack-heap collision after 1350 names were stored.
I've just developed a means of storing an avatar key losslessly in a quarternion, with help from work by Strife and Pedro. So that gives the chance to hold keys accurately in a list at just 28 bytes per key. Watch this space!