I got a bit fed up with people randomly linking to the performance page from Twitter and sniggering about whitespace changing execution speed.
I came up with this - thought you might like it:
Why not compile to native/bytecode?
Memory is scarce on microcontrollers, and we want the source code on the device itself so we can edit and debug it without external tools.
There isn't enough room on the microcontroller for source code and compiled code, but luckily source code is surprisingly memory-efficient.
For instance take this code that draws a Mandelbrot fractal:
var x,y,line;
for (y=0;y<32;y++) {
line="";
for (x=0;x<32;x++) {
var Xr = 0;
var Xi = 0;
var i = 0;
var Cr=(4*x/32)-2;
var Ci=(4*y/32)-2;
while ((i<8) & ((Xr*Xr+Xi*Xi)<4)) {
var t=Xr*Xr - Xi*Xi + Cr;
Xi=2*Xr*Xi+Ci;
Xr=t;
i=i+1;
}
line += " *"[i&1];
}
print(line);
}
It's 301 bytes long.
When compiled with SpiderMonkey, the following bytecode is created (obtained by running a debug build and dbg(function() { .... }):
loc op
----- --
main:
00000: getlocal 0
00003: pop
00004: getlocal 1
00007: pop
00008: getlocal 2
00011: pop
00012: zero
...
00256: loopentry 1
00258: getlocal 1
00261: int8 32
00263: lt
00264: ifne 22 (-242)
00269: stop
It's 270 bytes long. So you've saved 31 bytes over the original code, but now your code is totally uneditable and unreadable.
If you compiled this into native code with the Espruino Compiler, the size of the binary would be 1136 bytes.
But what if you rewrote it in C and compiled it in GCC with size optimisation turned on. That'll be efficient, right?
void main() {
int x,y;
char line[33];
line[32] = 0;
for (y=0;y<32;y++) {
for (x=0;x<32;x++) {
double Xr = 0;
double Xi = 0;
int i = 0;
double Cr=(4*x/32.0)-2;
double Ci=(4*y/32.0)-2;
while ((i<8) & ((Xr*Xr+Xi*Xi)<4)) {
double t=Xr*Xr - Xi*Xi + Cr;
Xi=2*Xr*Xi+Ci;
Xr=t;
i=i+1;
}
line[x] = (char)((i&1)?'*':' ');
}
puts(line);
}
}
However, if you minified your code with the closure compiler you'd get:
var a,b,c;for(b=0;32>b;b++){c="";for(a=0;32>a;a++){for(var
d=0,e=0,f=0,g=4*a/32-2,h=4*b/32-2;8>f&4>d*d+e*e;)var k=d*d
-e*e+g,e=2*d*e+h,d=k,f=f+1;c+=" *"[f&1]}print(c)};
It's editable, just about readable, and it's only 167 bytes - so it is smaller than bytecode and even highly optimised native code!
Type
Size (bytes)
Original JS Code
301
Spidermonkey bytecode
270
Espruino Compiled JS
1136
GCC Compiled C code (-Os)
290
Minified JS
167
So by executing from source, we use around the same amount of memory as we would if we compiled or used bytecode, while still having everything we need to edit and debug the code on-chip.
However, if you need to make things smaller, you can minify the JavaScript functions you don't need to edit, which will use less RAM than even size-optimised C code!
Espruino is a JavaScript interpreter for low-power Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.
I got a bit fed up with people randomly linking to the performance page from Twitter and sniggering about whitespace changing execution speed.
I came up with this - thought you might like it:
Why not compile to native/bytecode?
Memory is scarce on microcontrollers, and we want the source code on the device itself so we can edit and debug it without external tools.
There isn't enough room on the microcontroller for source code and compiled code, but luckily source code is surprisingly memory-efficient.
For instance take this code that draws a Mandelbrot fractal:
It's 301 bytes long.
When compiled with SpiderMonkey, the following bytecode is created (obtained by running a debug build and
dbg(function() { .... })
:It's 270 bytes long. So you've saved 31 bytes over the original code, but now your code is totally uneditable and unreadable.
If you compiled this into native code with the Espruino Compiler, the size of the binary would be 1136 bytes.
But what if you rewrote it in C and compiled it in GCC with size optimisation turned on. That'll be efficient, right?
Nope. 290 bytes.
However, if you minified your code with the closure compiler you'd get:
It's editable, just about readable, and it's only 167 bytes - so it is smaller than bytecode and even highly optimised native code!
-Os
)So by executing from source, we use around the same amount of memory as we would if we compiled or used bytecode, while still having everything we need to edit and debug the code on-chip.
However, if you need to make things smaller, you can minify the JavaScript functions you don't need to edit, which will use less RAM than even size-optimised C code!