Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.arch.embedded > #27062 > unrolled thread

Efficient debug log

Started bypozz <pozzugno@gmail.com>
First post2017-07-20 11:31 +0200
Last post2017-07-31 16:44 +0000
Articles 15 — 7 participants

Back to article view | Back to comp.arch.embedded


Contents

  Efficient debug log pozz <pozzugno@gmail.com> - 2017-07-20 11:31 +0200
    Re: Efficient debug log Anders.Montonen@kapsi.spam.stop.fi.invalid - 2017-07-20 10:35 +0000
    Re: Efficient debug log Stef <stef33d@yahooI-N-V-A-L-I-D.com.invalid> - 2017-07-20 23:14 +0200
      Re: Efficient debug log David Brown <david.brown@hesbynett.no> - 2017-07-24 09:40 +0200
        Re: Efficient debug log pozz <pozzugno@gmail.com> - 2017-07-26 11:15 +0200
          Re: Efficient debug log David Brown <david.brown@hesbynett.no> - 2017-07-26 14:24 +0200
          Re: Efficient debug log Stef <stef33d@yahooI-N-V-A-L-I-D.com.invalid> - 2017-07-27 10:23 +0200
            Re: Efficient debug log David Brown <david.brown@hesbynett.no> - 2017-07-27 11:14 +0200
        Re: Efficient debug log Stef <stef33d@yahooI-N-V-A-L-I-D.com.invalid> - 2017-07-27 10:06 +0200
          Re: Efficient debug log David Brown <david.brown@hesbynett.no> - 2017-07-27 11:35 +0200
    Re: Efficient debug log Clifford Heath <no.spam@please.net> - 2017-07-21 12:57 +1000
    Re: Efficient debug log Jack <jack4747@gmail.com> - 2017-07-20 23:17 -0700
    Re: Efficient debug log Chris <xxx.syseng.yyy@gfsys.co.uk> - 2017-07-29 12:47 +0000
      Re: Efficient debug log pozz <pozzugno@gmail.com> - 2017-07-31 10:45 +0200
        Re: Efficient debug log Chris <xxx.syseng.yyy@gfsys.co.uk> - 2017-07-31 16:44 +0000

#27062 — Efficient debug log

Frompozz <pozzugno@gmail.com>
Date2017-07-20 11:31 +0200
SubjectEfficient debug log
Message-ID<okpt2m$sok$1@dont-email.me>
I usually prints some messages on a free UART used as a debug port. 
They are very useful during debugging to understand the flow of execution.

Most of the time, I don't compile the debug log facility in release build.

I sometimes need to disable messages from some modules and enable 
messages from other modules under debugging.
Moreover I sometimes need to enable/disable less important messages.

Do you suggest some efficient implementation of debug log macros that 
include all the features above?

[toc] | [next] | [standalone]


#27064

FromAnders.Montonen@kapsi.spam.stop.fi.invalid
Date2017-07-20 10:35 +0000
Message-ID<okq116$pfe$1@gioia.aioe.org>
In reply to#27062
pozz <pozzugno@gmail.com> wrote:

> I sometimes need to disable messages from some modules and enable 
> messages from other modules under debugging.
> Moreover I sometimes need to enable/disable less important messages.

Most logging systems use a priority parameter which can be used to mask 
less important messages. If you have fewer modules than bits in a word, 
you could also pass a module id parameter, and efficiently mask messages 
per-module.

-a

[toc] | [prev] | [next] | [standalone]


#27066

FromStef <stef33d@yahooI-N-V-A-L-I-D.com.invalid>
Date2017-07-20 23:14 +0200
Message-ID<nnd$5a9c0de5$7bdbc657@f8f0cd39675aa771>
In reply to#27062
On 2017-07-20 pozz wrote in comp.arch.embedded:
> I usually prints some messages on a free UART used as a debug port. 
> They are very useful during debugging to understand the flow of execution.
>
> Most of the time, I don't compile the debug log facility in release build.
>
> I sometimes need to disable messages from some modules and enable 
> messages from other modules under debugging.
> Moreover I sometimes need to enable/disable less important messages.
>
> Do you suggest some efficient implementation of debug log macros that 
> include all the features above?

If I have a output stream available for this purpose, I often use the
following (assuming you use C):

#ifdef DEBUG_ENABLE
#define DEBUG_PRINTF(level, ...) ((level) <= (DebugLevel) ? fprintf(stderr, __VA_ARGS__) : (level))
#else
#define DEBUG_PRINTF(level, ...)

Call like a normal printf, except there is an initial parameter for the 
level of that paticular call.

Lower the value of 'DebugLevel' to reduce the output.


