Massive sketch size

C_D
Tue Jul 07, 2015 4:35 am
Ive started shifting a project of mine from an 8-bit arduino to stm32duino. When I compile for the stm32 the sketch size blows out hugely, and I cant work out why. I changed my pin definitions to be integers (instead of PA0 etc.) so it will compile for both 8-bit avr and stm32:

8-bit AVR: sketch 3,780 bytes and global variables 237 bytes
stm32duino: sketch 73,520 bytes and global variables 6,456 bytes

Heres the ReadASCIIString example compiled for the same two boards:
8-bit AVR: 3,506 bytes, global variables use 188 bytes
stm32duino: sketch 17,828 bytes and global variables use 4,224

So for an 8-bit AVR, my program is only marginally larger than ReadASCIIString, which makes sense, they do very similar things. But then on stm32 my code comes out 4 times larger than ReadASCIIString. Im not using any additional libraries, all my code does is read a serial message, read some ADC inputs and reply with the ADD values, its not very technical stuff.

I have tried chopping up the sketch and commenting out huge chunks, and I havent yet found what is causing it. I know there is a ton of extra code for the USB-serial stuff, but there must be more to it than that.

I dont really want to post the whole project (its about 300 lines), but does anyone have any ideas about where I should be looking to work this out?


victor_pv
Tue Jul 07, 2015 5:04 am
C_D wrote:

I dont really want to post the whole project (its about 300 lines), but does anyone have any ideas about where I should be looking to work this out?

RogerClark
Tue Jul 07, 2015 5:31 am
At the moment there can be a lot of things compiled in that you may not want.

if you are using the bootloader, there is the Serial USB stuff (as it has to go somewhere, i.e either the bootloader of the sketch, the overall amount of space taken would be the same)

But all boards have multiple hardware serial ports, minimum of 3 hardware serial.

I suspect the libraries for some things are bigger than on AVR, I know that the double variable type is correctly supported (AVR types double back to float), and the AVR takes a load of shortcuts to reduce code size, which make it a much less standard C compiler / linker.

However, if post the code somewhere, we could take a look


mrburnette
Tue Jul 07, 2015 12:27 pm
C_D wrote:Ive started shifting a project of mine from an 8-bit arduino to stm32duino. When I compile for the stm32 the sketch size blows out hugely, and I cant work out why. I changed my pin definitions to be integers (instead of PA0 etc.) so it will compile for both 8-bit avr and stm32:

C_D
Tue Jul 07, 2015 7:46 pm
Well my F103C8T6 is only meant to have 64K of flash, so a 73K sketch is too big. I gather *most* C8T6 parts actually ship with 128K of flash so in all probability it would actually work, but my concern is more that at present I don’t know where all that extra space has gone. Why is the ReadASCIIString example 17K (which is a reasonable size) and my sketch is 73K?

I’m doing some further investigation this morning to see if I can narrow it down.


martinayotte
Tue Jul 07, 2015 8:19 pm
Suggestion from Victor about looking at the resulting MAP file, look at all functions within address in 0x80000000 region and the next number is the size taken byt this function or symbol.
I’ve look at one of my sketches, and I saw that “cxa_demangle” from gcclibcxx is quite big. (I will try to figure out this one)

C_D
Tue Jul 07, 2015 8:21 pm
Apparently using ‘new’ is a bad idea?

Minimal example:

void setup() {
// initialise serial
Serial.begin(115200);

//this makes a 73K sketch
//byte *buf;
//buf = new byte [64];

//this makes a 12K sketch
byte buf[64];
}

void loop()
{
Serial.println("Running...");
delayMicroseconds(1000000);
}


RogerClark
Tue Jul 07, 2015 9:37 pm
I’m not sure why you would declare a byte array using new.

What you are asking the compiler to do is two completely different things.

Using “new” you are asking the compiler to create an array or objects of type byte rather than an array of bytes

I suspect the AVR compiler is simply not standards compliant and lets you do things like this, by not doing what an ANSI standard C++ compiler should do.

I have no idea why the byte object takes up so much space, probably Rick would be the person to advise on this. Perhaps its because internally the compiler is using malloc and there is a minimum allocation size.


martinayotte
Tue Jul 07, 2015 9:38 pm
Effectively, this is really strange !

Rick Kimball
Tue Jul 07, 2015 10:27 pm
C_D wrote:Apparently using ‘new’ is a bad idea?

C_D
Tue Jul 07, 2015 11:23 pm
Does 8-bit arduino handle new differently? I can use new just fine on 8-bit arduinos without this issue.

char* pvalue = NULL; // Pointer initialized with null
pvalue = new char[20]; // Request memory for the variable


RogerClark
Tue Jul 07, 2015 11:49 pm
The tutorial you linked to is not for embedded devices, its general C++

There are many things that C++ can do, but which you should avoid on embedded devices.

e.g. Use of malloc etc is generally not advised because the minimum allocation block size is often quite large in embedded terms, and also can lead to memory fragmentation.


C_D
Wed Jul 08, 2015 12:06 am
Which is a completely fair point :)

Whether using ‘new’ was appropriate or sensible in my sketch is probably an entirely separate argument (and it was almost certainly not the best way to achieve what I was trying to).

I guess my main observation is just that it appears to work in an 8-bit arduino environment and not in the 32-bit. Im quite happy not using the function, just interested to know why it works differently on the different platforms.


RogerClark
Wed Jul 08, 2015 12:12 am
@C_D

I’m not sure if there is a definitive list of the differences between the AVR and ARM compilers.

Perhaps its worth posting to the Due section of the Arduino.cc forum, as that will have the same “issues” as we are using exactly the same compiler as the Due (which is why you need to install the Due from the boards manager – as the ARM compiler is no longer installed by default)

And of course the shiny new Zero board will have the same issues. I suspect people buying the Zero as a replacement for the tried and tested Uno will be in for a few surprises.


Rick Kimball
Wed Jul 08, 2015 12:39 am
C_D wrote:Im quite happy not using the function, just interested to know why it works differently on the different platforms.

C_D
Wed Jul 08, 2015 12:57 am
I see. Thanks for clarifying that. I appreciate you guys taking the time to answer questions like this :D

RogerClark
Wed Jul 08, 2015 1:00 am
Rick

Is the Keil compiler any better. I’ve heard it is more optimised than GCC


mrburnette
Wed Jul 08, 2015 1:02 pm
Rick Kimball wrote:C_D wrote:Im quite happy not using the function, just interested to know why it works differently on the different platforms.

mrburnette
Wed Jul 08, 2015 1:11 pm
C_D wrote:Apparently using ‘new’ is a bad idea?
<…>

Rick Kimball
Wed Jul 08, 2015 2:00 pm
RogerClark wrote:Rick

Is the Keil compiler any better. I’ve heard it is more optimised than GCC


mrburnette
Thu Jul 09, 2015 1:31 am
Rick Kimball wrote:
<…>
I have no experience with Keil and unlikely I ever will. When I want to make something small I try to make sure it isn’t using any libc stuff.

-rick


pykowiec
Fri Oct 16, 2015 2:13 pm
Hi,

On arduino due there is the same problem. Linker generates massive binary when new and delete has been used.

Put the code at the top of the sketch.

void * operator new (size_t size) { return malloc (size); }
void * operator new (size_t size, void * ptr) { return ptr; }
void operator delete (void * ptr) { free (ptr); }

Now sketch size should by normal size.


mrburnette
Fri Oct 16, 2015 3:35 pm
pykowiec wrote:<…>

Rick Kimball
Wed Oct 21, 2015 6:46 pm
Rick Kimball wrote:RogerClark wrote:Rick

Is the Keil compiler any better. I’ve heard it is more optimised than GCC


RogerClark
Wed Oct 21, 2015 7:28 pm
Rick,

Thanks for the link to the free copy of Keil. I will grab a copy, just in case they change their minds about giving it away for free.

I dont need it now, but you never know in the future …..

Edit.

I downloaded the installer, but the page you get to when downloading, has text on their about limitations on demo and evaluation software.

I’m not sure if this is just because this text is always on that page, or whether this version of Keil is really just an evaluation copy.

You also need to register with MDK in order to get an activation code, i.e you can’t simply enter the code that is on the first page you get to.

So…

I’m probably not going to bother jumping through hoops to get Keil, as its unclear if I’m doing this just to get some evaluation software, rather than something I’m actually allowed to use in any practical sense.

(I know this is now the norm for big companies, even for evaluation software, to require registration and license code validation online etc etc, which is fine if you need it for work etc, but rather a pain just to evaluate something)


arpruss
Mon Apr 16, 2018 5:21 pm
By the way, just to update this old thread, at some point the libmaple-based core has dramatically improved in connection with the new operator. It’s still not as memory efficient as malloc() or compile-time allocation, but it’s way better–there is now only a 3K flash and 1K RAM penalty. Nonetheless I try to avoid new in my code.

void setup() {
byte* a = new byte[1]; // 18330 bytes flash, 3928 bytes RAM
// byte* a = (byte*)malloc(1); // 15276 bytes flash, 2824 bytes RAM
// static byte a[1]; // 15276 bytes flash, 2824 bytes RAM
}


Leave a Reply

Your email address will not be published. Required fields are marked *