Page 1 of 1

Memory Optimization

PostPosted: Fri Apr 04, 2014 3:32 am
by Myndale
I'm going to be turning my attention to code optimization next and I just thought I'd post a couple of tricks that may help if you suspect you're running out of memory and/or code space.

If you want to see how much memory your app is using for code space and global variables then you can use the objdump utility provided with the IDE. If you go to the Arduino IDE's File -> Preferences dialog and turn on verbose output for compilation then the output window will display the location of the hex file it makes when it compiles your project, i.e. something like this:

Code: Select all
C:\arduino-1.0.5\hardware\tools\avr\bin\avr-objcopy -O ihex -R .eeprom C:\Users\username\AppData\Local\Temp\build8635125389519731391.tmp\your_sketch.cpp.elf C:\Users\username\AppData\Local\Temp\build8635125389519731391.tmp\your_sketch.cpp.hex


The hex file is what gets uploaded to your Gambuino but the elf file contains information about the code that created it, and this info can be dump to a list file by running avr-objdump like this:

Code: Select all
C:\arduino-1.0.5\hardware\tools\avr\bin\avr-objdump -h -S -j .data -j .text C:\Users\username\AppData\Local\Temp\build8635125389519731391.tmp\your_sketch.cpp.elf > dump.lst


This will dump a whole bunch of useful info in dump.lst including a disaasembly of all routines imported into your project. Of particular interest are the text and data sections listed at the top of the file which show how much memory is being used for global variables and code, respectively:

Code: Select all
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         0000040c  00800100  000056ac  00005740  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         000056ac  00000000  00000000  00000094  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .bss          0000016b  0080050c  0080050c  00005b4c  2**0
                  ALLOC


This particular example is Rodot's AlienKiller demo, and we can see that there are 1036 (i.e. 0x40c) bytes used for global variables (half of which is the display buffer) and 22188 (i.e. 0x56ac) bytes of code. For comparison the Gamebuino has 2KB of usable RAM and 32KB for code (less 2KB being used by the boot loader). However it's also allocating 363 (0x16b) bytes for the .bss section which is globally allocated variables that aren't initialized to a particular value.

Looking at the lst file will tell you how much memory is allocated at the start-up, but you may also need to keep track of run-time usage. When a Gamebuino game starts up the global buffer is allocated at the very bottom of SRAM, the heap appears immediately after it and the stack is placed at the very top of RAM. Any calls to malloc() will cause the heap to grow "up", and any data allocated on the stack by calling functions etc will cause the stack to grow "down". If they meet up in the middle your program will either start acting weird or simply crash.

To help prevent this you can use code like this during development to keep track of the heap and stack pointers and if they get too close print an error message or something:

Code: Select all
void mem_check()
{
  void * heap_ptr = malloc(0); 
  if ((!heap_ptr) || ((int)heap_ptr + 100 >= SP))
  {
     Serial.println("Out of memory!");
     while (1);
  }
  free(heap_ptr);
}


Here's an example to demonstrate this, the test() function calls itself recursively, increasing the stack a little each time, until finally we run out of memory:

Code: Select all
void dump_mem()
{
  void * heap_ptr = malloc(0);
  if (heap_ptr)
    free(heap_ptr);
  Serial.print("heap: ");
  Serial.print((int)heap_ptr);
  Serial.print(",  stack: ");
  Serial.println(SP);
}

void test()
{
  dump_mem();
  mem_check();
  test();
  test();   // call test twice so that the compiler doesn't convert the first one to a tail call
}

void setup() {
  Serial.begin(9600);
  test();
}

void loop() {
}

Re: Memory Optimization

PostPosted: Fri Apr 04, 2014 12:28 pm
by rodot
Thank you for this detailed explanation!
If you could add it to the page "Performance optimization" of the wiki, that'd be really cool :)
http://gamebuino.com/wiki/index.php?title=Performance_optimization
I tried to write a few things, but I'm not a badass programmer like you and my skill in English doesn't help :P

Re: Memory Optimization

PostPosted: Fri Jun 20, 2014 2:38 am
by treflip
Yes, Thank you for your info Myndale. It is a real help!

Re: Memory Optimization

PostPosted: Tue Jun 24, 2014 7:45 am
by jonnection
On the subject of memory optimization, I came across Andy Brown's site today.

He's provided some excellent tools for debugging AVR dynamic memory allocation, should you want to use it.

http://andybrown.me.uk/wk/2011/01/01/debugging-avr-dynamic-memory-allocation/

Andy has written a port of the STL (standard template libraries) for the Arduino, which allows Arduino coders to use vectors and other dynamic goodies.

There is an extremely interesting bit about Andy's STL implementation, which I will quote here:

Note that I have also ported the template specialisation of vector for bool, i.e. std::vector<bool>. This is implemented as an array of single bits that is highly efficient in its memory usage.


...which could be VERY useful for game environment variables, which often are in the form of boolean true/false, and are a pain to pack into bytes or waste loads of space if used as single bytes.

Re: Memory Optimization

PostPosted: Thu Jun 11, 2015 9:07 pm
by BurningSushi
Wow, sorry about this I know it's an old post, but information like performance optimisation is quite hard to find on the wiki and I feel it's extremely important information to put on the sidebar. And if I had difficulty with it......

But honestly thanks for pointing to this page, it's going to help majorly in the future :)

Re: Memory Optimization

PostPosted: Tue Oct 06, 2015 3:53 pm
by Zvoc47
I like this idea. You should put those print strings into PROGMEM for more optimization for more optimization.