Espruino Performance Notes
Toggle navigation
Espruino
Get Espruino
Espruino Shop
Distributors
Download firmware
Donate
Documentation
Quick Start
API Reference
Tutorials & Examples
Modules
Tips & Tricks
Videos
Bangle.js 2
Bangle.js 1
Pixl.js
Puck.js
Jolt.js
Espruino WiFi
Espruino Pico
Original Espruino
MDBT42Q Module
Other Boards
Support
Forums
Getting Started
FAQ
Troubleshooting
Bangle.js App Loader
Espruino.js App Loader
Espruino for Business
Contact Us
Press Info
Espruino Performance Notes
Please see Internals for a more technical description of the interpreter's implementation.
Espruino is designed to run on devices with very small amounts of RAM available (under 8kB) while still keeping a copy of the source code so you can debug and edit on the device. As such, it makes some compromises that affect the performance in ways you may not expect.
Is it too slow for you?
Check out some easy Code Style changes to make your code run better.
JavaScript on Embedded devices will never be as efficient as compiled code, so we've made it easy for you to add extremely fast code where it is needed:
Add "ram" to the top of your function to tell Espruino to keep it in RAM and pretokenise it.
Add "jit" to the top of your function to tell Espruino to JIT compile it on the device (2v16 firmware and later)
Use the Web IDE to compile JavaScript into optimised Thumb Code using an Online service
Create functions with Inline C or Inline Assembler
Recompile the Espruino firmware with your own C code
ESPRUINO EXECUTES CODE DIRECTLY FROM SOURCE
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;<br>for (y=0;yIt's 301 bytes long.
When compiled with SpiderMonkey, the following bytecode is created (obtained by running a debug build and dbg(function() { .... }):
loc op<br>main:<br>00000: getlocal 0<br>00003: pop<br>00004: getlocal 1<br>00007: pop<br>00008: getlocal 2<br>00011: pop<br>00012: zero<br>...<br>00256: loopentry 1<br>00258: getlocal 1<br>00261: int8 32<br>00263: lt<br>00264: ifne 22 (-242)<br>00269: stop<br>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() {<br>int x,y;<br>char line[33];<br>line[32] = 0;<br>for (y=0;y$arm-none-eabi-gcc mandel.c -mthumb -Os -c -o mandel.o<br>$arm-none-eabi-objdump -S mandel.o
00000000 :<br>0: b5f0 push {r4, r5, r6, r7, lr}<br>2: 2400 movs r4, #0<br>4: b097 sub sp, #92 ; 0x5c<br>6: ab0c add r3, sp, #48 ; 0x30<br>...<br>116: bc01 pop {r0}<br>118: 4700 bx r0<br>11a: 46c0 nop ; (mov r8, r8)<br>11c: 3fa00000 .word 0x3fa00000<br>120: 40100000 .word 0x40100000<br>Nope. 290 bytes.
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<br>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<br>-e*e+g,e=2*d*e+h,d=k,f=f+1;c+=" *"[f&1]}print(c)};<br>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<br>Size (bytes)
Original JS Code<br>301
Spidermonkey bytecode<br>270
Espruino Compiled JS<br>1136
GCC Compiled C code (-Os)<br>290
Minified JS<br>167
Minified and pretokenised JS<br>149
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 around half the RAM of even size-optimised C code!
What does executing from source mean?
The size of your source code will affect the code execution speed.
On the Espruino board a simple loop will create roughly a 4kHz square wave (so 4000 iterations of the loop per second) using code like this:
while (1) {A0.set();A0.reset();}<br>While code like this will toggle a pin at around 3.5kHz.
while (1) { A0.set(); A0.reset(); }<br>This applies equally to comments - so it pays to keep comments above or below a function declaration or loop, not inside it.
Note: You can turn on 'pretokenisation' globally with E.setFlags({pretokenise:1}) or<br>by beginning a function's code with the string "ram". Pretokenised functions have all whitespace<br>removed, and any tokens (such as this, function, for, etc) will be turned<br>into numeric values. This means that the above (whitespace slowing down<br>execution) will not apply - however your original code formatting will be lost,<br>which will make...