-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Arduino fails to optimize out unreachable Serial library code #266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Well, the compiler doesn't really know whether that Option 1: fix your code to tell the compiler that all "global" variables and functions other than setup and loop are not meant to be used outside of this file, by using the
Option 2: fix Arduino so that it tells the linker to remove unused functions and variables by adding the compiler flags PS: I think these flags are not used. Maybe I'm wrong and Arduino already uses them, in which case I have no idea why this would happen. Still, option 1 would probably show some improvements. |
@cousteaulecommandant, the flags you indicate in option 2 are already used, and, I think, the However, the problem is that the function cannot be removed until link time (unless, as you suggested you add Note that I expect that only things referenced by the ISR are kept, so if you actually call Fixing this is probably impossible or tricky. While writing this I realized that |
Once upon a time, there used to be a deprecated and now unsupported (I think) option, |
@cousteaulecommandant, nowadays, there is link-time-optimization (LTO) which can be used to achieve pretty much the same effect I believe. However, that doesn't solve this particular problem, since the compiler still doesn't know when to (not) include ISRs. |
Every time Arduino's use of LTO comes up, problems with the USB Host Shield library seem to come up... |
@matthijskooijman, that was my point; LTO doesn't deal with this problem correctly. Then again, maybe The best solution would be to tell GCC to mark all function and object definitions in a file as (Then again, is this really needed? Isn't the user expected to just not define unused functions?) |
If you're worried about someone making a utility library where some functions use Serial (for example), then I think the rules change, since (I think) only symbols needed from an object file will cause the inclusion of other object files, so if I understood correctly the object file containing Serial will not be pulled if you don't use any of the functions from that library that use Serial. |
The externally_visible / used attribute on the ISRs will indeed prevent -fwhole-program from working here (unless -fwhole-program ignores that attribute, but then ISRs will always be optimized away, which isn't quite what you need either. I don't think -fwhole-program will really work for what you need here, unless the compilation is changed to compile everything in one gcc call (instead of separate compile and link steps as now). To make things work now, you would need smarter handling of ISRs. Ideally, you would be able to declare a dependency from all functions that enable an ISR to the ISR function itself, for the linker to see (but I'm not sure if this is possible in a way that does not generate any runtime code). Then you could remove the
This is exactly why C libraries used to do a 1-function-per-file approach in the old days (now, -ffunction-sections and -fgc-sections remove the need for this, except perhaps for ISRs and other functions that are marked as externally_visible / used and do not play by the normal rules). |
Just to clarify, I meant to use According to the GCC documentation:
So, if I understood correctly, |
Ah, I see now. However, this approach actually changes the meaning of the code. For symbols that are only used inside the .ino file where the user simply forgot to add static (which is most of them), this shouldn't matter, but for other symbols which are (weakly) referenced by external libraries, this approach will break (e.g. consider |
Even with MY_DISABLED_SERIAL defined, the linker is still adding the Serial object to the binary. That's because a) the MySensors *.cpp files are actually included into the sketch and compiled as part of it (and not compiled separately and then linked) and b) due the the default(?) behavior of the linker (https://github.com/arduino/Arduino/issues/4579).
Even with MY_DISABLED_SERIAL defined, the linker is still adding the Serial object to the binary. That's because a) the MySensors *.cpp files are actually included into the sketch and compiled as part of it (and not compiled separately and then linked) and b) due the the default(?) behavior of the linker (https://github.com/arduino/Arduino/issues/4579).
Even with MY_DISABLED_SERIAL defined, the linker is still adding the Serial object to the binary. That's because a) the MySensors *.cpp files are actually included into the sketch and compiled as part of it (and not compiled separately and then linked) and b) due the the default(?) behavior of the linker (https://github.com/arduino/Arduino/issues/4579).
Even with MY_DISABLED_SERIAL defined, the linker is still adding the Serial object to the binary. That's because a) the MySensors *.cpp files are actually included into the sketch and compiled as part of it (and not compiled separately and then linked) and b) due the the default(?) behavior of the linker (https://github.com/arduino/Arduino/issues/4579).
Even with MY_DISABLED_SERIAL defined, the linker is still adding the Serial object to the binary. That's because a) the MySensors *.cpp files are actually included into the sketch and compiled as part of it (and not compiled separately and then linked) and b) due the the default(?) behavior of the linker (https://github.com/arduino/Arduino/issues/4579).
Even with MY_DISABLED_SERIAL defined, the linker is still adding the Serial object to the binary. That's because a) the MySensors *.cpp files are actually included into the sketch and compiled as part of it (and not compiled separately and then linked) and b) due the the default(?) behavior of the linker (https://github.com/arduino/Arduino/issues/4579).
I think this is something we cannot really fix, since it is just a limitation of the C/C++ language. In particular, it is pretty much impossible for the compiler to tell whether an ISR is actually enabled or not. We already support leaving out the Serial ISR (and related code) if you do not reference the Serial object at all, which I think is the best we can do. If anyone has any ideas on how to fix this, I'm happy to hear them. Until then, I'm closing this issue. |
@matthijskooijman sorry for bringing this one up after so long, but I've been trying to figure out the mechanism for optimizing out unused Serial ISRs. Where in the code or build system is this happening? I'm asking because I'd like to do the same in a library; leave out the ISR if it's not being used. Thanks! |
For reference, the library I'm trying to modify is the Logic library A wapper for the CCL hardware for the megaAVR-0 series. The problem is that |
@MCUdude, for some background on how this was implemented for HardwareSerial, see arduino/Arduino#1711 (comment) and for a similar thing for the timer ISR, see #320 One important bit here, is that this trick only works when linking through .a files. This is the default for the core, but libraries are linked through .o files by default (meaning each .o file of the library is specified explicitly on the linker commandline, and thus is included in the link unconditionally, and then the Hope this helps. If you have further questions, maybe good to open an issue in your library for further discussion? If you tag me, I'll find the issue from the notification :-) |
Thank you for your reply @matthijskooijman! |
Many libraries use Serial output in debugging routines, and often times the serial interface is used for any number of other purposes.
Sometimes though, in a finished device, the serial interface is not used at all. In these instances, those serial output routines are never called, yet the Serial library wastes precious Flash space and SRAM.
Here's an empty Arduino project, and its compilation output:
Now the same code again with a simple, but unused function added:
As you can see, 173 bytes or SRAM and 938 bytes of Flash are now used that should have been available to the programmer. The SRAM is of the most concern... That's almost 17% of the SRAM available on 1k chips!
And to trigger this bug, all you have to do is have a stray Serial library reference in and file you're including (or anything it includes) and goodbye 173 bytes of SRAM.
The text was updated successfully, but these errors were encountered: