-
Notifications
You must be signed in to change notification settings - Fork 3k
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
mbed requires use of printf/scanf through any use of Stream #4830
Comments
Another option to consider:
I was looking into this a while back, if you moved the all of the ties into printf into the Stream::printf function, it's theoretically possible for the compiler to drop the function when it's not used. I had a messy prototype put together, but haven't had the time to get it merge ready: To hopefully explain some of mbed's long-term direction, the biggest obstacle for mbed is backwards compatibility. We do our best to avoid breaking existing APIs without marking the APIs as deprecated for several releases. For this reason the development around the Stream class has been slow, and we're thinking the best plan is to move onto a different interface, potentially deprecating the Stream class in the future. Currently, we are looking at moving over the FileHandle interface for stream operations. As is, FileHandle is a minimal stream interface that doesn't bring in the printf/scanf code, while still being compatible with the stdio retargeting code. We currently have the classes RawSerial and UARTSerial, which are intended to replace Serial while only inheriting from FileHandle. If the seperate printf/scanf functions work out, they will probably be added to the FileHandle class. Unfortunately we haven't begun deprecating the Stream classes since we don't yet have a complete replacement. Deprecating the Stream class will also require deprecating the Serial class, which is a heavily used class. Sorry that I don't have a more straightforward explanation, it is quite a mess right now. Your pr will be a great addition for some immediate savings. For new code it would be a good idea to adopt FileHandle and RawSerial/UARTSerial where possible. |
Internal Jira reference: https://jira.arm.com/browse/IOTCORE-127 |
Thank you for raising this issue. Please note we have updated our policies and |
Description
Enhancement
Reason to enhance or problem with existing solution
scanf/printf can be heavyweight (nanolib takes >2.5kb in flash) and hard to optimize even when only used once due to source->static lib->source traversal.
When you use a Stream subclass (like Serial), here's what happens:
Stream::Stream() calls fdopen->mbed_fdopen
In mbed_retarget.cpp, mbed_fdopen() calls sprintf just to do ":%p" % this, then calls std::fopen, which eventually leads to _open, which calls sscanf to rip the pointer out of ":%p".
Suggested enhancement
Option A: optimize these specific uses of printf/scanf out.
printf: A simpler (computationally) way to calculate a buf that will be checked by _open is:
This saves ~3.3kB from my program, though I still have these symbols in my Map and I can't trace them any further: svfprintf, vfprintf, fseek, setvbuf.
Option B: Allow Serial to not support file-like operations (via define?, or a SerialLite?)
To compare apples to apples, I first wrote the following code to ensure I was linking everything in:
This uses the async
write()
code since the synchronouswrite()
is implemented byStream
. Then I removedStream
as a base class ofSerial
in both Serial.h and Serial.cpp. Compiling before and after that base class removal, I got a 5kB shrink in text (and 300 in bss because mbed_retarget's filehandles aren't linked in anymore).Pros
Both options can be done, though B is more intrusive and more work as it seems the purpose of Stream was to capitalize on the stdlib's implementations of fprintf, fflush, etc. However, for more production-worthy systems, being able to use Serial ports without linking in string-manipulation libraries and/or file-manipulation libraries means being able to put more code in the same microcontroller or to cost-down and use one with less flash (and less ram, etc).
Option A:
Option B:
Stream::printf
callsfprintf
synchronously, butSerialBase::write
is an async write, adding/movingStream::write
toSerialBase
or a newStreamLite
would giveSerial
a synchronous write that doesn't link in file handling.To be clear, I haven't thought through Option B, partly because I don't know mbed's long-term vision for
Serial
,Stream
, etc. I just know that ripping out file handling code brings my blinky+serial code down to ~15kB from ~23kB. While that's still really large for the functionality, it's mostly UART and RCC related plus 4 printf-related functions that I'll figure out some other way.Cons
Option A:
Option B:
Conclusion
I'll send a PR for Option A to discuss the exact implementation since that seems reasonable. For Option B, I'd like to hear your thoughts and see what path you would prefer.
The text was updated successfully, but these errors were encountered: