-
Notifications
You must be signed in to change notification settings - Fork 3k
Remove debug links to printf/exit in NDEBUG builds #3881
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
Conversation
@geky by calling I'm favorable to such change but they are breaking changes for users and should be documented accordingly. |
platform/mbed_error.h
Outdated
mbed_error_vfprintf(format, arg); | ||
va_end(arg); | ||
#endif | ||
while (1) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This instead of exit()
- reason? I cant find it in the commit message.
We do not care what exit()
does? just a trap here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exit
flush the file standard IOs. Because exit
reference them, a lot of code from the IO subsystem is pulled in even if IOs function are not used directly in the actual program.
I've made a PR 6 month ago which address this issue: #2741 .
It allows user to disable flush of standard IOs in mbed_app.json.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if there is something better to do here, should I just call mbed_die?
Even with the change in #2741, the current definition of error is still preventing the format strings/arguments from being garbage collected by this compiler. This is ~1.5Kbytes of flash and grows with the number of calls to error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mbed_die still pulls in ~2Kbytes into the base image (for gpio to flash leds?).
I've changed error to still call exit in develop/release so streams are at least flushed while developing. This is a change between develop/debug, but it may be a worthwhile tradeoff for the space savings in the general case. Thoughts?
|
||
/** Output a debug message | ||
* | ||
* @param format printf-style format string, followed by variables | ||
*/ | ||
static inline void debug(const char *format, ...) { | ||
#if DEVICE_STDIO_MESSAGES && !defined(NDEBUG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking - is NDEBUG
defined in the default profile = not breaking for mbed 2 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NDEBUG is not defined in the default profile, not sure how that affects mbed 2
https://github.com/ARMmbed/mbed-os/blob/master/tools/profiles/develop.json
platform/mbed_error.h
Outdated
@@ -60,7 +67,17 @@ | |||
extern "C" { | |||
#endif | |||
|
|||
void error(const char* format, ...); | |||
|
|||
static inline void error(const char *format, ...) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removes the ability for applications to substitute in their own error function.
how much do we gain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the footprint (additional 1.5k flash) with debug correctly optimized out and @pan-'s workaround for the fflushs in exit. There's no stdio being dragged in, but the format strings/arguments can't be garbage collected by the compiler:
+--------------------------+-------+-------+------+
| Module | .text | .data | .bss |
+--------------------------+-------+-------+------+
| Misc | 348 | 0 | 1024 |
| features/storage | 30 | 0 | 184 |
| hal | 232 | 8 | 0 |
| platform | 188 | 16 | 0 |
| rtos | 36 | 8 | 0 |
| rtos/rtx | 5766 | 100 | 6764 |
| targets/TARGET_Freescale | 4712 | 92 | 112 |
| Subtotals | 11312 | 224 | 8084 |
+--------------------------+-------+-------+------+
Note: The savings difference grow with the more calls to error
Agreed, is there additional documentation we should add besides updating the doxygen for error? (Should this be a part of the next minor release?) |
@geky Getting a linking error: |
db6b73c
to
74ee476
Compare
@tommikas, thanks for reporting that! I've added a bit of a hacky workaround to provide external linkage to the error function for backwards compatiblity. It is still gced if unused. |
3f17cca
to
0f6945e
Compare
platform/mbed_error.c
Outdated
// Workaround to provide an externally linkable error function for binary | ||
// compatiblity with precompiled libraries. Will be gced by compiler if | ||
// not used at link time. Tiny bit hacky. | ||
#define static extern |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think we should allow this in our codebase. If linker is not smart enough, complain there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quoting the spec:
2 A translation unit shall not #define or #undef names lexically identical to keywords.
@geky I can't reproduce your results on your application which does something. "platform.stdio-flush-at-exit": false, NDEBUG defined, mbed-os-5.4.0
"platform.stdio-flush-at-exit": false, NDEBUG defined, mbed-os-5.4.0 + this PR
If I use an empty main rather than blinky the results are different and match yours: "platform.stdio-flush-at-exit": false, NDEBUG defined, mbed-os-5.4.0
"platform.stdio-flush-at-exit": false, NDEBUG defined, mbed-os-5.4.0 + this PR
Same results can be obtained without this patch just by redefining
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to keep the NDEBUG
exclusion in mbed_debug.h
.
I believe the rest of the patch is not needed/desirable:
- inlining of
error
forbid user code to redefine their own error code and might break existing applications. - not calling
mbed_die
in case of error will not help users which might want visible sign that something went wrong.
The optimization is a side effect of not calling this function. - The system is already flexible enough,
mbed_die
anderror
can be redefined in user application.
Thanks for waiting for my late response again. @pan-'s right that we have a workaround for this extra code size The asymmetry between I'll limit the |
@geky I must have miss something but what kind of consistency or symmetry do you want for |
Sorry about the delay. It just doesn't sit well that debug is an inlined function and error is a weak function. A user may see that they can overload error and try to overload debugging for their own logging. Perhaps Also I removed the |
@pan- Do you approve? |
@@ -244,7 +244,7 @@ void os_idle_demon (void) { | |||
/*---------------------------------------------------------------------------- | |||
* RTX Errors | |||
*---------------------------------------------------------------------------*/ | |||
extern void error(const char* format, ...); | |||
#include "mbed_error.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inclusion should be grouped with others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can update 👍
b6e9702
to
27f4bfc
Compare
retest uvisor |
@geky can we please update the PR title and description to be clear about what this PR is now changing and why? Thanks |
Allows development of small applications where stdio is avoided
Should be updated |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
OutputAll builds and test passed! |
ok by me |
…lwip_broadcast Release mbed OS 5.4.5 and mbed lib v142 Ports for Upcoming Targets Fixes and Changes 4059: [Silicon Labs] Rename targets ARMmbed#4059 4115: Support for Qt Creator Generic project export and associated Makefile ARMmbed#4115 3915: Feature vscode ARMmbed#3915 4205: tests: race test - add not supported for single threaded env ARMmbed#4205 4187: [NCS36510] Reduce default heap size allocated by IAR to 1/4 of RAM ARMmbed#4187 4145: test - add nanostack to examples.json file ARMmbed#4145 4093: Update.py: New feature - update a branch instead of a fork, plus general improvements. ARMmbed#4093 4225: fixed missing device_name for xDot and removed progen ARMmbed#4225 4243: Config: config header file should contain new line ARMmbed#4243 4251: Fix C++11 build error w/ u-blox EVK-ODIN-W2 ARMmbed#4251 4236: STM32 Fixed warning related to __packed redefinition ARMmbed#4236 4224: Add `mbed new .` output to export ARMmbed#4224 4190: LPC4088: Enable LWIP feature ARMmbed#4190 4136: Error when bootloader is specified but does not exist ARMmbed#4136 3881: Remove debug links to printf/exit in NDEBUG builds ARMmbed#3881 4260: Inherit Xadow M0 target from LPC11U35_501 ARMmbed#4260 4249: Add consistent button names across targets ARMmbed#4249 4254: Removed unused variable in TARGET_NXP/lpc17_emac.c ARMmbed#4254
Allows development of small applications where stdio is avoided, also optimizes out debug strings and format arguments.
Biggest change is thatexit
is no longer called. Not sure if that's important (destructors?).Another change to note is that the linkage oferror
is now the same asdebug
(always inlined). This is important to optimize out error strings, but removes the ability for applications to substitute in their own error function.EDIT: Only debug is optimized out now. As @pan- pointed out, error can be removed by redefining the function in user code. There's no real benefit to optimizing out error except for consistency, but that comes at the cost of preventing users from redefining the error function. An update to the error function can come at a later date if we find it necessary.
Bare main before (ARM, K64F):
Bare main after (ARM, K64F):
cc @pan-, @0xc0170