Where do all my bytes go? ... an analysis of program size in an S4A 4.0 series application

You heard it here first, but coming this year, we are finally releasing the version 2 compiler, as part of Swift for Arduino release 4.0.

This is a very exciting new development, with our own patched swift frontend and (most importantly) a custom built standard library, fine tuned for the atmega328p and the arduino uno.  There is most definitely nothing else like this anywhere in the world. Another first!

As part of this launch, I'm going to try to do some more blog posts about day to day findings and experiences with making AVR/Arduino programs using our new compiler.

As an example, I just compiled this program...

import AVR

SetupSerial()
print("newer API")
public let dummyArray = [1,5,9,112,0,1,4]
print(dummyArray.count)

while true {}

This is a super simple program demonstrating some of the powerful new features of version 4.0, namely our custom made strings and our customised arrays.

Both are super efficient on a microcontroller and we have removed some of the features you generally won't need (such as string manipulation) in favour of efficiency. The string is stored wholly in program memory, efficiently transmitted to the UART and never transferred to RAM.

When we run avr-size on this simple program, it's still nearly 6k in flash memory.  Where does this all get used?

/Users/carlpeto/compilers/avr-binutils/2.32/bin/avr-size main.elf
   text    data     bss     dec     hex filename
   5996      22     333    6351    18cf main.elf

Analysis of a disassembled and deconstructed ELF file shows us where it's all gone.  Specifically...

gcc/ld
***
(458 bytes)
vectors, strings and initialisation

vfprintf
***
(1730 bytes)

main
***
(112 bytes)

s4a custom swift runtime
***
(4 bytes)
swift_slowAlloc


AVR functions and specialisations
***
(200 bytes)

AVR ISRs and constructors
***
(1606 bytes)

AVR low level functions
***
(250 bytes)


libgcc, libc and gcc internals
***
(1636 bytes)
__udivmodsi4
__udivmodsi4_loop
__udivmodsi4_ep
1108=>114c

__prologue_saves__
__epilogue_restores__
__tablejump2__
114c=>11c6

malloc+free
11c6=>1410

__ftoa_engine
strnlen_P
strnlen
fputc
snprintf
__ultoa_invert
1410=>1768

_exit = 2 bytes
__stop_program = 2 bytes

end of flash .text section 0x176c = 5996 bytes

As you can see, the main program is only 112 bytes in length, which is very efficient. That's really the point of using swift, a powerful, expressive, safe language but compiling efficiently.

Our internal Swift for Arduino libraries (AVR) contain functions adding up to 450 bytes. But they also have a fixed overhead; ISRs and constructors, that are always present in every program, 1636, over a quarter of the whole hex file size, that handle interrupts and setup. In our particular case, they are not used by our program so they represent space that could be harvested in an advanced build.

Finally, gcc template code, start vectors, libgcc functions and libc functions, including an optimised vfprintf amount to another 3824 bytes, well over half the program size.  Some of this, like the 104 bytes of interrupt/reset vectors, are unavoidable, even in an assembly language hand written program.

Most of the rest of it should be seen as the typical costs of writing in a high level language, instead of hand written assembly. And would be similar even if we were using C or C++ libraries, indeed the same functions and prologue/epilogue would probably be present in about the same size.

The takeaway is that swift for arduino is remarkably efficient. Creating a main program of 112 bytes, including library functions amounting to only 454 bytes and with a fixed cost of 1606 bytes added to all programs for ISRs/constructors to give a fully featured platform (some of which might be able to be trimmed for super specialised developers needs).

This represents a powerful, safe, easy to use new platform with minimal overheads.

Comments

Popular posts from this blog

Halloween LED lights on a plastic trick or treat cauldron

All about bootloaders

code signing, entitlements, bundles, sandboxes, hardened runtime, notarisation, app store security