-
-
Notifications
You must be signed in to change notification settings - Fork 7k
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
Resources consumed by HardwareSerial even when not actually used #11597
Comments
@brycecherry75 What core/board are you using? For AVR, there is some code in place that ensures that serial objects are not included in the build unless they are referenced. For most other cores, this does not happen (so typically serial objects are always included, or sometimes all serial objects are included if one is referenced). For the particular case you show, though, that the serial object is referenced from a function, but that function itself is unused, I can imagine that the compiler fails to handle this case. Serial objects in this context are a bit special, since in addition to an object that can be optimized as normal, there is an interrupt handler that is not called directly, but must be defined when it is enabled. To prevent the ISR from being optimized away, it gets the "used" attribute, preventing it from being optimized away. To ensure that the ISR and serial object are not always included in the build, even when they are unused, the AVR core uses some trickery that takes advantage of how the linker pulls objects from the core.a library file only when needed. In this case, I can imagine that, because there is a reference to In other words, if you are indeed using the AVR core and if removing the reference to Though thinking about this, one thing that could maybe work is if we could somehow replace the "used" attribute on the ISR with an explicit dependency from the Serial object and/or constructor to the ISR (i.e. make it as if the ISR is called from the serial object), so the optimizer can actually make a meaningful choice whether or not to include the ISR or not. I'm not sure if this is at all possible without actually calling the ISR (or taking its address), but maybe there is some C++ or gcc trick for this? I do not have time to look into this right now (or soon), though. |
I gave this a little more thought today. I think that you could add the explicit dependency with some volatile asm statement that takes the address of the ISR as an input operand. This will probably still generate an explicit load of a literal (the ISR address), but that seems acceptable overhead (maybe you could even mask off all but the lowest bits of the address to ensure the load is just a single short instruction, but I'm not sure if the linker supports this). Assigning the address to a volatile pointer variable could be an alternative, but I think this will be optimized away if the variable is not otherwise used. I was thinking that this dependency should be added from the Simpler is to just add the dependency in the constructor, since that will also be called by the compiler but can also be optimized away when all references to the serial object are optimize away. Note that this still requires a separate subclass for each instance, but that's ok. The downside is that if you somehow reference a |
I did a quick experiment, and it turns out that just removing the
I'm not sure what happens exactly, maybe the linker already decided to override the weak version with the strong version before LTO, or maybe it still considers the strong version as a valid option even though it is discarded by LTO? Anyway, I'm out of time for this project (I thought I could maybe quickly whip something up, but it doesn't seem to be that easy...). Here's the files I've been experimenting with (using plain avr-gcc to keep things simple). main.cpp: #include <avr/io.h>
#include <avr/interrupt.h>
//extern "C" void USART0_RX_vect() __attribute__((signal, externally_visible, used));
extern "C" void USART0_RX_vect() __attribute__((signal));
void USART0_RX_vect() {
}
extern "C" void foo() __attribute__(());
void foo() {
}
int main() {
return 0;
} Makefile: #CC=/usr/bin/avr-gcc
CC=~/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc
test: main.cpp Makefile
$(CC) -v -flto -Os -g -mmcu=atmega2560 $< -o $@ |
My library contains serial communication function calls referring to HardwareSerial (not included at the level of my library) and when I include my aforementioned library, program memory and global registers related to HardwareSerial are used even though none of the functions in my library which specifically use serial communication are actually used.
Here is part of the .cpp file from my library in question:
The text was updated successfully, but these errors were encountered: