Skip to content
This repository has been archived by the owner on Aug 5, 2022. It is now read-only.

Debugging

Geoff Gustafson edited this page Nov 29, 2016 · 6 revisions

ZJS Debugging

Eventually, we should distinguish between tips for debugging JS applications and ZJS and its APIs themselves. But for now, let's just collect anything we can think of here.

Basics

To debug the Arduino 101 x86 image, first build and flash as usual. Then in one terminal, from the ZJS root directory, start the debug server on the A101 device like so:

$ make debug

Then in another terminal, from the ZJS root directory, start gdb and connect to the server like so:

$ make gdb

Now in this second terminal you are read to use gdb as usual with commands like b main, c, Ctrl-C, bt, n, etc.

These are just shortcuts to the make debugserver target in Zephyr and running gdb locally with a target command to connect to the server. For more details, read Debugging on Arduino 101.

Memory in ZJS

There are a number of different ways memory is used in the ZJS system. The Zephyr OS itself reserves some memory for its own use. Then there are some static structures we reserve in our ZJS API code. In prj.mdef, we set HEAP_SIZE to reserve some space for calling task_malloc / task_free. Currently this is set to 4096 (4KB). Finally, JerryScript allocates a memory pool for the data structures it needs as your application runs. These last two are the places where you might run out of memory at run time.

When JerryScript runs out of pool memory, it writes 'exit' to the serial console and terminates. When our Zephyr heap runs out, it returns a NULL pointer to task_malloc and we should catch it; we should be able to recover or drop an operation without a hard fail.

Debugging memory leaks

If I suspect a memory leak, the way I usually debug it is to force it to happen faster. So I create a loop in my JavaScript to run the suspected faulty operation over and over. If you're leaking even one byte per operation, you will run out of memory in a few tens of thousands of calls. But really, the minimum allocation is something like 8 or 16 bytes (TODO: fill in exact details), so you will tend to run out of memory after at most 5000 calls. Usually I add a print statement to count each time I perform the operation, then I watch what count I got to before the 'exit'.

Once you can reproduce it like this, try to shrink down the amount of code that's getting repeated until you get it down to the smallest amount of code that reproduces the problem. Then you should be hot on the trail of the memory leak.

When it's the Zephyr heap that's running out instead, I've just added a feature to trace the malloc/free calls that ZJS makes. We've wrapped all these calls with zjs_malloc and zjs_free, and now if you set TRACE=y when building, these will be redefined to also print messages like this:

zjs_add_callback:99: allocating 20 bytes (0xa800dc28)
...
zjs_remove_callback:136: allocating 20 bytes (0xa800dc28)

You can manually review the output and hopefully discover the problem. Here's how you use it:

$ make TRACE=y JS=samples/Timers.js
Clone this wiki locally