-- 
Stef    (remove caps, dashes and .invalid from e-mail address to reply by mail)

A wise person makes his own decisions, a weak one obeys public opinion.
		-- Chinese proverb

[toc] | [prev] | [next] | [standalone]


#27071

FromDavid Brown <david.brown@hesbynett.no>
Date2017-07-24 09:40 +0200
Message-ID<ol482a$b09$1@dont-email.me>
In reply to#27066
On 20/07/17 23:14, Stef wrote:
> On 2017-07-20 pozz wrote in comp.arch.embedded:
>> I usually prints some messages on a free UART used as a debug port. 
>> They are very useful during debugging to understand the flow of execution.
>>
>> Most of the time, I don't compile the debug log facility in release build.
>>
>> I sometimes need to disable messages from some modules and enable 
>> messages from other modules under debugging.
>> Moreover I sometimes need to enable/disable less important messages.
>>
>> Do you suggest some efficient implementation of debug log macros that 
>> include all the features above?
> 
> If I have a output stream available for this purpose, I often use the
> following (assuming you use C):
> 
> #ifdef DEBUG_ENABLE
> #define DEBUG_PRINTF(level, ...) ((level) <= (DebugLevel) ? fprintf(stderr, __VA_ARGS__) : (level))
> #else
> #define DEBUG_PRINTF(level, ...)
> 
> Call like a normal printf, except there is an initial parameter for the 
> level of that paticular call.
> 
> Lower the value of 'DebugLevel' to reduce the output.
> 

Yes, something like that is the way to do it.  That means in the code
itself, you avoid having any extra "#ifdef DEBUG_ENABLE" conditional
compilation that /really/ messes up the readability of the code.  You
just use DEBUG_PRINTF, safe in the knowledge that it does nothing when
debugging is disabled.

The only unpleasant thing about this method is that if you have local
data that is only used for debugging, you are going to get warnings
about it when you disable debugging.  Since I like to have most of my
compiler warnings enabled, and like my code to be warning-free when
compiled, this bugs me.

So I have this definition:

static inline int emptyFunctionX(int x, ...) { (void) x; return 0; }
#define emptyFunction(...) emptyFunctionX(0, ## __VA_ARGS__)

Then when disabling debugging, I have:

#define debugPrintf emptyFunction

(I don't like defining a function as an expression in the way you did,
and I hate all-caps macro names for constants or function-like macros.)


"emptyFunction" uses a gcc extension here, but that's a common compiler
for many people.  It swallows any arguments without generating code, and
without requiring the arguments to be calculated at all (assuming you
have optimisation enabled), but considers the arguments "used" as far as
warnings are concerned.

[toc] | [prev] | [next] | [standalone]


#27074

Frompozz <pozzugno@gmail.com>
Date2017-07-26 11:15 +0200
Message-ID<ol9mbs$aq6$1@dont-email.me>
In reply to#27071
Il 24/07/2017 09:40, David Brown ha scritto:
> On 20/07/17 23:14, Stef wrote:
>> On 2017-07-20 pozz wrote in comp.arch.embedded:
>>> I usually prints some messages on a free UART used as a debug port.
>>> They are very useful during debugging to understand the flow of execution.
>>>
>>> Most of the time, I don't compile the debug log facility in release build.
>>>
>>> I sometimes need to disable messages from some modules and enable
>>> messages from other modules under debugging.
>>> Moreover I sometimes need to enable/disable less important messages.
>>>
>>> Do you suggest some efficient implementation of debug log macros that
>>> include all the features above?
>>
>> If I have a output stream available for this purpose, I often use the
>> following (assuming you use C):
>>
>> #ifdef DEBUG_ENABLE
>> #define DEBUG_PRINTF(level, ...) ((level) <= (DebugLevel) ? fprintf(stderr, __VA_ARGS__) : (level))
>> #else
>> #define DEBUG_PRINTF(level, ...)
>>
>> Call like a normal printf, except there is an initial parameter for the
>> level of that paticular call.
>>
>> Lower the value of 'DebugLevel' to reduce the output.
>>
> 
> Yes, something like that is the way to do it.  That means in the code
> itself, you avoid having any extra "#ifdef DEBUG_ENABLE" conditional
> compilation that /really/ messes up the readability of the code.  You
> just use DEBUG_PRINTF, safe in the knowledge that it does nothing when
> debugging is disabled.
> 
> The only unpleasant thing about this method is that if you have local
> data that is only used for debugging, you are going to get warnings
> about it when you disable debugging.  Since I like to have most of my
> compiler warnings enabled, and like my code to be warning-free when
> compiled, this bugs me.
> 
> So I have this definition:
> 
> static inline int emptyFunctionX(int x, ...) { (void) x; return 0; }
> #define emptyFunction(...) emptyFunctionX(0, ## __VA_ARGS__)
> 
> Then when disabling debugging, I have:
> 
> #define debugPrintf emptyFunction
> 
> (I don't like defining a function as an expression in the way you did,
> and I hate all-caps macro names for constants or function-like macros.)
> 
> 
> "emptyFunction" uses a gcc extension here, but that's a common compiler
> for many people.  It swallows any arguments without generating code, and
> without requiring the arguments to be calculated at all (assuming you
> have optimisation enabled), but considers the arguments "used" as far as
> warnings are concerned.

