Skip to content
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

Library uses substantially more storage than PrintEx? #1

Closed
scottchiefbaker opened this issue Apr 30, 2020 · 13 comments
Closed

Library uses substantially more storage than PrintEx? #1

scottchiefbaker opened this issue Apr 30, 2020 · 13 comments

Comments

@scottchiefbaker
Copy link
Contributor

I use PrintEx in a lot of my projects, but it's not maintained any more (last update was 2016). Researching your printf() implementation looks promising but it uses a significant amount of storage.

Any idea why this implementation is so much larger?

PrintEx

Sketch uses 5486 bytes (17%) of program storage space. Maximum is 32256 bytes.
Global variables use 264 bytes (12%) of dynamic memory, leaving 1784 bytes for local variables. Maximum is 2048 bytes.

arduino-printf

Sketch uses 9876 bytes (30%) of program storage space. Maximum is 32256 bytes.
Global variables use 254 bytes (12%) of dynamic memory, leaving 1794 bytes for local variables. Maximum is 2048 bytes.
@phillipjohnston
Copy link
Member

Hello Scott,

Thanks for writing in and sending a size comparison. This library is merely a wrapper around mpaland/printf, so the sizing is determined by that library's implementation.

I notice a few things in my testing and reading:

  1. Exponential formatting is enabled in this library by default, but doesn't seem to be used in PrintEx. Disabling this support by defining PRINTF_DISABLE_SUPPORT_EXPONENTIAL saves 1764 bytes in my test case.
  2. PrintEx tops out at 32 bit integers, while "long long" support is enabled in this library by default. Disabling support by defining PRINTF_DISABLE_SUPPORT_LONG_LONG saves 1266 bytes in my test case
  3. Disabling these two options together gets us closer to the PrintEx numbers, although we're still +~1400 bytes
  4. If you're not using floats, disabling floating-point support by defining PRINTF_DISABLE_SUPPORT_FLOAT saves a whopping 4,044 byes. Disabling all three of the above options saves 5220 bytes.

The PrintEx library is a custom wrapper around the Print class, while mpaland/printf is written to the C standard. From PrintEx:

The printf implementation found in this library is unique. It has been built directly on top of the Arduino Print library rather than as a separate code base simply called from within. All the features found in printf use a feature already implemented in Print.

It could very well be that there are differences in the two implementations accounting for the remaining size difference, such as additional format flags implemented in mpaland/printf that aren't used in PrintEx.

It could also be that the optimizer is better able to work with the PrintEx inheritance structure. This printf library is standalone and is only tied to the Print class through the default implementation of _putchar.

@phillipjohnston
Copy link
Member

I'll also add this information to the README, seems useful to note in general.

@scottchiefbaker
Copy link
Contributor Author

Thank you for the the very detailed write up. This was by no means meant to disparage this library, I'm just trying to find a good replacement for PrintEx. I love the idea that this has no dependencies and is super simple. On an MCU that's pretty important.

I think the options you mentioned above sound promising. I definitely need floating point support as that was the main reason I need a printf() implementation. The other two are certainly less common. I'm not sure how I disable them though. If I include

#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL

The output size of my sketch doesn't change. Am I missing something here?

@scottchiefbaker
Copy link
Contributor Author

scottchiefbaker commented Apr 30, 2020

Just for posterity here are my initial findings. Using vanilla options for both libraries on my PrintfTest.ino I get:

Type Bytes
No Serial 1606
PrintEx 5056
arduino-printf 9476

@phillipjohnston
Copy link
Member

No disparagement perceived! It's a reasonable question worth exploring.

Due to the design of the mpaland/printf library, these definitions must come from the compiler, rather than defining that before the header. I'll work with the library author on that, as it would be convenient to define them before including the header to control behavior.

If you're using a Makefile or other build system, you'd use the -D flag (e.g., -D PRINTF_DISABLE_SUPPORT_EXPONENTIAL) to add the necessary variables/commands.

For Arduino IDE, the flags need to be added to the compiler.extra_flags property in platform.txt or platform.local.txt. You would need to restart the IDE for the changes to take effect.

I believe that you can also use the Arduino CLI to control preferences. Some notes: https://forum.arduino.cc/index.php?topic=537500.0

(Will also update the README with better notes on this)

@scottchiefbaker
Copy link
Contributor Author

scottchiefbaker commented Apr 30, 2020

If I disable long long support, and exponential I get:

Type Bytes
No Serial 1606
PrintEx 5056
arduino-printf 6328

Which is a lot more reasonable. It would be great if you could disable these at compile time with a #define instead of having to use -D which is a pain.

Or perhaps better yet, they could default to disabled on an AVR based MCUs, and enabled on bigger more capable boards? I feel like the use case for needing 64 bit ints, and exponents on AVR boards is going to be pretty minimal.

My compile command was:

arduino --verify --pref build.extra_flags="-DPRINTF_DISABLE_SUPPORT_EXPONENTIAL -DPRINTF_DISABLE_SUPPORT_LONG_LONG" --pref build.path=/tmp/arduino-build-PrintfTest/ --port /dev/ttyUSB0 --board arduino:avr:uno /home/bakers/Arduino/PrintfTest/PrintfTest.ino

@phillipjohnston
Copy link
Member

That's a reasonable request. I'll modify the library source here and work on improvements with the primary project separately.

@scottchiefbaker
Copy link
Contributor Author

Sounds good. I look forward to testing it.

@scottchiefbaker
Copy link
Contributor Author

scottchiefbaker commented May 1, 2020

I just found out (accidentally) that the ESP8266 and ESP32 Arduino implementations both implement printf()/sprintf() natively now. I'm not sure how well documented/publicized that is.

From my testing the ESP implementation of printf() supports: floating point, long longs, but not exponents.

It might be worth putting in your README.md. If you think it's worthy of mention I can submit a pull request for it.

@phillipjohnston
Copy link
Member

Definitely worth a note - happy to accept PRs.

@phillipjohnston
Copy link
Member

Do you know what header ESPxxx defines printf in? I'd like to take a look at what they're doing in the context of another library (arduino-logger)

@scottchiefbaker
Copy link
Contributor Author

@phillipjohnston I'm not a C++ expert, it's hard to tell where it gets defined. I think it's here:

https://github.com/esp8266/Arduino/blob/master/cores/esp8266/Print.h#L78

@scottchiefbaker
Copy link
Contributor Author

Digging a little deeper I think it's here actually:

https://github.com/esp8266/Arduino/blob/master/cores/esp8266/Print.cpp#L58

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants