Difference between revisions of "User:Pedro Oval/Mono code memory usage"

From Second Life Wiki
Jump to navigation Jump to search
(More surprising results)
(Fix savings for ZERO_VECTOR (thanks to Omei for catching) and add ZERO_ROTATION)
 
(15 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Here are some memory usage results I've obtained with Mono, for common language constructs. They were obtained by replicating each line to test 512 times and looking at [[llGetFreeMemory]] right at the beginning of the script.
Here are some memory usage results I've obtained with Mono, for common language constructs. They were obtained by replicating each line to test 512 times and looking at [[llGetFreeMemory]] right at the beginning of the script.


Results for local integer variables x, y, and local float variables f, g:
Most findings are supported by a [[User:Pedro Oval/Mono code memory usage/CIL|compilation into CIL code]]. Some of them, however, are puzzling.
 
Includes tips on memory reduction, with the corresponding savings. In some cases, "same bytes as (something)" is indicated, which means that the constructs are equivalent but offer no savings.
 
Notation below is that x, y are local integer variables; f, g are local float variables, v is a local vector variable, a is a list


{| {{Prettytable}}
{| {{Prettytable}}
Line 7: Line 11:
!Construct !! Bytes used !! Comments
!Construct !! Bytes used !! Comments
|-
|-
| ;      || 0  ||
| ;      || 0  || Empty statement, e.g. ;;;;;; takes same mem as ;
|-
|-
| {}    || 0  ||
| {}    || 0  || Empty statement e.g. {{{{{}}}}} takes same mem as {}
|-
|-
| return || 1  || Tested in event and without arguments
| return || 1  || Tested in event and without arguments
|-
|-
| x      || 2 ||
| x=0    || 8-9 || 8 bytes if x is one of the first four local variables; 9 if not (see [[User:Pedro Oval/Mono code memory usage/CIL#Important notes:|notes on CIL]] for an explanation)
|-
| x      || 2-3 || 2 bytes if x is one of the first four local variables; 3 if not (see [[User:Pedro Oval/Mono code memory usage/CIL#Important notes:|notes on CIL]] for an explanation)
|-
|-
| (x)    || 2  ||
| x=y    || 4-6 || Assignment. 4 bytes if both x and y are among the first four local variables; 6 if neither is; 5 otherwise.
|-
| (x)    || 2  || Same as above, but we won't be adding that at every appearance. We just use the shortest on this table.
|-
|-
| (integer)x || 2  ||
| (integer)x || 2  ||
Line 23: Line 31:
| f      || 2  ||
| f      || 2  ||
|-
|-
| (float)f || 2 ||
| (float)f || 2 ||
|-
|-
| (integer)f || 7 ||
| (integer)f || 7 ||
|-
| v      || 2  ||
|-
| v.z    || 8  || Vector component
|-
|-
| -x    || 3  ||
| -x    || 3  ||
|-
|-
| ~x    || 3  || Bitwise, equivalent to -x-1 which allows it to be used for some hacks
| ~x    || 3  || Bitwise, equivalent to -x-1 which allows it to be used for some hacks. Not applicable to floats though.
|-
|-
| !x    || 5  || Logical
| !x    || 5  || Logical
|-
|-
| --x    || 6  || Pre-decrement (same bytes as x=~-x)
| --x    || 6  || Pre-decrement. Same bytes as x=~-x
|-
|-
| ++x    || 6  || Pre-increment (same bytes as x=-~x)
| ++x    || 6  || Pre-increment. Same bytes as x=-~x
|-
|-
| x--    || 8  || Post-decrement
| x--    || 8  || Post-decrement. Same bytes as -~(x=~-x)
|-
|-
| x++    || 8  || Post-increment
| x++    || 8  || Post-increment. Same bytes as ~-(x=-~x)
|-
| x=y    || 4  || Assignment
|-
|-
| x==y  || 5  || Comparison
| x==y  || 5  || Comparison
Line 47: Line 57:
| x=y=z  || 6  || (for local integer z) Chained assignment
| x=y=z  || 6  || (for local integer z) Chained assignment
|-
|-
| f=x    || 5  || Implicit conversion from integer to float
| f=x    || 5  || Implicit cast from integer to float
|-
|-
| f=(float)x || 5  || Explicit conversion from integer to float
| f=(float)x || 5  || Explicit cast from integer to float
|-
|-
| x!=y  || 8  || Same bytes as !(x==y)
| x!=y  || 8  || Same bytes as !(x==y) (implemented that way). Can sometimes be replaced by x^y, saving 4 bytes.
|-
| x*y   || 4 ||
|-
| x/y    || 8  ||
|-
| x%y    || 8  || Modulo
|-
|-
| x+y    || 4  ||
| x+y    || 4  ||
|-
|-
| x-y    || 8  || !?!?
| x-y    || 8  || <nowiki>!?!?</nowiki> (uses a function call in CIL)
|-
|-
| x+-y  || 5  || Saves 3 bytes vs. a subtraction!
| x+-y  || 5  || Saves 3 bytes vs. a subtraction!
|-
|-
| x*y    || 4  ||
| x*y    || 4  || Can sometimes be used instead of x << bits, saving 4 bytes.
|-
|-
| x/y    || 8  ||
| x/y    || 8  ||
|-
| x%y    || 8  || Modulo
|-
|-
| x&y    || 4  || Bitwise
| x&y    || 4  || Bitwise
|-
|-
| x&&y  || 13 || Logical
| x&&y  || 13 || Logical. Same bytes as !(!x<nowiki>|</nowiki>!y) (implemented that way)
|-
|-
| x<nowiki>|</nowiki>y    || 4  || Bitwise
| x<nowiki>|</nowiki>y    || 4  || Bitwise
|-
|-
| x<nowiki>||</nowiki>y  || 10 || Logical
| x<nowiki>||</nowiki>y  || 10 || Logical. Same bytes as !!(x<nowiki>|</nowiki>y) (implemented that way)
|-
|-
| x^y    || 4  || Bitwise
| x^y    || 4  || Bitwise. Can sometimes be used instead of x!=y (if careful), saving 4 bytes.
|-
|-
| x<<y  || 8  || Bitwise shift left (can be simulated with mult in most cases)
| x<<y  || 8  || Bitwise shift left. Can be replaced with a multiplication in some cases, saving 4 bytes.
|-
|-
| x>>y  || 8  || Bitwise shift right
| x>>y  || 8  || Bitwise shift right (division doesn't help here though)
|-
|-
| x<y    || 5  ||
| x<y    || 5  ||
Line 87: Line 93:
| x>y    || 5  ||
| x>y    || 5  ||
|-
|-
| x<=y  || 8  || Same bytes as !(x>y)
| x<=y  || 8  || Same bytes as !(x>y) (implemented that way)
|-
|-
| x>=y  || 8  || Same bytes as !(x<y)
| x>=y  || 8  || Same bytes as !(x<y) (implemented that way)
|-
|-
| x+=y  || 6  || Same bytes as x=x+y
| x+=y  || 6  || Same bytes as x=x+y
Line 116: Line 122:
|-
|-
| 0xffffffff || 6  || Equivalent to -1.
| 0xffffffff || 6  || Equivalent to -1.
|-
| (integer)-1 || 6  || Saves 1 byte.
|-
| (integer)(-1) || 7  || The extra parentheses break the magic.
|-
| ALL_SIDES || 6  || Value is -1. Constants with negative values don't take memory for the sign.
|-
|-
| x<nowiki>|</nowiki>~x || 5  || Equivalent to -1. Saves 1 byte vs 0xffffffff, 2 bytes vs -1.
| x<nowiki>|</nowiki>~x || 5  || Equivalent to -1. Saves 1 byte vs 0xffffffff, 2 bytes vs -1.
Line 129: Line 141:
| ~-x    || 4  || Same as x-1, saves 8 bytes
| ~-x    || 4  || Same as x-1, saves 8 bytes
|-
|-
| x*y+y-1 || 16 || This kind of construct is sometimes used to access last element of strided lists
| x*y+y-1 || 16 || This kind of construct is sometimes used to access last element of strided lists
|-
|-
| (x+1)*y-1 || 20 || Equivalent to the above, just worse
| (x+1)*y-1 || 20 || Equivalent to the above, just worse
|-
|-
| ~(~x*y) || 6   || Equivalent to the above, saves 10 bytes
| ~(~x*y) || 6 || Equivalent to the above, saves 10 bytes
|-
|-
| while(x); || 37 ||
| while(x); || 37 || That byte count is not supported by CIL. Puzzling. It seems that backward jumps take more than forward. According to CIL it should take 11 bytes.
|-
|-
| do ; while(x); || 41 || Unexpected but true
| do ; while(x); || 41 || Unexpected but true. According to CIL it should take 6 bytes.
|-
|-
| for(;x;); || 37 || For loops seem to be plainly rewritten as while loops
| for(;x;); || 37 || For loops seem to be plainly rewritten as while loops.
|-
|-
| @label; if(x) jump label; || 37  || Equivalent to a do...while loop, saves 4 bytes.
| @label; if(x) jump label; || 37  || Equivalent to a do...while loop, saving 4 bytes. It takes as many as a while according to CIL.
|-
| 0.0    || 10 || Float constants use a lot of memory (they use double-precision reals in Mono).
|-
| -2.2  || 11 || Sign takes 1 extra byte
|-
| (float)-2.2 || 10 || Casting negative float to float saves 1 byte
|-
| f=0.0  || 12 ||
|-
| f=0    || 9  || In general, using integer constants with implicit conversion to float instead of float constants saves 3 bytes every time. Another example follows.
|-
| <0.0, 0.0, 0.0> || 33 || Same as ZERO_VECTOR
|-
| ZERO_VECTOR || 33 ||
|-
| <0, 0, 0> || 24 || Saves 3 bytes per constant, total 9 bytes vs. ZERO_VECTOR
|-
| TOUCH_INVALID_TEXCOORD || 33 ||
|-
| <-1.0, -1.0, 0.0> || 35 || (because of the signs). Equivalent to TOUCH_INVALID_TEXCOORD.
|-
| <(float)-1.0, (float)-1.0, 0.0> || 33 || Equivalent to TOUCH_INVALID_TEXCOORD.
|-
| <-1, -1, 0> || 26 || (because of the signs)
|-
| <0xffffffff, 0xffffffff, 0> || 24 || (no signs but ugly)
|-
| <(integer)-1, (integer)-1, 0> || 24 || (saves the sign bytes, not so ugly)
|-
| <ZERO_ROTATION> || 42 ||
|-
| <0, 0, 0, 1> || 30 || Saves 3 bytes per constant, total 12 bytes vs. ZERO_ROTATION
|-
| v+v  || 8  || Vector addition (with the vectors as local variables)
|-
| v-v  || 8  || Vector subtraction
|-
| v*v  || 8  || Vector dot product
|-
| v%v  || 8  || Vector cross product
|-
| []    || 6  || Empty list
|-
| a=[]  || 8  || Assignment of empty list
|-
| a+[x] || 23 || Append an element to a list, with brackets
|-
| a+x  || 8  || Append an element to a list, without brackets
|-
| [x]+a || 23 || Prepend an element to a list, with brackets
|-
| x+a  || 13 || Prepend an element to a list, without brackets
|-
| [x]  || 17 || List with an integer
|-
| []+x  || 12 || Empty list plus an integer element appended, saves 5 bytes with respect to [x]
|-
| (list)x || 12 || Same bytes as []+x
|-
| [x,y] || 28 || List with two integers (the type of variable doesn't seem to affect the result)
|-
| []+x+y || 18 || Empty list with two integer elements appended, saves 10 bytes with respect to [x,y] (the type of variable doesn't seem to affect the result)
|-
| (string)a || 7  || Typecasting a list to a string
|}
|}
=== See also ===
* [[User:Omei Qunhua]]
* [[User talk:Omei Qunhua]]

Latest revision as of 02:11, 21 July 2014

Here are some memory usage results I've obtained with Mono, for common language constructs. They were obtained by replicating each line to test 512 times and looking at llGetFreeMemory right at the beginning of the script.

Most findings are supported by a compilation into CIL code. Some of them, however, are puzzling.

Includes tips on memory reduction, with the corresponding savings. In some cases, "same bytes as (something)" is indicated, which means that the constructs are equivalent but offer no savings.

Notation below is that x, y are local integer variables; f, g are local float variables, v is a local vector variable, a is a list

Construct Bytes used Comments
; 0 Empty statement, e.g. ;;;;;; takes same mem as ;
{} 0 Empty statement e.g. {{{{{}}}}} takes same mem as {}
return 1 Tested in event and without arguments
x=0 8-9 8 bytes if x is one of the first four local variables; 9 if not (see notes on CIL for an explanation)
x 2-3 2 bytes if x is one of the first four local variables; 3 if not (see notes on CIL for an explanation)
x=y 4-6 Assignment. 4 bytes if both x and y are among the first four local variables; 6 if neither is; 5 otherwise.
(x) 2 Same as above, but we won't be adding that at every appearance. We just use the shortest on this table.
(integer)x 2
(float)x 3
f 2
(float)f 2
(integer)f 7
v 2
v.z 8 Vector component
-x 3
~x 3 Bitwise, equivalent to -x-1 which allows it to be used for some hacks. Not applicable to floats though.
!x 5 Logical
--x 6 Pre-decrement. Same bytes as x=~-x
++x 6 Pre-increment. Same bytes as x=-~x
x-- 8 Post-decrement. Same bytes as -~(x=~-x)
x++ 8 Post-increment. Same bytes as ~-(x=-~x)
x==y 5 Comparison
x=y=z 6 (for local integer z) Chained assignment
f=x 5 Implicit cast from integer to float
f=(float)x 5 Explicit cast from integer to float
x!=y 8 Same bytes as !(x==y) (implemented that way). Can sometimes be replaced by x^y, saving 4 bytes.
x+y 4
x-y 8 !?!? (uses a function call in CIL)
x+-y 5 Saves 3 bytes vs. a subtraction!
x*y 4 Can sometimes be used instead of x << bits, saving 4 bytes.
x/y 8
x%y 8 Modulo
x&y 4 Bitwise
x&&y 13 Logical. Same bytes as !(!x|!y) (implemented that way)
x|y 4 Bitwise
x||y 10 Logical. Same bytes as !!(x|y) (implemented that way)
x^y 4 Bitwise. Can sometimes be used instead of x!=y (if careful), saving 4 bytes.
x<<y 8 Bitwise shift left. Can be replaced with a multiplication in some cases, saving 4 bytes.
x>>y 8 Bitwise shift right (division doesn't help here though)
x<y 5
x>y 5
x<=y 8 Same bytes as !(x>y) (implemented that way)
x>=y 8 Same bytes as !(x<y) (implemented that way)
x+=y 6 Same bytes as x=x+y
x-=y 10 Same bytes as x=x-y
x+=-y 7 Saves 3 bytes vs x-=y
x*=y 6 Same as x=x*y
x/=y 10 Same as x=x/y
x%=y 10 Same as x=x%y
if(x); 6
if(x); else; 11
0 6
x^x 4 It gives always 0, saving 2 bytes. (Thanks to User:Omei Qunhua for the discovery)
1 6
-1 7 Sign takes code memory.
0xffffffff 6 Equivalent to -1.
(integer)-1 6 Saves 1 byte.
(integer)(-1) 7 The extra parentheses break the magic.
ALL_SIDES 6 Value is -1. Constants with negative values don't take memory for the sign.
x|~x 5 Equivalent to -1. Saves 1 byte vs 0xffffffff, 2 bytes vs -1.
x+1 8
-~x 4 Same as x+1, saves 4 bytes
x-1 12 What's wrong with subtraction?
x+-1 9 Same as x-1, saves 3 bytes
~-x 4 Same as x-1, saves 8 bytes
x*y+y-1 16 This kind of construct is sometimes used to access last element of strided lists
(x+1)*y-1 20 Equivalent to the above, just worse
~(~x*y) 6 Equivalent to the above, saves 10 bytes
while(x); 37 That byte count is not supported by CIL. Puzzling. It seems that backward jumps take more than forward. According to CIL it should take 11 bytes.
do ; while(x); 41 Unexpected but true. According to CIL it should take 6 bytes.
for(;x;); 37 For loops seem to be plainly rewritten as while loops.
@label; if(x) jump label; 37 Equivalent to a do...while loop, saving 4 bytes. It takes as many as a while according to CIL.
0.0 10 Float constants use a lot of memory (they use double-precision reals in Mono).
-2.2 11 Sign takes 1 extra byte
(float)-2.2 10 Casting negative float to float saves 1 byte
f=0.0 12
f=0 9 In general, using integer constants with implicit conversion to float instead of float constants saves 3 bytes every time. Another example follows.
<0.0, 0.0, 0.0> 33 Same as ZERO_VECTOR
ZERO_VECTOR 33
<0, 0, 0> 24 Saves 3 bytes per constant, total 9 bytes vs. ZERO_VECTOR
TOUCH_INVALID_TEXCOORD 33
<-1.0, -1.0, 0.0> 35 (because of the signs). Equivalent to TOUCH_INVALID_TEXCOORD.
<(float)-1.0, (float)-1.0, 0.0> 33 Equivalent to TOUCH_INVALID_TEXCOORD.
<-1, -1, 0> 26 (because of the signs)
<0xffffffff, 0xffffffff, 0> 24 (no signs but ugly)
<(integer)-1, (integer)-1, 0> 24 (saves the sign bytes, not so ugly)
<ZERO_ROTATION> 42
<0, 0, 0, 1> 30 Saves 3 bytes per constant, total 12 bytes vs. ZERO_ROTATION
v+v 8 Vector addition (with the vectors as local variables)
v-v 8 Vector subtraction
v*v 8 Vector dot product
v%v 8 Vector cross product
[] 6 Empty list
a=[] 8 Assignment of empty list
a+[x] 23 Append an element to a list, with brackets
a+x 8 Append an element to a list, without brackets
[x]+a 23 Prepend an element to a list, with brackets
x+a 13 Prepend an element to a list, without brackets
[x] 17 List with an integer
[]+x 12 Empty list plus an integer element appended, saves 5 bytes with respect to [x]
(list)x 12 Same bytes as []+x
[x,y] 28 List with two integers (the type of variable doesn't seem to affect the result)
[]+x+y 18 Empty list with two integer elements appended, saves 10 bytes with respect to [x,y] (the type of variable doesn't seem to affect the result)
(string)a 7 Typecasting a list to a string


See also