Commit afbe7973 authored by Steven Rostedt (VMware)'s avatar Steven Rostedt (VMware)
Browse files

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: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent 720dee53
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -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);
		[..]
	}
+34 −0
Original line number Diff line number Diff line
@@ -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