Program storage and memory analysis, tools. methods.

Hi!

What is the most common method to analyze what is using up what in Arduino code?

For example, I'd like to find out what parts of the program are using the most program space (including libraries) and RAM space.

I know there is a plethora of tools and methods in the GCC ecosystem but is there a canonical how-to for this in Arduino code for the AVR family?

I must assume this is something pretty typical when you start hitting the limits on the AVRs. So wondering what methods, toolchains people are commonly using.

TIA!
Alex

There is a freemem "library" that you can include at strategic places in your code to display how much RAM memory is used.

If that's insufficient, I think that you will end up using avr-objdump (it's included in the install) and analyse the results. I don't have much experience with it.

AgroMeInc:
I must assume this is something pretty typical when you start hitting the limits on the AVRs. So wondering what methods, toolchains people are commonly using.

many of the basic gcc tools are under Arduino/hardware/tools/avr/bin

one that may be helpful is size. the following is for a program that ran out of RAM space and I had to put constant data in program memory space

Sketch uses 9518 bytes (29%) of program storage space. Maximum is 32256 bytes.
Global variables use 1380 bytes (67%) of dynamic memory, leaving 668 bytes for local variables. Maximum is 2048 bytes.

arduino_build_133433 /tools/Arduino/hardware/tools/avr/bin/avr-size *elf
   text    data     bss     dec     hex filename
   8524     994     386    9904    26b0 West.ino.elf

On an ATmega328 i tend to keep track a little in my head of anything i use and declare, 2KB isn't an awful lot, but i tend to use boards for specific tasks, that may use a fair amount, but rarely use libraries that suck up the lot. I know any sort of display with a resolution higher than an LCD takes up space, any monochrome pixel is a bit most color pixels are a word, and RGB LEDs take up 24-bits a pop. The main idea is not to double up on buffer.
On an ATtiny (the 13's mostly) every line of code you write can have different results, usually the 64bytes of RAM are enough, if not then store what you can in progmem. Flash memory in those cases can be quite surprising, the difference in flash use of a 32-bit calculation and a 16-bit is considerable (sure it may save you 2 bytes of RAM but in flash wow !) Many times blocking code is more efficient, and there isn't always a need for using millis() to de-bounce switches

void Switch() {
  uint8_t newswitchstate =  analogRead(SWITCH) / 350;
  if (newswitchstate == switchstate) return;
  
  for (uint8_t i=0; i<SW_DEBOUNCE; i++) {
    delay(1);
    if (newswitchstate != analogRead(SWITCH) / 350) return;
  }

this switch with 3 positions and a pull-up and a pull-down resistor on 2 of them.
using just delay(SW_DEBOUNCE);would result in the switch not being checked during that time, using millis() would result in much bigger code. In this case it can be about bytes, so taking the time to try making thisanalogRead(SWITCH) / 350;equation 8-bit can be worth it (it isn't but i have tried, the bit-shifting takes up more space)
For small things like the analogRead() equation, many times the optimizer kicks in (definitely in the micro-core) but anything you do more than once should be a call to a function rather than the same code twice. Even just similar pieces of code that can be converted to functions that take it's exception as an argument are usually worth it (though do not always make for code that is easier to read, more 'if' & if else' and 'switch-case'
On an ESP i sort of relax about the whole thing, and let it all hang out, use Strings (though keep in mind to either reserve space for them if they are global, or use them local only, i still don't want to fragment anything), big arrays anything i want, don't care about the memory use but rather go for read-ability, creating 2 functions for similar task, but with their own name etc.