As usual, thanks for the interesting tricks, David.


If I understood correctly:

#include "debug.h"  // Where is debugPrintf, emptyFunction, ...
static int var_used_only_in_debug;
...
debug_printf(10, "The value is %d\n", var_used_only_in_debug);

The compilation doesn't emit warnings (regarding unused static 
variables) and doesn't really allocate space for var_used_only_in_debug 
(thanks to optimization).


This should work for functions too:

#include "debug.h"
static const char *fun_used_only_in_debug(int arg);
...
debug_printf(10, "The name is %s\n", fun_used_only_in_debug(value));
...
static const char *fun_used_only_in_debug(int arg) {
    if (arg == 3) return "Three";
    if (arg == 3) return "Four";
    ...
}

In this case, the function isn't included in the output file (thanks to 
optimization).


I have another situation. I want to include a member in a structure, but 
it's only used in debug. This member is used only in debug_printf calls, 
so it can be omitted in the Release build. If I use #ifdef DEBUG_ENABLE 
#endif to avoid including the member, I will have an error during build 
(because debug_print refers to a member that doesn't exist).
If I leave the member in the structure in Release build, I will waste 
some space.

Is there a trick to solve this problem?

[toc] | [prev] | [next] | [standalone]


#27075

FromDavid Brown <david.brown@hesbynett.no>
Date2017-07-26 14:24 +0200
Message-ID<ola1er$ets$1@dont-email.me>
In reply to#27074
On 26/07/17 11:15, pozz wrote:
> Il 24/07/2017 09:40, David Brown ha scritto:
>> On 20/07/17 23:14, Stef wrote:
>>> On 2017-07-20 pozz wrote in comp.arch.embedded:
>>>> I usually prints some messages on a free UART used as a debug port.
>>>> They are very useful during debugging to understand the flow of
>>>> execution.
>>>>
>>>> Most of the time, I don't compile the debug log facility in release
>>>> build.
>>>>
>>>> I sometimes need to disable messages from some modules and enable
>>>> messages from other modules under debugging.
>>>> Moreover I sometimes need to enable/disable less important messages.
>>>>
>>>> Do you suggest some efficient implementation of debug log macros that
>>>> include all the features above?
>>>
>>> If I have a output stream available for this purpose, I often use the
>>> following (assuming you use C):
>>>
>>> #ifdef DEBUG_ENABLE
>>> #define DEBUG_PRINTF(level, ...) ((level) <= (DebugLevel) ?
>>> fprintf(stderr, __VA_ARGS__) : (level))
>>> #else
>>> #define DEBUG_PRINTF(level, ...)
>>>
>>> Call like a normal printf, except there is an initial parameter for the
>>> level of that paticular call.
>>>
>>> Lower the value of 'DebugLevel' to reduce the output.
>>>
>>
>> Yes, something like that is the way to do it.  That means in the code
>> itself, you avoid having any extra "#ifdef DEBUG_ENABLE" conditional
>> compilation that /really/ messes up the readability of the code.  You
>> just use DEBUG_PRINTF, safe in the knowledge that it does nothing when
>> debugging is disabled.
>>
>> The only unpleasant thing about this method is that if you have local
>> data that is only used for debugging, you are going to get warnings
>> about it when you disable debugging.  Since I like to have most of my
>> compiler warnings enabled, and like my code to be warning-free when
>> compiled, this bugs me.
>>
>> So I have this definition:
>>
>> static inline int emptyFunctionX(int x, ...) { (void) x; return 0; }
>> #define emptyFunction(...) emptyFunctionX(0, ## __VA_ARGS__)
>>
>> Then when disabling debugging, I have:
>>
>> #define debugPrintf emptyFunction
>>
>> (I don't like defining a function as an expression in the way you did,
>> and I hate all-caps macro names for constants or function-like macros.)
>>
>>
>> "emptyFunction" uses a gcc extension here, but that's a common compiler
>> for many people.  It swallows any arguments without generating code, and
>> without requiring the arguments to be calculated at all (assuming you
>> have optimisation enabled), but considers the arguments "used" as far as
>> warnings are concerned.
> 
> As usual, thanks for the interesting tricks, David.
> 
> 
> If I understood correctly:
> 
> #include "debug.h"  // Where is debugPrintf, emptyFunction, ...
> static int var_used_only_in_debug;
> ...
> debug_printf(10, "The value is %d\n", var_used_only_in_debug);
> 
> The compilation doesn't emit warnings (regarding unused static
> variables) and doesn't really allocate space for var_used_only_in_debug
> (thanks to optimization).
> 

Yes.

In most such debug calls, you are just showing existing data, so it
makes little difference.  But sometimes you might want to manipulate
something or make new local data before printing it.

> 
> This should work for functions too:
> 
> #include "debug.h"
> static const char *fun_used_only_in_debug(int arg);
> ...
> debug_printf(10, "The name is %s\n", fun_used_only_in_debug(value));
> ...
> static const char *fun_used_only_in_debug(int arg) {
>    if (arg == 3) return "Three";
>    if (arg == 3) return "Four";
>    ...
> }
> 
> In this case, the function isn't included in the output file (thanks to
> optimization).

Yes.

Note that this will only apply if the compiler knows it is safe to skip
the function call - either because it has the definition of the function
on hand and can see it (such as in this case), or because you have told
it is safe (such as by using the "const" or "pure" function attributes
in gcc).

> 
> 
> I have another situation. I want to include a member in a structure, but
> it's only used in debug. This member is used only in debug_printf calls,
> so it can be omitted in the Release build. If I use #ifdef DEBUG_ENABLE
> #endif to avoid including the member, I will have an error during build
> (because debug_print refers to a member that doesn't exist).
> If I leave the member in the structure in Release build, I will waste
> some space.
> 
> Is there a trick to solve this problem?

That is a very interesting question.  I hadn't thought about this
before, but I've got an answer for you:


#define enableDebugging

static inline int emptyFunctionX(int x, ...) { (void) x; return 0; }
#define emptyFunction(...) emptyFunctionX(0, ## __VA_ARGS__)


typedef struct {} empty_t;

#ifdef enableDebugging
  extern int debugPrintf(const char *format, ...)
      __attribute__ ((format (printf, 1, 2)));
  #define debugField(T) T
#else
  #define debugPrintf emptyFunction
  #define debugField(T) empty_t
#endif

typedef struct {
    int a;
    int b;
    debugField(int) debug;
} data_t;
data_t data;

int sizeofData(void) {
    return sizeof(data_t);
}

int foo(void) {
    data.a += data.b;
    debugPrintf("%i %i %i", data.a, data.b, data.debug);
    return data.a;
}



I tested this using the online compiler at <https://godbolt.org>.  Copy
and paste it in, using whatever compiler version you like (gcc or clang,
because of the __attribute__).

Use "-Wall -Wextra -std=c11 -O1 -x c" as the command line options ("-x
c" makes gcc compile C, rather than the default C++ for the tools used
by the site).

You can see the real size of the "data_t" struct from the assembly code
generated for "sizeofData" - a field of type "empty_t" takes no space,
but avoids the error when it is used in the disabled debugPrintf call.

However, note that a struct with no members is invalid in strict ISO C.
 gcc is happy with it, but if you use -Wpedantic or use another compiler
you may get warnings or errors.


The code here also shows how to use the "format" attribute to get
checking of the types in the debugPrintf call.  Try changing one of the
%i to %s, and look at the warnings (they will only be checked when
debugging is enabled, but you can't have everything!)

[toc] | [prev] | [next] | [standalone]


#27077

FromStef <stef33d@yahooI-N-V-A-L-I-D.com.invalid>
Date2017-07-27 10:23 +0200
Message-ID<nnd$38a3e4a4$53074aad@b171b2391b83fd0d>
In reply to#27074
On 2017-07-26 pozz wrote in comp.arch.embedded:
>
> I have another situation. I want to include a member in a structure, but 
> it's only used in debug. This member is used only in debug_printf calls, 
> so it can be omitted in the Release build. If I use #ifdef DEBUG_ENABLE 
> #endif to avoid including the member, I will have an error during build 
> (because debug_print refers to a member that doesn't exist).
> If I leave the member in the structure in Release build, I will waste 
> some space.
>
> Is there a trick to solve this problem?

I often find this "waste of space" argument a bit irrelevant. On large
targets, the few extra bytes usually don't matter at all. On small targets,
the space argument may seem valid. But often, you want to be able to run
the debug version on the same target as the release version. This means
the target must have space for this data and that this space will simply
be vacant if you have a release version with the data removed.

There is even a danger of expanding the code in release mode and then
finding it does not fit anymore when you need to switch back to debug.

But there may be situations where you have a special (larger) target for
debug than is used for the release. Or situations where you have to store
or transmit binaries and space is tight or expensive.

So for these situations (or others, or just for the fun of it), I do find
Davids exercise in the other reply very interesting.


-- 
Stef    (remove caps, dashes and .invalid from e-mail address to reply by mail)

"Can you program?"  "Well, I'm literate, if that's what you mean!"

[toc] | [prev] | [next] | [standalone]


#27078

FromDavid Brown <david.brown@hesbynett.no>
Date2017-07-27 11:14 +0200
Message-ID<olcam4$4oo$1@dont-email.me>
In reply to#27077
On 27/07/17 10:23, Stef wrote:
> On 2017-07-26 pozz wrote in comp.arch.embedded:
>>
>> I have another situation. I want to include a member in a structure, but 
>> it's only used in debug. This member is used only in debug_printf calls, 
>> so it can be omitted in the Release build. If I use #ifdef DEBUG_ENABLE 
>> #endif to avoid including the member, I will have an error during build 
>> (because debug_print refers to a member that doesn't exist).
>> If I leave the member in the structure in Release build, I will waste 
>> some space.
>>
>> Is there a trick to solve this problem?
> 
> I often find this "waste of space" argument a bit irrelevant. On large
> targets, the few extra bytes usually don't matter at all. On small targets,
> the space argument may seem valid. But often, you want to be able to run
> the debug version on the same target as the release version. This means
> the target must have space for this data and that this space will simply
> be vacant if you have a release version with the data removed.
> 
> There is even a danger of expanding the code in release mode and then
> finding it does not fit anymore when you need to switch back to debug.
> 
> But there may be situations where you have a special (larger) target for
> debug than is used for the release. Or situations where you have to store
> or transmit binaries and space is tight or expensive.
> 
> So for these situations (or others, or just for the fun of it), I do find
> Davids exercise in the other reply very interesting.
> 

When working with very small systems, it is not uncommon to use a larger
or faster device for prototyping, testing, etc., and then a cost-optimal
device for mass production.  Sometimes that is just devices in the same
families with different memory sizes, but it could easily be that your
development and software testing is done mainly on an evaluation board
with a large chip, extra UARTs for debug output, etc., and the final
version will run on a different device.

Even when you have just a single device for everything, you may have
different balances.  Perhaps the release system will hold a log of the
last 24 hours of sensor values, while for debugging it is fine for the
log to be 6 hours and use the extra space for debugging information.

There are lots of possibilities here - even though you are right that
the space cost of an extra debug data item or two is rarely significant.

[toc] | [prev] | [next] | [standalone]


#27076

FromStef <stef33d@yahooI-N-V-A-L-I-D.com.invalid>
Date2017-07-27 10:06 +0200
Message-ID<nnd$2c7d62f4$0355e474@d9499a4098fdcb40>
In reply to#27071
On 2017-07-24 David Brown wrote in comp.arch.embedded:
> On 20/07/17 23:14, Stef wrote:
>> On 2017-07-20 pozz wrote in comp.arch.embedded:
>>> I usually prints some messages on a free UART used as a debug port. 
>>> They are very useful during debugging to understand the flow of execution.
>>>
>>> Most of the time, I don't compile the debug log facility in release build.
>>>
>>> I sometimes need to disable messages from some modules and enable 
>>> messages from other modules under debugging.
>>> Moreover I sometimes need to enable/disable less important messages.
>>>
>>> Do you suggest some efficient implementation of debug log macros that 
>>> include all the features above?
>> 
>> If I have a output stream available for this purpose, I often use the
>> following (assuming you use C):
>> 
>> #ifdef DEBUG_ENABLE
>> #define DEBUG_PRINTF(level, ...) ((level) <= (DebugLevel) ? fprintf(stderr, __VA_ARGS__) : (level))
>> #else
>> #define DEBUG_PRINTF(level, ...)
>> 
>> Call like a normal printf, except there is an initial parameter for the 
>> level of that paticular call.
>> 
>> Lower the value of 'DebugLevel' to reduce the output.
>> 
>
> Yes, something like that is the way to do it.  That means in the code
> itself, you avoid having any extra "#ifdef DEBUG_ENABLE" conditional
> compilation that /really/ messes up the readability of the code.  You
> just use DEBUG_PRINTF, safe in the knowledge that it does nothing when
> debugging is disabled.
>
> The only unpleasant thing about this method is that if you have local
> data that is only used for debugging, you are going to get warnings
> about it when you disable debugging.  Since I like to have most of my
> compiler warnings enabled, and like my code to be warning-free when
> compiled, this bugs me.

This is true, but you could also argue that data only used for debugging
should be removed as well when debugging is disabled. That will require
inserting some additional #ifdefs in the code in places where debug-only
data is used.
But mostly, i use the construct to print values of variables that are in
use in normal code. And most often de DEBUG_PRINTF is not disabled at all,
only the level lowered to a point where only things like startup and
critical messages are emitted.

> So I have this definition:
>
> static inline int emptyFunctionX(int x, ...) { (void) x; return 0; }
> #define emptyFunction(...) emptyFunctionX(0, ## __VA_ARGS__)
>
> Then when disabling debugging, I have:
>
> #define debugPrintf emptyFunction
>
> (I don't like defining a function as an expression in the way you did,
> and I hate all-caps macro names for constants or function-like macros.)

But this requires you to write an actual debugPrintf function to handle
the level comparison before calling the actual printf? But I look into
it, might be a better solution is some situations.
And i love all-caps macro names for constants or function-like macros ;-)

>
> "emptyFunction" uses a gcc extension here, but that's a common compiler
> for many people.  It swallows any arguments without generating code, and
> without requiring the arguments to be calculated at all (assuming you
> have optimisation enabled), but considers the arguments "used" as far as
> warnings are concerned.

Indeed a common compiler for me as well, but I have a few projects that
use other compilers.

-- 
Stef    (remove caps, dashes and .invalid from e-mail address to reply by mail)

Predestination was doomed from the start.

[toc] | [prev] | [next] | [standalone]


#27079

FromDavid Brown <david.brown@hesbynett.no>
Date2017-07-27 11:35 +0200
Message-ID<olcbta$891$1@dont-email.me>
In reply to#27076
On 27/07/17 10:06, Stef wrote:
> On 2017-07-24 David Brown wrote in comp.arch.embedded:
>> On 20/07/17 23:14, Stef wrote:
>>> On 2017-07-20 pozz wrote in comp.arch.embedded:
>>>> I usually prints some messages on a free UART used as a debug port. 
>>>> They are very useful during debugging to understand the flow of execution.
>>>>
>>>> Most of the time, I don't compile the debug log facility in release build.
>>>>
>>>> I sometimes need to disable messages from some modules and enable 
>>>> messages from other modules under debugging.
>>>> Moreover I sometimes need to enable/disable less important messages.
>>>>
>>>> Do you suggest some efficient implementation of debug log macros that 
>>>> include all the features above?
>>>
>>> If I have a output stream available for this purpose, I often use the
>>> following (assuming you use C):
>>>
>>> #ifdef DEBUG_ENABLE
>>> #define DEBUG_PRINTF(level, ...) ((level) <= (DebugLevel) ? fprintf(stderr, __VA_ARGS__) : (level))
>>> #else
>>> #define DEBUG_PRINTF(level, ...)
>>>
>>> Call like a normal printf, except there is an initial parameter for the 
>>> level of that paticular call.
>>>
>>> Lower the value of 'DebugLevel' to reduce the output.
>>>
>>
>> Yes, something like that is the way to do it.  That means in the code
>> itself, you avoid having any extra "#ifdef DEBUG_ENABLE" conditional
>> compilation that /really/ messes up the readability of the code.  You
>> just use DEBUG_PRINTF, safe in the knowledge that it does nothing when
>> debugging is disabled.
>>
>> The only unpleasant thing about this method is that if you have local
>> data that is only used for debugging, you are going to get warnings
>> about it when you disable debugging.  Since I like to have most of my
>> compiler warnings enabled, and like my code to be warning-free when
>> compiled, this bugs me.
> 
> This is true, but you could also argue that data only used for debugging
> should be removed as well when debugging is disabled. That will require
> inserting some additional #ifdefs in the code in places where debug-only
> data is used.

You certainly /can/ argue that.  It is not a good idea, usually, to have
code or data that is not in use.  It is a balance of choices, and you
have to pick the method that is clearest, most maintainable, and easiest
to be sure is correct.

> But mostly, i use the construct to print values of variables that are in
> use in normal code. And most often de DEBUG_PRINTF is not disabled at all,
> only the level lowered to a point where only things like startup and
> critical messages are emitted.
> 
>> So I have this definition:
>>
>> static inline int emptyFunctionX(int x, ...) { (void) x; return 0; }
>> #define emptyFunction(...) emptyFunctionX(0, ## __VA_ARGS__)
>>
>> Then when disabling debugging, I have:
>>
>> #define debugPrintf emptyFunction
>>
>> (I don't like defining a function as an expression in the way you did,
>> and I hate all-caps macro names for constants or function-like macros.)
> 
> But this requires you to write an actual debugPrintf function to handle
> the level comparison before calling the actual printf? But I look into
> it, might be a better solution is some situations.

I often have something like "debugPrintf" which would use snprintf to
put the formatted data into a buffer, then send it out on a UART.  It is
typically a good deal more efficient than using a library printf with a
fake file/stream output.

> And i love all-caps macro names for constants or function-like macros ;-)
> 

Many people use them.  Actually, I like that /other/ people use them,
such as in microcontroller peripheral definition headers - it means the
names don't conflict with my identifiers!

And I use all-caps for any macros that are passed via compiler command
lines (I don't use these much, but they can be a fine way to do parallel
builds of different variations of the same code).

But I have never been able to comprehend why someone would think you
should use all caps for:

#define SQRT2 1.4142135623730951

but not for

static const double sqrt2 = 1.4142135623730951;


Or why you should write:

#define VALID_PERCENT(x) (((x) >= 0) && ((x) <= 100))

and

static inline bool valid_percent(int x) {
	return ((x >= 0) && (x <= 100));
}


If the code that calls a "function" cares whether it is a real function
or a function-like macro, then that code is bad or the macro is bad.
Put braces on your if statements, put "do {...} while (0)" wrappers in
your multi-statement macros, never use expressions with side-effects in
your function arguments.


>>
>> "emptyFunction" uses a gcc extension here, but that's a common compiler
>> for many people.  It swallows any arguments without generating code, and
>> without requiring the arguments to be calculated at all (assuming you
>> have optimisation enabled), but considers the arguments "used" as far as
>> warnings are concerned.
> 
> Indeed a common compiler for me as well, but I have a few projects that
> use other compilers.
> 

Yes, me too.  I use gcc of preference whenever there is a choice - it is
one of the criteria I have for picking a microcontroller for a project.
 It is, in many ways, the best choice of tool for most of my work (I am
fully aware that one of the reasons gcc is a good choice for me is that
I use gcc so much).

If I have to use a different compiler, I will often also use gcc (for
any target) in parallel to do extra error checking.  Things like
__attributes__ are wrapped in conditional checks on __GNUC__.

[toc] | [prev] | [next] | [standalone]


#27067

FromClifford Heath <no.spam@please.net>
Date2017-07-21 12:57 +1000
Message-ID<g4ecB.95706$_25.60397@fx09.iad>
In reply to#27062
On 20/07/17 19:31, pozz wrote:
> I usually prints some messages on a free UART used as a debug port. They 
> are very useful during debugging to understand the flow of execution.
> 
> Most of the time, I don't compile the debug log facility in release build.
> 
> I sometimes need to disable messages from some modules and enable 
> messages from other modules under debugging.
> Moreover I sometimes need to enable/disable less important messages.
> 
> Do you suggest some efficient implementation of debug log macros that 
> include all the features above?

We used to use a 32-bit trace-control word with bit-fields assigned for
different subject areas. In large systems, 26 such words under letters
of the alphabet, so you could enable tracing e.g. "t0-3,c6", etc.

The trace function took a first argument that packed a letter and a
number (0..31) into 16 bits, which made it quick to check whether
that trace flag was enabled. printf-style string & varargs followed.
It also returned the "enabled" boolean, so you could avoid a code
path whose only purpose is to generate detailed tracing.

More recently (2005) I implemented an even more powerful system, but
it would only suit the largest embedded systems. It had an inlined
test for the trace class being enabled (less than 2ns if disabled,
after the first pass that bound the control variable), then queued
the control strings and parameters into a large shared memory buffer.
The buffer used lock-free synchronisation, so on normal Intel
hardware could achieve >1GBps. One or more trace consumer threads
could format the messages and write to a file, or send them over a
TCP link. This consumer thread also listened for local connection
requests so you could remotely enable and listen to tracing on a
program while it was already running.

So yeah, the sky is the limit as far as sophistication goes ;)

Clifford Heath.

[toc] | [prev] | [next] | [standalone]


#27068

FromJack <jack4747@gmail.com>
Date2017-07-20 23:17 -0700
Message-ID<110ff36d-122b-4d52-aa6a-a46d3fcba445@googlegroups.com>
In reply to#27062
Il giorno giovedì 20 luglio 2017 11:31:54 UTC+2, pozz ha scritto:
> I usually prints some messages on a free UART used as a debug port. 
> They are very useful during debugging to understand the flow of execution.
> 
> Most of the time, I don't compile the debug log facility in release build.
> 
> I sometimes need to disable messages from some modules and enable 
> messages from other modules under debugging.
> Moreover I sometimes need to enable/disable less important messages.
> 
> Do you suggest some efficient implementation of debug log macros that 
> include all the features above?

different #define for each module

#define UART_DEBUG
#define TIMER_DEBUG 
etc.

and the in the module

#ifdef UART_DEBUG
   printf("NO PANIC!! error on uart module")
#endif

You enable only the ones you want.
Or instead of defining in source code, you can use the -D directive of the compiler to enable/disable the debug parts.
Depending on your toolchain one could be easier than the other.

Bye Jack

[toc] | [prev] | [next] | [standalone]


#27088

FromChris <xxx.syseng.yyy@gfsys.co.uk>
Date2017-07-29 12:47 +0000
Message-ID<oli059$kqe$1@gioia.aioe.org>
In reply to#27062
On 07/20/17 09:31, pozz wrote:
> I usually prints some messages on a free UART used as a debug port. They
> are very useful during debugging to understand the flow of execution.
>
> Most of the time, I don't compile the debug log facility in release build.
>
> I sometimes need to disable messages from some modules and enable
> messages from other modules under debugging.
> Moreover I sometimes need to enable/disable less important messages.
>
> Do you suggest some efficient implementation of debug log macros that
> include all the features above?

For any system designed here, some sort of debug and
syslog is included at the design stage. To start, always
an led or two hanging off spare port lines, then a simple
class / value pair syslog facility, with an output to
leds or a uart.

A simple syslog can be implemented in less than a page of
code, with an array of structures for the subsystem class
and value pairs. Everything in the system that can have
an error condition or other useful info has an entry.

Trivial stuff really, but gets the job done...

Chris

[toc] | [prev] | [next] | [standalone]


#27092

Frompozz <pozzugno@gmail.com>
Date2017-07-31 10:45 +0200
Message-ID<olmqff$7mr$1@dont-email.me>
In reply to#27088
Il 29/07/2017 14:47, Chris ha scritto:
> On 07/20/17 09:31, pozz wrote:
>> I usually prints some messages on a free UART used as a debug port. They
>> are very useful during debugging to understand the flow of execution.
>>
>> Most of the time, I don't compile the debug log facility in release 
>> build.
>>
>> I sometimes need to disable messages from some modules and enable
>> messages from other modules under debugging.
>> Moreover I sometimes need to enable/disable less important messages.
>>
>> Do you suggest some efficient implementation of debug log macros that
>> include all the features above?
> 
> For any system designed here, some sort of debug and
> syslog is included at the design stage. To start, always
> an led or two hanging off spare port lines, then a simple
> class / value pair syslog facility, with an output to
> leds or a uart.
> 
> A simple syslog can be implemented in less than a page of
> code, with an array of structures for the subsystem class
> and value pairs. Everything in the system that can have
> an error condition or other useful info has an entry.
> 
> Trivial stuff really, but gets the job done...

Do you have a facility to disable (not present in the final binary) 
syslog messages from single modules?

Do you disable (as before) all the syslog feature in Release production?

Do you create messages in textual form (i.e. do you use printf-like 
functions)?

[toc] | [prev] | [next] | [standalone]


#27093

FromChris <xxx.syseng.yyy@gfsys.co.uk>
Date2017-07-31 16:44 +0000
Message-ID<olnmpf$1hvl$1@gioia.aioe.org>
In reply to#27092
On 07/31/17 08:45, pozz wrote:
On 07/31/17 08:45, pozz wrote:

 >
 > Do you have a facility to disable (not present in the final binary)
 > syslog messages from single modules?

Typically, no, since it can be useful for finding faults and form
the basis of a diagnostic for production and in field testing. If
you work it right, the overhead is minimal. If you want selective
reporting, define another member of the structure for each item to
enable or disable that or define the level, say from none to verbose.
Typically, the structure just carries a U32 count, but can be changed
to include strings etc. if i'm bringing a board up from cold, the
syslog stuff is the first to be built. That then provides built in
diagnostics as you bring up the hal layer for the other hardware and
peripherals.

 >
 > Do you create messages in textual form (i.e. do you use printf-like
 > functions)?

Depends on the system, but typically use as little of the C library as
possible. All the types are wrong etc. Instead, have a well proven
library of simple functions that print strings, convert between number
bases, read input etc. It gets added to over the years to provide
functionality. Of course, text output assumes a uart or other means
of accessing the messages, but the same ideas can be used to
provide flashing led sequences, whatever.

I guess what i'm saying is that I try to build some level of on board
diagnostics into every project from the start, whether or not it's in
the spec. It just makes life so much easier...

Chris

[toc] | [prev] | [standalone]


Back to top | Article view | comp.arch.embedded


csiph-web