tracing: Add trace_<tracepoint>_enabled() function
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>
Tue, 6 May 2014 13:26:30 +0000 (09:26 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Wed, 7 May 2014 16:10:51 +0000 (12:10 -0400)
There are some code paths in the kernel that need to do some preparations
before it calls a tracepoint. As that code is worthless overhead when
the tracepoint is not enabled, it would be prudent to have that code
only run when the tracepoint is active. To accomplish this, all tracepoints
now get a static inline function called "trace_<tracepoint-name>_enabled()"
which returns true when the tracepoint is enabled and false otherwise.

As an added bonus, that function uses the static_key of the tracepoint
such that no branch is needed.

  if (trace_mytracepoint_enabled()) {
arg = process_tp_arg();
trace_mytracepoint(arg);
  }

Will keep the "process_tp_arg()" (which may be expensive to run) from
being executed when the tracepoint isn't enabled.

It's best to encapsulate the tracepoint itself in the if statement
just to keep races. For example, if you had:

  if (trace_mytracepoint_enabled())
arg = process_tp_arg();
  trace_mytracepoint(arg);

There's a chance that the tracepoint could be enabled just after the
if statement, and arg will be undefined when calling the tracepoint.

Link: http://lkml.kernel.org/r/20140506094407.507b6435@gandalf.local.home
Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Documentation/trace/tracepoints.txt
include/linux/tracepoint.h

index 6b018b53177aa7ee499b5adb0e95d52e2e92d9ee..a3efac621c5ad59e50167345cd4ce48538fc6ddf 100644 (file)
@@ -115,6 +115,30 @@ If the tracepoint has to be used in kernel modules, an
 EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be
 used to export the defined tracepoints.
 
+If you need to do a bit of work for a tracepoint parameter, and
+that work is only used for the tracepoint, that work can be encapsulated
+within an if statement with the following:
+
+       if (trace_foo_bar_enabled()) {
+               int i;
+               int tot = 0;
+
+               for (i = 0; i < count; i++)
+                       tot += calculate_nuggets();
+
+               trace_foo_bar(tot);
+       }
+
+All trace_<tracepoint>() calls have a matching trace_<tracepoint>_enabled()
+function defined that returns true if the tracepoint is enabled and
+false otherwise. The trace_<tracepoint>() should always be within the
+block of the if (trace_<tracepoint>_enabled()) to prevent races between
+the tracepoint being enabled and the check being seen.
+
+The advantage of using the trace_<tracepoint>_enabled() is that it uses
+the static_key of the tracepoint to allow the if statement to be implemented
+with jump labels and avoid conditional branches.
+
 Note: The convenience macro TRACE_EVENT provides an alternative way to
       define tracepoints. Check http://lwn.net/Articles/379903,
       http://lwn.net/Articles/381064 and http://lwn.net/Articles/383362
index 9d30ee469c2aed19e9444de08ba37b0978bd1a27..2e2a5f7717e5e56870c58f6ec97021dadf4f72ca 100644 (file)
@@ -185,6 +185,11 @@ extern void syscall_unregfunc(void);
        static inline void                                              \
        check_trace_callback_type_##name(void (*cb)(data_proto))        \
        {                                                               \
+       }                                                               \
+       static inline bool                                              \
+       trace_##name##_enabled(void)                                    \
+       {                                                               \
+               return static_key_false(&__tracepoint_##name.key);      \
        }
 
 /*
@@ -230,6 +235,11 @@ extern void syscall_unregfunc(void);
        }                                                               \
        static inline void check_trace_callback_type_##name(void (*cb)(data_proto)) \
        {                                                               \
+       }                                                               \
+       static inline bool                                              \
+       trace_##name##_enabled(void)                                    \
+       {                                                               \
+               return false;                                           \
        }
 
 #define DEFINE_TRACE_FN(name, reg, unreg)