Code size

Why does an Arduino sketch take up so much precious code space? A few lines of code takes up 2k?

Also, can I create a MAP file somehow (to answer the above question?)?

Libraries, my friend, libraries…
Remember those "include"s?

can I create a MAP file somehow

see this thread for info on avr-objdump:

you can find info on the arguments for avr-objdump here: avr-objdump

I have no “includes”. The code is really only a few lines with an interrupt.

I’m not a developer, just a newbie programmer curious why the code is so big.

Is there some way to “turn off” or not include unnecessary stuff?

A sketch with nothing but empty setup and loop functions uses just under 1k of program memory. These are for some of the core arduino functions like the interrupt handlers that will be used when you start using millis and analog writes.

If want to use Arduino functions then you do need to have that code. But I think you may be pleasently surprised how much stuff you can do within the available program memory.

Have fun!

Thanks for the info.

A fellow programmer here at work claims there must be a way to get a MAP file of the code. Is that possible?

  1. A map is of somewhat limited use when most of the functions are invisible to you. However, there is a utility “avr-nm” (display name list) that sort-of shows the info you want. Here’s (edited) output from “avr-nm -S blink.elf” using the basic blink code as an example. The second column is length:
000002fc 00000054 T delay
00000400 00000096 T digitalWrite
0000008b 00000014 T digital_pin_to_bit_mask_PGM
00000077 00000014 T digital_pin_to_port_PGM
0000009f 00000014 T digital_pin_to_timer_PGM
0000057a W exit
00000350 00000074 T init
0080010a 00000004 b intFunc
00800100 00000002 D ledPin
0000010a 0000002e T loop
00000144 0000000e T main
000003c4 0000003c T pinMode
00000072 00000005 T port_to_input_PGM
00000068 00000005 T port_to_mode_PGM
0000006d 00000005 T port_to_output_PGM
0080011e 00000080 B rx_buffer
0080011a 00000002 B rx_buffer_head
0080011c 00000002 B rx_buffer_tail
00000496 00000010 T serialWrite
00000138 0000000c T setup
00800112 00000004 B timer0_clock_cycles
00800116 00000004 B timer0_millis
0080010e 00000004 B timer0_overflow_count
  1. New algorithms envoked in 14 let the linker omit code that used to be included. Unfortunate, that was expected to REPLACE the previous library-based omit-code techniques, and it doesn’t quite. (so you see above that blink includes some serial code even though it doesn’t use it.) It’s easy enough to get the old code back (in addition to the new code), and ardunio-15 will contain the patch. Giving (for blink):
 text    data     bss     dec     hex filename
 1090       2       4    1096     448 Blink.elf   [arduino-0011]
 1122       2       8    1132     46c Blink.elf   [arduino-0012]
 1218       8     148    1374     55e Blink.elf   [arduino-0013]
 1406       8     150    1564     61c Blink.elf   [arduino-0014]
   952       2      12     966     3c6 Blink.elf   [arduino-0014 with patch]

An empty sketch is down to about 500 bytes with 14+patch. Note that the size is also dependent on compiler version; there was a significant jump in the size of code produced going between ardunio 11 and 12 with no obvious cause. The gains in patched 14 are due to being able to leave code out, not due to smaller code :frowning: The compiler writers (NOT the arduino team) can change their minds at any moment, resulting in significant changes in behavior; compiler writers do that :slight_smile:

  1. The size of a small sketch is irrelevant. This is a microcontrolller, and you’re not sharing system resources with other users or other tasks. Either your sketch fits, or it doesn’t fit. There is no advantage to having 12k of program memory free vs having 2k free. There’s also no used optimizing the size of “empty” sketches, because empty sketches aren’t interesting. The “real” measure of how well things are working is the slope of the line:
y = mx + b
codesize = ( compilerefficiency * sourcesize ) + overhead

That means, when you double the size of your sketch, the amount of memory consumed in the AVR does NOT double. It’s not like a basic stamp where nearly ALL of the overhead is “hidden” where you can’t see it.

I noticed that (did not do further research though) code is generated even for functions that are not referenced.
So, if one has defined a function, even if that function is not called, the program size grows.

Okay, so I’m not understanding something, then. No surprise.

The code size does affect how long it takes to loop(), doesn’t it? So at least in some cases it is relevant?

I doubt that the overall code size affects the time spent in the loop. The code for a function is there, for one to call. But if you don’t call it, then no time is spent on that function.
You can measure the time spent in the loop by using millis().

As was said above, code in a sketch that is not used has no impact on execution speed. Code can be executed from an interrupt, but the only interrupt that is operating in a minimal sketch is a few lines of code used for millis and delay. These functions are the heartbeat of almost every sketch so there’s not much point in removing them.

So as an experiment, I tool the “Blink” example and exactly doubled the size of the sketch by adding “ledPin2” that gets the same things done to it as ledPin. This cause the sketch (compiled with the arduino environment on Mac) to increase in size from 1414 bytes to 1470 bytes (56 bytes)
(With the patched 14, it when from 954 to 1010 bytes; same increase!)
(with version 11, which has a compiler that is “well known” to produce smaller code, the change was from 1092 to 1148; same increase, so this is apparently not the sort of code whose size changed!)

So following the dubious line of reasoning that one can deduce anything of value by looking at the size of a few lines of code, one might conclude that if adding 7 lines of code (to blink a second LED) adds 56 bytes, then assuming each additional line of similar code added on average ten bytes, Arduino with a 328 chip can have a sketch that is over 3000 lines long :wink:

the interestering question is just: Do additional lines or functions that are not needed correlate with the amount of space used by the binary program?

i have asked myself that question a few times myself when i was reading through libraries. The main question for me was if libs are always compiled the way they are or if the code compiler mechanism leaves out unused functions and variables. Stupid me i never tested it though…

Ok tested it… there is no difference between programs using libraries with unused functions…

Try it with version 0014.

the blink example referred to above is no bigger if importing but not using the LiquidCrystal library.

Adding the constructor brings in 400 bytes of library code.

Adding a println statement adds 54 bytes but adding a second println only adds another 16 bytes. I think that shows that there is a difference in code size with unused functions.

it’s not the number of lines that correlate to code size, its the actual number of bytes of machine code that the compiler produces for each function.

yes… so its not a big surprise with your numbers. I was just wondering if a library is always compiled and included completely or not - and it seems it isnt ;0)

So, MEM, a program with 3000 lines of code will loop() just a fast as Blink?

Getting back to the beginning tho, is there some way to get a MAP file during the compile process? That would help answer these questions.

The utilities mentioned in reply#2 or reply#6 should give you what you are looking for.

mem, thanks for the help and patience, but I have almost no idea how to use the utilities suggested in reply #2, or how to get any useful information out of the code in reply #6.

Remember that I have a total of about 10 hours of experience writing code of any type, so I’m not really understanding most of what you all are saying.

I was just curious how Loop() might be affected by how long a program is, in case I or someone wanted/needed it to loop at a known or controllable frequency.

So, I asked a co-worker to look at Blink and he was quite surprised that it took up much more than a few bytes of program space. Someone else then jumped in and said “make it print out a MAP file, that will have all the information you want”. Hence the question that started this surprisingly long forum topic.

I await yet another attempt by some patient person to explain this in yet another way that my simple mind might understand it.

Thanks in advance!

OK well…

Your question about 3000 lines of code is kind of undefined… if each of the 3000 lines just did something really simple, like adding 1 to a number, it would definately finish in time. On the other hand, you could come up with some really crazy code that would take more than a second to execute, but it’d be really complex stuff.

As an example of what you can do in a small amount of time, you can read a position from a GPS unit, log the data to an SD card, and display your position on an LCD screen in well under 1/10th of a second.

In general, the arduino is way fast enough for anything you will do. It runs at 16MHz - that’s 16 million instructions per second. That’s a LOT of changing output pins, reading input pins etc. Of course there is some overhead with the arduino code, but that is the trade-off between SIMPLICITY and EFFICIENCY.

In regards to your desire to do something at regular intervals, this is a well-used feature. The arduino has a functions built in to do this. They are called interrupts. Definately do some reading of the arduino website and this forum, but bassically when the condition for an interrupt is met; can be a change of pin value like a button being pushed, or like you want to do a defined time period has elapsed, the arduino stops whatever it was doing (i.e. it interrupts) and runs the code you want to run when the condition is met.

People use this extensively in timing sensitive applications, like clocks. An interrupt is set to occur every second. when the interrupt starts, it adds one second to the time.