Commit c1df1bd2 authored by Mathieu Desnoyers's avatar Mathieu Desnoyers Committed by Ingo Molnar

markers: auto enable tracepoints (new API : trace_mark_tp())

Impact: new API

Add a new API trace_mark_tp(), which declares a marker within a
tracepoint probe. When the marker is activated, the tracepoint is
automatically enabled.

No branch test is used at the marker site, because it would be a
duplicate of the branch already present in the tracepoint.
Signed-off-by: default avatarMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent a419246a
...@@ -49,6 +49,8 @@ struct marker { ...@@ -49,6 +49,8 @@ struct marker {
void (*call)(const struct marker *mdata, void *call_private, ...); void (*call)(const struct marker *mdata, void *call_private, ...);
struct marker_probe_closure single; struct marker_probe_closure single;
struct marker_probe_closure *multi; struct marker_probe_closure *multi;
const char *tp_name; /* Optional tracepoint name */
void *tp_cb; /* Optional tracepoint callback */
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
#ifdef CONFIG_MARKERS #ifdef CONFIG_MARKERS
...@@ -73,7 +75,7 @@ struct marker { ...@@ -73,7 +75,7 @@ struct marker {
__attribute__((section("__markers"), aligned(8))) = \ __attribute__((section("__markers"), aligned(8))) = \
{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \
0, 0, marker_probe_cb, \ 0, 0, marker_probe_cb, \
{ __mark_empty_function, NULL}, NULL }; \ { __mark_empty_function, NULL}, NULL, NULL, NULL }; \
__mark_check_format(format, ## args); \ __mark_check_format(format, ## args); \
if (unlikely(__mark_##name.state)) { \ if (unlikely(__mark_##name.state)) { \
(*__mark_##name.call) \ (*__mark_##name.call) \
...@@ -81,11 +83,38 @@ struct marker { ...@@ -81,11 +83,38 @@ struct marker {
} \ } \
} while (0) } while (0)
#define __trace_mark_tp(name, call_private, tp_name, tp_cb, format, args...) \
do { \
void __check_tp_type(void) \
{ \
register_trace_##tp_name(tp_cb); \
} \
static const char __mstrtab_##name[] \
__attribute__((section("__markers_strings"))) \
= #name "\0" format; \
static struct marker __mark_##name \
__attribute__((section("__markers"), aligned(8))) = \
{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \
0, 0, marker_probe_cb, \
{ __mark_empty_function, NULL}, NULL, #tp_name, tp_cb };\
__mark_check_format(format, ## args); \
(*__mark_##name.call)(&__mark_##name, call_private, \
## args); \
} while (0)
extern void marker_update_probe_range(struct marker *begin, extern void marker_update_probe_range(struct marker *begin,
struct marker *end); struct marker *end);
#else /* !CONFIG_MARKERS */ #else /* !CONFIG_MARKERS */
#define __trace_mark(generic, name, call_private, format, args...) \ #define __trace_mark(generic, name, call_private, format, args...) \
__mark_check_format(format, ## args) __mark_check_format(format, ## args)
#define __trace_mark_tp(name, call_private, tp_name, tp_cb, format, args...) \
do { \
void __check_tp_type(void) \
{ \
register_trace_##tp_name(tp_cb); \
} \
__mark_check_format(format, ## args); \
} while (0)
static inline void marker_update_probe_range(struct marker *begin, static inline void marker_update_probe_range(struct marker *begin,
struct marker *end) struct marker *end)
{ } { }
...@@ -117,6 +146,20 @@ static inline void marker_update_probe_range(struct marker *begin, ...@@ -117,6 +146,20 @@ static inline void marker_update_probe_range(struct marker *begin,
#define _trace_mark(name, format, args...) \ #define _trace_mark(name, format, args...) \
__trace_mark(1, name, NULL, format, ## args) __trace_mark(1, name, NULL, format, ## args)
/**
* trace_mark_tp - Marker in a tracepoint callback
* @name: marker name, not quoted.
* @tp_name: tracepoint name, not quoted.
* @tp_cb: tracepoint callback. Should have an associated global symbol so it
* is not optimized away by the compiler (should not be static).
* @format: format string
* @args...: variable argument list
*
* Places a marker in a tracepoint callback.
*/
#define trace_mark_tp(name, tp_name, tp_cb, format, args...) \
__trace_mark_tp(name, NULL, tp_name, tp_cb, format, ## args)
/** /**
* MARK_NOARGS - Format string for a marker with no argument. * MARK_NOARGS - Format string for a marker with no argument.
*/ */
......
...@@ -808,6 +808,7 @@ config TRACEPOINTS ...@@ -808,6 +808,7 @@ config TRACEPOINTS
config MARKERS config MARKERS
bool "Activate markers" bool "Activate markers"
depends on TRACEPOINTS
help help
Place an empty function call at each marker site. Can be Place an empty function call at each marker site. Can be
dynamically changed for a probe function. dynamically changed for a probe function.
......
...@@ -479,7 +479,7 @@ static int marker_set_format(struct marker_entry *entry, const char *format) ...@@ -479,7 +479,7 @@ static int marker_set_format(struct marker_entry *entry, const char *format)
static int set_marker(struct marker_entry *entry, struct marker *elem, static int set_marker(struct marker_entry *entry, struct marker *elem,
int active) int active)
{ {
int ret; int ret = 0;
WARN_ON(strcmp(entry->name, elem->name) != 0); WARN_ON(strcmp(entry->name, elem->name) != 0);
if (entry->format) { if (entry->format) {
...@@ -531,9 +531,40 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, ...@@ -531,9 +531,40 @@ static int set_marker(struct marker_entry *entry, struct marker *elem,
*/ */
smp_wmb(); smp_wmb();
elem->ptype = entry->ptype; elem->ptype = entry->ptype;
if (elem->tp_name && (active ^ elem->state)) {
WARN_ON(!elem->tp_cb);
/*
* It is ok to directly call the probe registration because type
* checking has been done in the __trace_mark_tp() macro.
*/
if (active) {
/*
* try_module_get should always succeed because we hold
* lock_module() to get the tp_cb address.
*/
ret = try_module_get(__module_text_address(
(unsigned long)elem->tp_cb));
BUG_ON(!ret);
ret = tracepoint_probe_register_noupdate(
elem->tp_name,
elem->tp_cb);
} else {
ret = tracepoint_probe_unregister_noupdate(
elem->tp_name,
elem->tp_cb);
/*
* tracepoint_probe_update_all() must be called
* before the module containing tp_cb is unloaded.
*/
module_put(__module_text_address(
(unsigned long)elem->tp_cb));
}
}
elem->state = active; elem->state = active;
return 0; return ret;
} }
/* /*
...@@ -544,7 +575,24 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, ...@@ -544,7 +575,24 @@ static int set_marker(struct marker_entry *entry, struct marker *elem,
*/ */
static void disable_marker(struct marker *elem) static void disable_marker(struct marker *elem)
{ {
int ret;
/* leave "call" as is. It is known statically. */ /* leave "call" as is. It is known statically. */
if (elem->tp_name && elem->state) {
WARN_ON(!elem->tp_cb);
/*
* It is ok to directly call the probe registration because type
* checking has been done in the __trace_mark_tp() macro.
*/
ret = tracepoint_probe_unregister_noupdate(elem->tp_name,
elem->tp_cb);
WARN_ON(ret);
/*
* tracepoint_probe_update_all() must be called
* before the module containing tp_cb is unloaded.
*/
module_put(__module_text_address((unsigned long)elem->tp_cb));
}
elem->state = 0; elem->state = 0;
elem->single.func = __mark_empty_function; elem->single.func = __mark_empty_function;
/* Update the function before setting the ptype */ /* Update the function before setting the ptype */
...@@ -608,6 +656,7 @@ static void marker_update_probes(void) ...@@ -608,6 +656,7 @@ static void marker_update_probes(void)
marker_update_probe_range(__start___markers, __stop___markers); marker_update_probe_range(__start___markers, __stop___markers);
/* Markers in modules. */ /* Markers in modules. */
module_update_markers(); module_update_markers();
tracepoint_probe_update_all();
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment