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

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
Loading
Loading
Loading
Loading
+44 −1
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ struct marker {
	void (*call)(const struct marker *mdata, void *call_private, ...);
	struct marker_probe_closure single;
	struct marker_probe_closure *multi;
	const char *tp_name;	/* Optional tracepoint name */
	void *tp_cb;		/* Optional tracepoint callback */
} __attribute__((aligned(8)));

#ifdef CONFIG_MARKERS
@@ -73,7 +75,7 @@ struct marker {
		__attribute__((section("__markers"), aligned(8))) =	\
		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
		0, 0, marker_probe_cb,					\
		{ __mark_empty_function, NULL}, NULL };			\
		{ __mark_empty_function, NULL}, NULL, NULL, NULL };	\
		__mark_check_format(format, ## args);			\
		if (unlikely(__mark_##name.state)) {			\
			(*__mark_##name.call)				\
@@ -81,11 +83,38 @@ struct marker {
		}							\
	} 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,
	struct marker *end);
#else /* !CONFIG_MARKERS */
#define __trace_mark(generic, name, call_private, 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,
	struct marker *end)
{ }
@@ -117,6 +146,20 @@ static inline void marker_update_probe_range(struct marker *begin,
#define _trace_mark(name, 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.
 */
+1 −0
Original line number Diff line number Diff line
@@ -808,6 +808,7 @@ config TRACEPOINTS

config MARKERS
	bool "Activate markers"
	depends on TRACEPOINTS
	help
	  Place an empty function call at each marker site. Can be
	  dynamically changed for a probe function.
+51 −2
Original line number Diff line number Diff line
@@ -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,
		int active)
{
	int ret;
	int ret = 0;
	WARN_ON(strcmp(entry->name, elem->name) != 0);

	if (entry->format) {
@@ -531,9 +531,40 @@ static int set_marker(struct marker_entry *entry, struct marker *elem,
	 */
	smp_wmb();
	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;

	return 0;
	return ret;
}

/*
@@ -544,7 +575,24 @@ static int set_marker(struct marker_entry *entry, struct marker *elem,
 */
static void disable_marker(struct marker *elem)
{
	int ret;

	/* 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->single.func = __mark_empty_function;
	/* Update the function before setting the ptype */
@@ -608,6 +656,7 @@ static void marker_update_probes(void)
	marker_update_probe_range(__start___markers, __stop___markers);
	/* Markers in modules. */
	module_update_markers();
	tracepoint_probe_update_all();
}

/**