tracing: Add trace events for preemption and irq disable/enable
Subsystems (3)
v8 cover tracing: Add trace events for preemption and irq disable/enable
These patches add trace events support for preempt and irq disable/enable events.
Here's an example of how Android's systrace will be using it to show atomic sections as a gantt chart: http://imgur.com/download/TZplEVp
Other advantages of this initial work could be rewriting of preemptirqs off tracer to use trace events, and replacing kprobes with tracepoint hooks for these events in BPF samples (see samples/bpf/lathist_kern.c).
Changes since v7:
* Defining the tracepoints when they are unused gives a false impression to the user that the tracepoints are present but unused, for this reason:
- preempt toggle tracepoints are unused when CONFIG_PREEMPT_DEBUG is off, lets not define them.
- irq toggle tracepoints are unused when CONFIG_PROVE_LOCKING is on, lets not define them.
I think in future patches, we should also do the same to the irqsoff tracer since it can appear that the tracer is not working when the issue is hooks aren't called.
Also in future patches, we should unify the trace_hardirqs* paths of trace_irqsoff.c and lockdep.c and avoid duplication of the 2 paths - but I leave that for a future patch set as I don't want to disrupt the functionality of irqsoff tracer or lockdep in this patchset and increase the risk of breaking something else. I am focusing on getting the tracepoints in first in this set. Hope that's Ok.
* Clarified comment about per-CPU variable used for protection in trace_hardirqs_*
Joel Fernandes (2):
tracing: Prepare to add preempt and irq trace events
tracing: Add support for preempt and irq enable/disable events
include/linux/ftrace.h | 3 +- include/trace/events/preemptirq.h | 70 ++++++++++++++++++++ kernel/trace/Kconfig | 11 ++++ kernel/trace/Makefile | 1 + kernel/trace/trace_irqsoff.c | 133 ++++++++++++++++++++++++++++++-------- 5 files changed, 191 insertions(+), 27 deletions(-) create mode 100644 include/trace/events/preemptirq.h
Signature · 1 line
2.14.2.920.gcf0c67979c-goog
PATCH v8 1/2 tracing: Prepare to add preempt and irq trace events
In preparation of adding irqsoff and preemptsoff enable and disable trace events, move required functions and code to make it easier to add these events in a later patch. This patch is just code movement and no functional change.
--- kernel/trace/trace_irqsoff.c | 100 ++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 26 deletions(-)
kernel/trace/trace_irqsoff.c +74 -26
@@ -16,6 +16,7 @@#include "trace.h" +#if defined(CONFIG_IRQSOFF_TRACER ) || defined(CONFIG_PREEMPT_TRACER )static struct trace_array *irqsoff_trace__read_mostly ;static int tracer_enabled__read_mostly ;
@@ -462,64 +463,44 @@ void time_hardirqs_off(unsigned long a0, unsigned long a1)#else /* !CONFIG_PROVE_LOCKING */ -/* -* Stubs: -*/ - -void trace_softirqs_on (unsigned long ip) -{ -} - -void trace_softirqs_off (unsigned long ip) -{ -} - -inline void print_irqtrace_events (struct task_struct *curr) -{ -} -/* * We are only interested in hardirq on/off events: */ -void trace_hardirqs_on (void ) +static inline void tracer_hardirqs_on (void ) {if (!preempt_trace () &&irq_trace ())stop_critical_timing (CALLER_ADDR0 ,CALLER_ADDR1 ); } -EXPORT_SYMBOL (trace_hardirqs_on); -void trace_hardirqs_off (void ) +static inline void tracer_hardirqs_off (void ) {if (!preempt_trace () &&irq_trace ())start_critical_timing (CALLER_ADDR0 ,CALLER_ADDR1 ); } -EXPORT_SYMBOL (trace_hardirqs_off); -__visible void trace_hardirqs_on_caller(unsigned long caller_addr) +static inline void tracer_hardirqs_on_caller (unsigned long caller_addr) {if (!preempt_trace () &&irq_trace ())stop_critical_timing (CALLER_ADDR0 , caller_addr); } -EXPORT_SYMBOL (trace_hardirqs_on_caller); -__visible void trace_hardirqs_off_caller(unsigned long caller_addr) +static inline void tracer_hardirqs_off_caller (unsigned long caller_addr) {if (!preempt_trace () &&irq_trace ())start_critical_timing (CALLER_ADDR0 , caller_addr); } -EXPORT_SYMBOL (trace_hardirqs_off_caller);#endif /* CONFIG_PROVE_LOCKING */ #endif /* CONFIG_IRQSOFF_TRACER */ #ifdef CONFIG_PREEMPT_TRACER -void trace_preempt_on (unsigned long a0,unsigned long a1) +static inline void tracer_preempt_on (unsigned long a0,unsigned long a1) {if (preempt_trace () && !irq_trace ())stop_critical_timing (a0, a1); } -void trace_preempt_off (unsigned long a0,unsigned long a1) +static inline void tracer_preempt_off (unsigned long a0,unsigned long a1) {if (preempt_trace () && !irq_trace ())start_critical_timing (a0, a1);
@@ -781,3 +762,70 @@ __init static int init_irqsoff_tracer(void)return 0 ; }core_initcall (init_irqsoff_tracer); +#endif /* IRQSOFF_TRACER || PREEMPTOFF_TRACER */ + +#ifndef CONFIG_IRQSOFF_TRACER +static inline void tracer_hardirqs_on (void ) { } +static inline void tracer_hardirqs_off (void ) { } +static inline void tracer_hardirqs_on_caller (unsigned long caller_addr) { } +static inline void tracer_hardirqs_off_caller (unsigned long caller_addr) { } +#endif + +#ifndef CONFIG_PREEMPT_TRACER +static inline void tracer_preempt_on (unsigned long a0,unsigned long a1) { } +static inline void tracer_preempt_off (unsigned long a0,unsigned long a1) { } +#endif + +#if defined(CONFIG_TRACE_IRQFLAGS ) && !defined(CONFIG_PROVE_LOCKING ) +void trace_hardirqs_on (void ) +{ +tracer_hardirqs_on (); +} +EXPORT_SYMBOL (trace_hardirqs_on); + +void trace_hardirqs_off (void ) +{ +tracer_hardirqs_off (); +} +EXPORT_SYMBOL (trace_hardirqs_off); + +__visible void trace_hardirqs_on_caller(unsigned long caller_addr) +{ +tracer_hardirqs_on_caller (caller_addr); +} +EXPORT_SYMBOL (trace_hardirqs_on_caller); + +__visible void trace_hardirqs_off_caller(unsigned long caller_addr) +{ +tracer_hardirqs_off_caller (caller_addr); +} +EXPORT_SYMBOL (trace_hardirqs_off_caller); + +/* +* Stubs: +*/ + +void trace_softirqs_on (unsigned long ip) +{ +} + +void trace_softirqs_off (unsigned long ip) +{ +} + +inline void print_irqtrace_events (struct task_struct *curr) +{ +} +#endif + +#ifdef CONFIG_PREEMPT_TRACER +void trace_preempt_on (unsigned long a0,unsigned long a1) +{ +tracer_preempt_on (a0, a1); +} + +void trace_preempt_off (unsigned long a0,unsigned long a1) +{ +tracer_preempt_off (a0, a1); +} +#endif
Signature · 1 line
2.14.2.920.gcf0c67979c-goog
Steven Rostedt
maintainerRe: [PATCH v8 1/2] tracing: Prepare to add preempt and irq trace events
Quoted 3 lines · On Thu, 5 Oct 2017 17:54:31 -0700 Joel Fernandes <[email protected]> wrote:
In preparation of adding irqsoff and preemptsoff enable and disable trace events, move required functions and code to make it easier to add these events in a later patch. This patch is just code movement and no functional change.
New warning:
kernel/trace/trace_irqsoff.c:783:69: warning: 'tracing_irq_cpu' defined but not used [-Wunused-variable]
Looks pretty obvious what the fix is. Care to send a v9?
-- Steve
Quoted 163 lines
Cc Steven Rostedt <[email protected]>Cc Peter Zijlstra <[email protected]>Signed-off-by Joel Fernandes <[email protected]>--- kernel/trace/trace_irqsoff.c | 100 ++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 26 deletions(-)kernel/trace/trace_irqsoff.c +74
-26@@ -16,6 +16,7 @@#include "trace.h" +#if defined(CONFIG_IRQSOFF_TRACER ) || defined(CONFIG_PREEMPT_TRACER )static struct trace_array *irqsoff_trace__read_mostly ;static int tracer_enabled__read_mostly ;@@ -462,64 +463,44 @@ void time_hardirqs_off(unsigned long a0, unsigned long a1)#else /* !CONFIG_PROVE_LOCKING */ -/* -* Stubs: -*/ - -void trace_softirqs_on (unsigned long ip) -{ -} - -void trace_softirqs_off (unsigned long ip) -{ -} - -inline void print_irqtrace_events (struct task_struct *curr) -{ -} -/* * We are only interested in hardirq on/off events: */ -void trace_hardirqs_on (void ) +static inline void tracer_hardirqs_on (void ) {if (!preempt_trace () &&irq_trace ())stop_critical_timing (CALLER_ADDR0 ,CALLER_ADDR1 ); } -EXPORT_SYMBOL (trace_hardirqs_on); -void trace_hardirqs_off (void ) +static inline void tracer_hardirqs_off (void ) {if (!preempt_trace () &&irq_trace ())start_critical_timing (CALLER_ADDR0 ,CALLER_ADDR1 ); } -EXPORT_SYMBOL (trace_hardirqs_off); -__visible void trace_hardirqs_on_caller(unsigned long caller_addr) +static inline void tracer_hardirqs_on_caller (unsigned long caller_addr) {if (!preempt_trace () &&irq_trace ())stop_critical_timing (CALLER_ADDR0 , caller_addr); } -EXPORT_SYMBOL (trace_hardirqs_on_caller); -__visible void trace_hardirqs_off_caller(unsigned long caller_addr) +static inline void tracer_hardirqs_off_caller (unsigned long caller_addr) {if (!preempt_trace () &&irq_trace ())start_critical_timing (CALLER_ADDR0 , caller_addr); } -EXPORT_SYMBOL (trace_hardirqs_off_caller);#endif /* CONFIG_PROVE_LOCKING */ #endif /* CONFIG_IRQSOFF_TRACER */ #ifdef CONFIG_PREEMPT_TRACER -void trace_preempt_on (unsigned long a0,unsigned long a1) +static inline void tracer_preempt_on (unsigned long a0,unsigned long a1) {if (preempt_trace () && !irq_trace ())stop_critical_timing (a0, a1); } -void trace_preempt_off (unsigned long a0,unsigned long a1) +static inline void tracer_preempt_off (unsigned long a0,unsigned long a1) {if (preempt_trace () && !irq_trace ())start_critical_timing (a0, a1);@@ -781,3 +762,70 @@ __init static int init_irqsoff_tracer(void)return 0 ; }core_initcall (init_irqsoff_tracer); +#endif /* IRQSOFF_TRACER || PREEMPTOFF_TRACER */ + +#ifndef CONFIG_IRQSOFF_TRACER +static inline void tracer_hardirqs_on (void ) { } +static inline void tracer_hardirqs_off (void ) { } +static inline void tracer_hardirqs_on_caller (unsigned long caller_addr) { } +static inline void tracer_hardirqs_off_caller (unsigned long caller_addr) { } +#endif + +#ifndef CONFIG_PREEMPT_TRACER +static inline void tracer_preempt_on (unsigned long a0,unsigned long a1) { } +static inline void tracer_preempt_off (unsigned long a0,unsigned long a1) { } +#endif + +#if defined(CONFIG_TRACE_IRQFLAGS ) && !defined(CONFIG_PROVE_LOCKING ) +void trace_hardirqs_on (void ) +{ +tracer_hardirqs_on (); +} +EXPORT_SYMBOL (trace_hardirqs_on); + +void trace_hardirqs_off (void ) +{ +tracer_hardirqs_off (); +} +EXPORT_SYMBOL (trace_hardirqs_off); + +__visible void trace_hardirqs_on_caller(unsigned long caller_addr) +{ +tracer_hardirqs_on_caller (caller_addr); +} +EXPORT_SYMBOL (trace_hardirqs_on_caller); + +__visible void trace_hardirqs_off_caller(unsigned long caller_addr) +{ +tracer_hardirqs_off_caller (caller_addr); +} +EXPORT_SYMBOL (trace_hardirqs_off_caller); + +/* +* Stubs: +*/ + +void trace_softirqs_on (unsigned long ip) +{ +} + +void trace_softirqs_off (unsigned long ip) +{ +} + +inline void print_irqtrace_events (struct task_struct *curr) +{ +} +#endif + +#ifdef CONFIG_PREEMPT_TRACER +void trace_preempt_on (unsigned long a0,unsigned long a1) +{ +tracer_preempt_on (a0, a1); +} + +void trace_preempt_off (unsigned long a0,unsigned long a1) +{ +tracer_preempt_off (a0, a1); +} +#endif
Re: [PATCH v8 1/2] tracing: Prepare to add preempt and irq trace events
Quoted 7 lines · Steven Rostedt
Quoted 3 lines · On Thu, 5 Oct 2017 17:54:31 -0700 Joel Fernandes <[email protected]> wrote:
In preparation of adding irqsoff and preemptsoff enable and disable trace events, move required functions and code to make it easier to add these events in a later patch. This patch is just code movement and no functional change.
Quoted 5 lines
New warning:
kernel/trace/trace_irqsoff.c:783:69: warning: 'tracing_irq_cpu' defined but not used [-Wunused-variable]Looks pretty obvious what the fix is. Care to send a v9?
Yes, I'll fix it and send a v9. Sorry about that.
thanks,
- Joel
Steven Rostedt
maintainerRe: [PATCH v8 1/2] tracing: Prepare to add preempt and irq trace events
Quoted 8 lines · On Tue, 10 Oct 2017 15:32:27 -0700 Joel Fernandes <[email protected]> wrote:
Quoted 7 lines · Steven Rostedt
Quoted 3 lines · On Thu, 5 Oct 2017 17:54:31 -0700 Joel Fernandes <[email protected]> wrote:
In preparation of adding irqsoff and preemptsoff enable and disable trace events, move required functions and code to make it easier to add these events in a later patch. This patch is just code movement and no functional change.
Quoted 8 lines
Quoted 5 lines
New warning:
kernel/trace/trace_irqsoff.c:783:69: warning: 'tracing_irq_cpu' defined but not used [-Wunused-variable]Looks pretty obvious what the fix is. Care to send a v9?
Yes, I'll fix it and send a v9. Sorry about that.
Just send the patch for this one. Don't need to send a series.
Heck, call it v8.1 ;-)
-- Steve
Re: [PATCH v8 1/2] tracing: Prepare to add preempt and irq trace events
Quoted 15 lines · Steven Rostedt
Quoted 12 lines · On Tue, 10 Oct 2017 15:32:27 -0700 Joel Fernandes <[email protected]> wrote:
Quoted 11 lines · Steven Rostedt
Quoted 3 lines · On Thu, 5 Oct 2017 17:54:31 -0700 Joel Fernandes <[email protected]> wrote:
In preparation of adding irqsoff and preemptsoff enable and disable trace events, move required functions and code to make it easier to add these events in a later patch. This patch is just code movement and no functional change.
New warning:
kernel/trace/trace_irqsoff.c:783:69: warning: 'tracing_irq_cpu' defined but not used [-Wunused-variable]
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Looks pretty obvious what the fix is. Care to send a v9?
Yes, I'll fix it and send a v9. Sorry about that.
Just send the patch for this one. Don't need to send a series.
Heck, call it v8.1 ;-)
Done, the variable was introduced in patch 2/2 so I fixed that up and resent it as 8.1 ;-)
thanks,
- Joel
PATCH v8 2/2 tracing: Add support for preempt and irq enable/disable events
In reply to Joel FernandesPreempt and irq trace events can be used for tracing the start and end of an atomic section which can be used by a trace viewer like systrace to graphically view the start and end of an atomic section and correlate them with latencies and scheduling issues.
This also serves as a prelude to using synthetic events or probes to rewrite the preempt and irqsoff tracers, along with numerous benefits of using trace events features for these events.
--- include/linux/ftrace.h | 3 +- include/trace/events/preemptirq.h | 70 +++++++++++++++++++++++++++++++++++++++ kernel/trace/Kconfig | 11 ++++++ kernel/trace/Makefile | 1 + kernel/trace/trace_irqsoff.c | 35 +++++++++++++++++++- 5 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 include/trace/events/preemptirq.h
include/linux/ftrace.h +2 -1
@@ -742,7 +742,8 @@ static inline unsigned long get_lock_parent_ip(void)static inline void time_hardirqs_off (unsigned long a0,unsigned long a1) { }#endif -#ifdef CONFIG_PREEMPT_TRACER +#if defined(CONFIG_PREEMPT_TRACER ) || \ + (defined(CONFIG_DEBUG_PREEMPT ) && defined(CONFIG_PREEMPTIRQ_EVENTS ))extern void trace_preempt_on (unsigned long a0,unsigned long a1);extern void trace_preempt_off (unsigned long a0,unsigned long a1);#else
include/trace/events/preemptirq.h new file +70 -0
70 lines not on this page · raw message
kernel/trace/Kconfig +11 -0
@@ -160,6 +160,17 @@ config FUNCTION_GRAPH_TRACER address on the current task structure into a stack of calls. +config PREEMPTIRQ_EVENTS + bool "Enable trace events for preempt and irq disable/enable" + select TRACE_IRQFLAGS + depends on DEBUG_PREEMPT || !PROVE_LOCKING + default n + help + Enable tracing of disable and enable events for preemption and irqs. + For tracing preempt disable/enable events, DEBUG_PREEMPT must be + enabled. For tracing irq disable/enable events, PROVE_LOCKING must + be disabled. + config IRQSOFF_TRACER bool "Interrupts-off Latency Tracer" default n
kernel/trace/Makefile +1 -0
@@ -34,6 +34,7 @@ obj-$(CONFIG_TRACING) += trace_printk.o obj-$(CONFIG_TRACING_MAP) += tracing_map.o obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o +obj-$(CONFIG_PREEMPTIRQ_EVENTS) += trace_irqsoff.o obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
kernel/trace/trace_irqsoff.c +34 -1
@@ -16,6 +16,9 @@#include "trace.h" +#define CREATE_TRACE_POINTS +#include <trace/events/preemptirq.h> +#if defined(CONFIG_IRQSOFF_TRACER ) || defined(CONFIG_PREEMPT_TRACER )static struct trace_array *irqsoff_trace__read_mostly ;static int tracer_enabled__read_mostly ;
@@ -776,27 +779,54 @@ static inline void tracer_preempt_on(unsigned long a0, unsigned long a1) { }static inline void tracer_preempt_off (unsigned long a0,unsigned long a1) { }#endif +/* Per-cpu variable to prevent redundant calls when IRQs already off */ +static DEFINE_PER_CPU(int, tracing_irq_cpu); +#if defined(CONFIG_TRACE_IRQFLAGS ) && !defined(CONFIG_PROVE_LOCKING )void trace_hardirqs_on (void ) { +if (!this_cpu_read (tracing_irq_cpu)) +return ; + +trace_irq_enable_rcuidle (CALLER_ADDR0 ,CALLER_ADDR1 );tracer_hardirqs_on (); + +this_cpu_write (tracing_irq_cpu,0 ); }EXPORT_SYMBOL (trace_hardirqs_on);void trace_hardirqs_off (void ) { +if (this_cpu_read (tracing_irq_cpu)) +return ; + +this_cpu_write (tracing_irq_cpu,1 ); + +trace_irq_disable_rcuidle (CALLER_ADDR0 ,CALLER_ADDR1 );tracer_hardirqs_off (); }EXPORT_SYMBOL (trace_hardirqs_off); __visible void trace_hardirqs_on_caller(unsigned long caller_addr) { +if (!this_cpu_read (tracing_irq_cpu)) +return ; + +trace_irq_enable_rcuidle (CALLER_ADDR0 , caller_addr);tracer_hardirqs_on_caller (caller_addr); + +this_cpu_write (tracing_irq_cpu,0 ); }EXPORT_SYMBOL (trace_hardirqs_on_caller); __visible void trace_hardirqs_off_caller(unsigned long caller_addr) { +if (this_cpu_read (tracing_irq_cpu)) +return ; + +this_cpu_write (tracing_irq_cpu,1 ); + +trace_irq_disable_rcuidle (CALLER_ADDR0 , caller_addr);tracer_hardirqs_off_caller (caller_addr); }EXPORT_SYMBOL (trace_hardirqs_off_caller);
@@ -818,14 +848,17 @@ inline void print_irqtrace_events(struct task_struct *curr) }#endif -#ifdef CONFIG_PREEMPT_TRACER +#if defined(CONFIG_PREEMPT_TRACER ) || \ + (defined(CONFIG_DEBUG_PREEMPT ) && defined(CONFIG_PREEMPTIRQ_EVENTS ))void trace_preempt_on (unsigned long a0,unsigned long a1) { +trace_preempt_enable_rcuidle (a0, a1);tracer_preempt_on (a0, a1); }void trace_preempt_off (unsigned long a0,unsigned long a1) { +trace_preempt_disable_rcuidle (a0, a1);tracer_preempt_off (a0, a1); }#endif
Signature · 1 line
2.14.2.920.gcf0c67979c-goog