-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
[RFC][DNM] logging: subsystem major redesign #7992
Conversation
Adding new implementation of logging subsystem. New features includes: support for multiple backends, improving performance by deferring log processing to the known context, adding timestamps and logs filtering options (compile time, runtime, module level, instance level). Console backend added as the example backend. Signed-off-by: Krzysztof Chruściński <[email protected]>
cc: @pizi-nordic |
CC: @nashif @carlescufi |
static u32_t timestamp_get() | ||
{ | ||
#ifdef CONFIG_SOC_FAMILY_NRF | ||
return NRF_RTC1->COUNTER; |
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.
why? k_cycle_get_32() works on Nordic devices as well
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.
It does but it is very slow (see _timer_cycle_get_32 in nrf_rtc_timer.c). It temporary, wanted to use it to achieve expected performance. Hopefully, nordic implementation of cycle_get will get improved.
static u32_t timestamp_freq() | ||
{ | ||
#ifdef CONFIG_SOC_FAMILY_NRF | ||
return 32768 / (NRF_RTC1->PRESCALER + 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.
same, why special cases for Nordic in a common file?
@@ -0,0 +1,44 @@ | |||
Title: Log list |
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.
You should use .rst for documentation
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 removed the file. Imo, there is not much value added by keeping this file. Added it because logger-hook had it but i see that most of the tests do not have this file.
This project outputs to the console. It can be built and executed | ||
on QEMU as follows: | ||
|
||
make run |
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 is out of date, there should be CMake here. Also please use .. zephyr-app-commands::
for this
|
||
-------------------------------------------------------------------------------- | ||
|
||
Troubleshooting: |
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.
Same, this needs rewriting
@@ -0,0 +1,52 @@ | |||
Title: Log message test |
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.
see comments above for the README file format
void test_main(void) | ||
{ | ||
ztest_test_suite(test_log_message, | ||
// ztest_unit_test(test_log_std_msg), |
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.
why is this disabled?
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.
Accident, re-enabled.
@nordic-krch thanks for this PR! I tried running this on an nRF52832 devkit with |
Codecov Report
@@ Coverage Diff @@
## master #7992 +/- ##
==========================================
+ Coverage 55.03% 77% +21.96%
==========================================
Files 481 10 -471
Lines 53936 274 -53662
Branches 10474 30 -10444
==========================================
- Hits 29686 211 -29475
+ Misses 19981 43 -19938
+ Partials 4269 20 -4249 Continue to review full report at Codecov.
|
@nordic-krch I tested the |
|
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.
log_backend is windows formatted, i.e it has lots of ^M
@@ -14,7 +14,12 @@ | |||
{ | |||
SHELL_INIT_SECTIONS() | |||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) | |||
|
|||
|
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.
you have some whitespace noise 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.
Fixed
{ | ||
LOG_RAM_SECTIONS() | ||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) | ||
|
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.
and 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.
Fixed
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.
Not remotely done reading all of this. Haven't looked at micro-level complaints in the source at all.
I love the compressed log stream and the backend-agnostic API. I'm impressed by the linker and preprocessor magic.
Found at least two things that I think I hate, though. Am I missing something as to how these work?
* | ||
*/ | ||
#ifndef LOG_LEVEL | ||
#define LOG_SRC_LEVEL CONFIG_LOG_DEFAULT_LEVEL |
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.
Maybe call this "LOCAL" log level or something. "SRC" is a little confusing -- all logging comes from "source code".
Also: not a fan of "define this before including the file" preprocessor APIs. With a little care you can do something like IS_ENABLED() to test vs. symbols that may or may not be defined.
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 liked your suggestion to use something like IS_ENABLED() macro. Then we get rid of the requirement that local log level must be defined before including log.h.
'Source' meant module or instance (source of the log). I see that this is confusing. Maybe I will come with better name.
* @param ... A string optionally containing printk valid conversion specifier, | ||
* followed by as many values as specifiers. | ||
*/ | ||
#define LOG_ERR(...) LOG_INTERNAL_MODULE(LOG_LEVEL_ERR, __VA_ARGS__) |
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.
So... digging through all the levels of this API...
I think this is going to defeat the GCC built-in printf format string validation, right? The compiler never sees the format literal as a string passed to a function with atribute((format(printf...))), because it goes into a separate linker section.
If so, that's a pretty critical loss of functionality. That warning saves a ton of bugs that would otherwise never be noticed.
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.
Added empty, inline function log_printf_arg_checker() to be called in LOG_INTERNAL macro. This function has printf attribute. Compiler checking works with no performance penalty.
|
||
void log_1(const char *p_str, | ||
u32_t arg0, | ||
struct log_msg_ids src_level) |
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.
Wait, wait, wait. Wait. No, seriously, wait...
You have a staggeringly huge framework constructed of extraordinarily clever preprocessor code. It automatically detects the varargs structure of the logging used at runtime in order to correctly pack the right number of arguments into the highly compressed stream, so that the code just does the right thing without having to write out all the variants by hand. It probably does other stuff I haven't figured out yet.
But all that work just lands here in a bunch of hand-coded marshalling functions that need to duplicate all the work via separately-compiled (and thus big!) runtime code?
Why wasn't this whole mess just one C varargs function (with a little wrapper to put the format string into the right section, etc...) to begin with? Smaller, probably faster, MUCH simpler (seriously: it would cut hundreds on hundreds of lines out of the patch!).
I just don't get why you had to go through all the cpp and boilerplate hell just to get 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.
The goal was to have best performance possible. Vargs will add some additional cycles. I reused approach we had in logger in nRF5 SDK. Back then I was evaluating the cost of using vargs. I will try to get the numbers as the input for discussion.
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've tried to change log macro to build an array of arguments and pass that array to generic log_n() function. Log message is created with single function, etc. It takes 74 cycles more (296 vs. 222) to log typical message (string + 1 argument) on nrf52 (cortex m4, 64mhz). That's 30% worse. In my opinion, it's a significant penalty and I would stay with current solution.
* It's meant to report severe errors, such as those from which it's | ||
* not possible to recover. | ||
* | ||
* @param p_inst Pointer to the log filter associated with the instance. |
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 you please remove all the p_
and all other Hungarian notation prefixes? Zephyr doesn't use those and it collides with the rest of the code.
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.
Done
Adding new implementation of logging subsystem. New features
includes: support for multiple backends, improving performance
by deferring log processing to the known context, adding
timestamps and logs filtering options (compile time, runtime,
module level, instance level). Console backend added as the
example backend.
Implementation according to the design proposal made by @pizi-nordic in #6186 with one exception: in the proposal messages are stored in the ring buffer but in the implementation they are stored as linked list. Ring buffer requires fixed size where linked list does not.
Logger features:
Logger subsystem consists of following entities:
Logger API's:
PR contains:
Please add RFC and DNP labels.
Signed-off-by: Krzysztof Chruściński [email protected]