tracepoints: Add helper to test if tracepoint is enabled in a header

As tracepoints are discouraged from being added in a header because it can
cause side effects if other tracepoints are in headers, as well as bloat the
kernel as the trace_<tracepoint>() function is not a small inline, the common
workaround is to add a function call that calls a wrapper function in a
C file that then calls the tracepoint. But as function calls add overhead,
this function should only be called when the tracepoint in question is
enabled. To get around this overhead, a static_branch can be used to only
have the tracepoint wrapper get called when the tracepoint is enabled.

Add a tracepoint_enabled(tp) macro that gets passed the name of the
tracepoint, and this becomes a static_branch that is enabled when the
tracepoint is enabled and is a nop when the tracepoint is disabled.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
Steven Rostedt (VMware) 2020-09-24 12:30:20 -04:00
parent 720dee53ad
commit afbe797317
2 changed files with 61 additions and 0 deletions

View File

@ -146,3 +146,30 @@ with jump labels and avoid conditional branches.
define tracepoints. Check http://lwn.net/Articles/379903,
http://lwn.net/Articles/381064 and http://lwn.net/Articles/383362
for a series of articles with more details.
If you require calling a tracepoint from a header file, it is not
recommended to call one directly or to use the trace_<tracepoint>_enabled()
function call, as tracepoints in header files can have side effects if a
header is included from a file that has CREATE_TRACE_POINTS set, as
well as the trace_<tracepoint>() is not that small of an inline
and can bloat the kernel if used by other inlined functions. Instead,
include tracepoint-defs.h and use tracepoint_enabled().
In a C file::
void do_trace_foo_bar_wrapper(args)
{
trace_foo_bar(args);
}
In the header file::
DECLARE_TRACEPOINT(foo_bar);
static inline void some_inline_function()
{
[..]
if (tracepoint_enabled(foo_bar))
do_trace_foo_bar_wrapper(args);
[..]
}

View File

@ -48,4 +48,38 @@ struct bpf_raw_event_map {
u32 writable_size;
} __aligned(32);
/*
* If a tracepoint needs to be called from a header file, it is not
* recommended to call it directly, as tracepoints in header files
* may cause side-effects and bloat the kernel. Instead, use
* tracepoint_enabled() to test if the tracepoint is enabled, then if
* it is, call a wrapper function defined in a C file that will then
* call the tracepoint.
*
* For "trace_foo_bar()", you would need to create a wrapper function
* in a C file to call trace_foo_bar():
* void do_trace_foo_bar(args) { trace_foo_bar(args); }
* Then in the header file, declare the tracepoint:
* DECLARE_TRACEPOINT(foo_bar);
* And call your wrapper:
* static inline void some_inlined_function() {
* [..]
* if (tracepoint_enabled(foo_bar))
* do_trace_foo_bar(args);
* [..]
* }
*
* Note: tracepoint_enabled(foo_bar) is equivalent to trace_foo_bar_enabled()
* but is safe to have in headers, where trace_foo_bar_enabled() is not.
*/
#define DECLARE_TRACEPOINT(tp) \
extern struct tracepoint __tracepoint_##tp
#ifdef CONFIG_TRACEPOINTS
# define tracepoint_enabled(tp) \
static_key_false(&(__tracepoint_##tp).key)
#else
# define tracepoint_enabled(tracepoint) false
#endif
#endif