Optimizations

The goal is to reduce the size of the generated binaries. This is done by aiding the linker to eleminate dead code by splitting large source files and by hand-optimizing individual functions.

Results

The sum of all these optimizations reduces the total size of Blink.ino by more than 30%, saving more than 800 bytes of precious flash space:

code data RAM flash total split stage
2507 138 72 2645 before split
2450 138 72 2588 after splitting wiring.c
2381 138 72 2519 after splitting wiring_digital.c
1799 138 72 1937 after splitting HardwareSerial.c
1686 138 72 1824 after optimizing pinMode()

Data is mostly the tables to map the Arduino pin numbers to the actual port registers. RAM is mostly the transmit and receive buffers for serial communication. These can't easily be optimized out.

Splitting files

The SDCC linker does not detect unused functions and constants in an object file. It always links the whole file even if only a single symbol contained in the file is referenced. This results in pretty bloated binaries if the SPL is used.

Splitting larger source files into smaller units and compile them individually before building the libraries helps the SDCC linker to eleminate dead code and to produce smaller binaries.

Splitting files is worthwhile for all SPL files and at least some of the bigger Arduino core files.

The stategy

The SPL consists of many source files with a very regular structure. This allows to automate the splitting process with very little preparation work.

All SPL functions are documented with a doxygen comment block. The beginning of this comment block is a line with only "/**", that can easily be used as a marker for splitting the files.

Only the very first block is special. It contains definitions and prototypes that are needed all over the module. This block is saved as a .h file and #include'd by all the following blocks.

In most cases this is already sufficient. Only in very rare cases the position of a split needs the be edited.

To prevent a split: Change the /** line into something different, /*** is used in the scripts.

To force a split: Add an empty Doxygen comment block:

/**
 * This is just a split marker
 */

Splitting the SPL files

Splitting and compiling the SPL libraries is moved into the separate project spl-splitter now.

Split Arduino core files

The Arduino files don't have any regular structure. They need to be edited to become splitable at all and some of the resulting split files still need manual adjustments.

wiring.c, wiring_digital.c and HardwareSerial.c all compile into quite large binaries. All of them are linked with almost every project. This is true even if no serial communication is used since main.c references serialEvent() and this way pulls in all of HardwareSerial.

Splitting these three files reduces the size of simple sketches significantly. It does not help so much for complex sketches that use almost all functions of these modules.

Optimizing individual functions

pinMode() sticks out when looking at the size of individual functions. 270 bytes for just setting the IO-mode of a pin. A re-write in assember reduces this to just 147 bytes.