0

I am observing large changes to the program storage space used by my code when I change the size of buffers in my objects. An example object:

class MyClass {
    uint8_t buffer[1024];
    // ...
};

These objects are created and destroyed as local variables, meaning they only consume dynamic memory while they're actually in use:

void foo() {
    MyClass o;
    o.blah();
    // ...
}

And indeed, the initial dynamic memory used by my program is almost 0 (dynamic memory isn't the issue I'm having).

I've started hitting program storage space limits, so I've been playing with different options to reduce the size. Strangely, by changing the size of these buffers (and not even updating the rest of the code to be aware that the buffers are smaller), I'm able to reduce the total program storage space by 1-2kB (though obviously, it stops working correctly!)

Following discussion in the comments, here is an MCVE:

#define N 10

class MyClass {
    uint8_t buffer[N];

public:
    int get(int p) const {
        // Obviously likely to be an invalid memory read.
        // Add a %10 (regardless of N) if you want to prove this isn't due to UB.
        return buffer[p];
    }
};

void setup(void) {
    MyClass o;
    delay(o.get(rand()));
}

void loop(void) {
}

Compiled with: (same behaviour can be seen with IDE too)

mkdir -p "out";
/Applications/Arduino.app/Contents/Java/arduino-builder \
    -hardware "/Applications/Arduino.app/Contents/Java/hardware" \
    -tools "/Applications/Arduino.app/Contents/Java/tools-builder" \
    -tools "/Applications/Arduino.app/Contents/Java/hardware/tools" \
    -built-in-libraries "/Applications/Arduino.app/Contents/Java/libraries" \
    -fqbn "arduino:avr:pro:cpu=8MHzatmega328" \
    -warnings "all" \
    -build-path "$(pwd)/out" \
    "$(pwd)/Test.ino";
size out/Test.ino.elf;

The value of N can be changed to observe varying output sizes. It looks like this isn't storing initialisation values as I'd originally thought, but performing some form of optimisation on the code. Even this tiny program changes by 56 bytes though (N=10 -> 1040b, N=1000 -> 1096b).

I'd like to to know what is actually changing, and what is causing it to change the size of the generated code so drastically; maybe in my real code I have similar calculations consuming lots of bytes unnecessarily.

  • You wrote “the existence of this buffer immediately increases the program storage space by 1kb”. Did you verify that or are you just assuming this to be the case. – Edgar Bonet Jan 30 '17 at 20:38
  • @EdgarBonet yes; I changed the buffer to have a size of 1 instead and noticed the code size reduced by approximately the expected amount (12 bytes off). I expect the final small difference was just due to some other minor optimisations the compiler was able to make with the new memory layout. Also I should note that this is using the Arduino-default -Os compilation flag. – Dave Jan 30 '17 at 20:59
  • @EdgarBonet after further experimentation in a minimal project, and trying other values in my full project, it seems to not be so straightforward. There's a link with larger buffers causing larger executables, but it's flat most of the time and goes up in jumps. Perhaps just coincidence that it matched up so closely in my original test. – Dave Jan 30 '17 at 21:25
  • The .noinit section might do what you want. atmel.com/webdoc/AVRLibcReferenceManual/… – Majenko Jan 31 '17 at 0:15
  • Could you share a Minimal, Complete, and Verifiable example showing your problem? – Edgar Bonet Jan 31 '17 at 10:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.