PDA

View Full Version : One function adds 21,736 bytes to total flash count?



t3andy
02-07-2013, 11:36 PM
One function adds 21,736 bytes to total flash count? :confused:
Also, it adds 1226 for ram usage? :confused:

Before
Binary sketch size: 51,172 bytes (of a 131,072 byte maximum)
Estimated memory use: 4,680 bytes (of a 16,384 byte maximum)

Using
sprintf(str,"%d",abs(networktime));

After
Binary sketch size: 72,908 bytes (of a 131,072 byte maximum)
Estimated memory use: 5,908 bytes (of a 16,384 byte maximum)

Code snippet- counts the number of chars in a integer

long x = 0;
char str[20];
sprintf(str,"%d",abs(networktime));
x = (strlen(str));
Serial.println(x);


win xp/sp3
beta12

PaulStoffregen
02-07-2013, 11:54 PM
Yes, newlib's printf and scanf implementations are huge.

MichaelMeissner
02-08-2013, 12:01 AM
Well sprintf is a rather large function. Look at the documentation for it, it has to have code to handle all of the different formats, and different sized data types.

You didn't mention if it was teensy 1/2/2++ or 3.0. I suspect in addition to the size of the the code for sprintf and all of the functions it calls, the teensy 3.0 may bring in the entire floating point emulator, since sprintf supports %g, %f, etc. to print floating point. The AVR port for Arduino (and presumably teensy 1/2/2++) compiles its sprintf without support for %f, %g, etc. so it doesn't drag in the emulator.

There are better ways to do what you want (looping, dividing by 10 to get the number of digits would probably be the smallest, or calling itoa instead of sprintf would be simpler)

PaulStoffregen
02-08-2013, 12:21 AM
I've considered porting the avr-libc version. But at this point, with the only downside being extra memory usage, it's a really low priority.

However, if someone were to do this porting, I'd happily accept a patch.......

Jp3141
02-08-2013, 12:24 AM
Yes, newlib's printf and scanf implementations are huge.

Is there a better (smaller) version ? I use it frequently to ensure my outputs are formatted cleanly. The floating point is the only portion I could perhaps work around.

e.g. sprintf(DataLine, "%4i %3s %3s %2i %2d:%02d:%02d Internal Temp # %9ld = %6.2f deg.C%s\n", Set6Y, DOW[dayofweek(Set6Y, Set6Month, Set6D)], Month[Set6Month-1], Set6D, (iLastTime/3600) % 24, (iLastTime/60) % 60, iLastTime % 60, rollingCounter++, temperatureC, CRLF);

t3andy
02-08-2013, 01:05 AM
You didn't mention if it was teensy 1/2/2++ or 3.0.
Teensy 3 using beta 12

MichaelMeissner
02-08-2013, 03:03 AM
The arm toolchain uses newlib as a base. Back when I was doing embedded toolchains, I recall that there was a variant of the *printf family that was compiled without floating point support. So if you change all 'sprintf' calls to 'siprintf' calls, it will save some amount of memory. I always wanted to add an option to GCC for newlib toolchains that would convert calls to sprintf to siprintf if there were no long, long longs, or floating point passed, but it was never a high enough of a priority to do the work.

Lets see, if I compiled a simple sketch that calls sprintf in the setup function:


32,164 bytes of text space, and 5,376 bytes of read/write data if I use sprintf;
16,488 bytes of text space, and 5,252 bytes of read/write data if I use siprintf.

t3andy
02-12-2013, 11:30 PM
I checked the function sprintf(); on the AVR and it only adds ~ 2k to the flash count.;)

MichaelMeissner
02-13-2013, 12:38 AM
It is likely the AVR sprintf doesn't have all of the various formats that siprintf does.

Another thing is how compact the encoding is for the AVR compared to the ARM. I haven't looked at either instruction set ISA in any detail.

I believe that Teensy 3.0 actually supports normal printf/iprintf, and if so, it may be that doing that support drags in all of Serial support.

Finally, one of these discussions highlighted that in the AVR world, all modules are compiled with -ffunction-sections and linked with -Wl,--gc-sections. These two options compile each function into a separate section, and then the linker eliminates all of the unused sections. That means if you have a package (say Serial.print) that has a bunch of methods for different types, and you only use one of type, the code for the other templates, etc. is not in the final linked images on the AVR, while it currently is linked in for the ARM.

You would need somebody dedicated to tracking down where all of the stuff that is part of the final link comes from. I already have a day job that keeps me quite busy dealing with the GNU tools (and in fact, things will be heating up in a month or so in terms of future work), so I'm not stepping up to the task for doing something after hours. It isn't rocket science, but you need somebody with the time and energy to track down these things.

PaulStoffregen
02-13-2013, 02:22 AM
It isn't rocket science, but you need somebody with the time and energy to track down these things.

Yup, indeed.

Eventually I'll probably work on this... but most likely I would do so by porting the avr-libc code or something similar. Despite ARM's marketing info, AVR code does tend to compile larger on ARM. But it's not usually more than about 50% larger.

Of course, this is a very low priority for me. It'll probably be about a year until I look at it.

nekidfrog
02-28-2013, 10:09 PM
ugh.. no wonder my code went from 35k to 58k using snprintf....