Skip to content

Commit c3bc8fd

Browse files
joelagnelrostedt
authored andcommitted
tracing: Centralize preemptirq tracepoints and unify their usage
This patch detaches the preemptirq tracepoints from the tracers and keeps it separate. Advantages: * Lockdep and irqsoff event can now run in parallel since they no longer have their own calls. * This unifies the usecase of adding hooks to an irqsoff and irqson event, and a preemptoff and preempton event. 3 users of the events exist: - Lockdep - irqsoff and preemptoff tracers - irqs and preempt trace events The unification cleans up several ifdefs and makes the code in preempt tracer and irqsoff tracers simpler. It gets rid of all the horrific ifdeferry around PROVE_LOCKING and makes configuration of the different users of the tracepoints more easy and understandable. It also gets rid of the time_* function calls from the lockdep hooks used to call into the preemptirq tracer which is not needed anymore. The negative delta in lines of code in this patch is quite large too. In the patch we introduce a new CONFIG option PREEMPTIRQ_TRACEPOINTS as a single point for registering probes onto the tracepoints. With this, the web of config options for preempt/irq toggle tracepoints and its users becomes: PREEMPT_TRACER PREEMPTIRQ_EVENTS IRQSOFF_TRACER PROVE_LOCKING | | \ | | \ (selects) / \ \ (selects) / TRACE_PREEMPT_TOGGLE ----> TRACE_IRQFLAGS \ / \ (depends on) / PREEMPTIRQ_TRACEPOINTS Other than the performance tests mentioned in the previous patch, I also ran the locking API test suite. I verified that all tests cases are passing. I also injected issues by not registering lockdep probes onto the tracepoints and I see failures to confirm that the probes are indeed working. This series + lockdep probes not registered (just to inject errors): [ 0.000000] hard-irqs-on + irq-safe-A/21: ok | ok | ok | [ 0.000000] soft-irqs-on + irq-safe-A/21: ok | ok | ok | [ 0.000000] sirq-safe-A => hirqs-on/12:FAILED|FAILED| ok | [ 0.000000] sirq-safe-A => hirqs-on/21:FAILED|FAILED| ok | [ 0.000000] hard-safe-A + irqs-on/12:FAILED|FAILED| ok | [ 0.000000] soft-safe-A + irqs-on/12:FAILED|FAILED| ok | [ 0.000000] hard-safe-A + irqs-on/21:FAILED|FAILED| ok | [ 0.000000] soft-safe-A + irqs-on/21:FAILED|FAILED| ok | [ 0.000000] hard-safe-A + unsafe-B #1/123: ok | ok | ok | [ 0.000000] soft-safe-A + unsafe-B #1/123: ok | ok | ok | With this series + lockdep probes registered, all locking tests pass: [ 0.000000] hard-irqs-on + irq-safe-A/21: ok | ok | ok | [ 0.000000] soft-irqs-on + irq-safe-A/21: ok | ok | ok | [ 0.000000] sirq-safe-A => hirqs-on/12: ok | ok | ok | [ 0.000000] sirq-safe-A => hirqs-on/21: ok | ok | ok | [ 0.000000] hard-safe-A + irqs-on/12: ok | ok | ok | [ 0.000000] soft-safe-A + irqs-on/12: ok | ok | ok | [ 0.000000] hard-safe-A + irqs-on/21: ok | ok | ok | [ 0.000000] soft-safe-A + irqs-on/21: ok | ok | ok | [ 0.000000] hard-safe-A + unsafe-B #1/123: ok | ok | ok | [ 0.000000] soft-safe-A + unsafe-B #1/123: ok | ok | ok | Link: http://lkml.kernel.org/r/[email protected] Acked-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Namhyung Kim <[email protected]> Signed-off-by: Joel Fernandes (Google) <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent e6753f2 commit c3bc8fd

File tree

12 files changed

+195
-229
lines changed

12 files changed

+195
-229
lines changed

include/linux/ftrace.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -701,16 +701,7 @@ static inline unsigned long get_lock_parent_ip(void)
701701
return CALLER_ADDR2;
702702
}
703703

704-
#ifdef CONFIG_IRQSOFF_TRACER
705-
extern void time_hardirqs_on(unsigned long a0, unsigned long a1);
706-
extern void time_hardirqs_off(unsigned long a0, unsigned long a1);
707-
#else
708-
static inline void time_hardirqs_on(unsigned long a0, unsigned long a1) { }
709-
static inline void time_hardirqs_off(unsigned long a0, unsigned long a1) { }
710-
#endif
711-
712-
#if defined(CONFIG_PREEMPT_TRACER) || \
713-
(defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_PREEMPTIRQ_EVENTS))
704+
#ifdef CONFIG_TRACE_PREEMPT_TOGGLE
714705
extern void trace_preempt_on(unsigned long a0, unsigned long a1);
715706
extern void trace_preempt_off(unsigned long a0, unsigned long a1);
716707
#else

include/linux/irqflags.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@
1515
#include <linux/typecheck.h>
1616
#include <asm/irqflags.h>
1717

18-
#ifdef CONFIG_TRACE_IRQFLAGS
18+
/* Currently trace_softirqs_on/off is used only by lockdep */
19+
#ifdef CONFIG_PROVE_LOCKING
1920
extern void trace_softirqs_on(unsigned long ip);
2021
extern void trace_softirqs_off(unsigned long ip);
22+
#else
23+
# define trace_softirqs_on(ip) do { } while (0)
24+
# define trace_softirqs_off(ip) do { } while (0)
25+
#endif
26+
27+
#ifdef CONFIG_TRACE_IRQFLAGS
2128
extern void trace_hardirqs_on(void);
2229
extern void trace_hardirqs_off(void);
2330
# define trace_hardirq_context(p) ((p)->hardirq_context)
@@ -43,8 +50,6 @@ do { \
4350
#else
4451
# define trace_hardirqs_on() do { } while (0)
4552
# define trace_hardirqs_off() do { } while (0)
46-
# define trace_softirqs_on(ip) do { } while (0)
47-
# define trace_softirqs_off(ip) do { } while (0)
4853
# define trace_hardirq_context(p) 0
4954
# define trace_softirq_context(p) 0
5055
# define trace_hardirqs_enabled(p) 0

include/linux/lockdep.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ struct held_lock {
266266
/*
267267
* Initialization, self-test and debugging-output methods:
268268
*/
269-
extern void lockdep_info(void);
269+
extern void lockdep_init(void);
270+
extern void lockdep_init_early(void);
270271
extern void lockdep_reset(void);
271272
extern void lockdep_reset_lock(struct lockdep_map *lock);
272273
extern void lockdep_free_key_range(void *start, unsigned long size);
@@ -406,7 +407,8 @@ static inline void lockdep_on(void)
406407
# define lock_downgrade(l, i) do { } while (0)
407408
# define lock_set_class(l, n, k, s, i) do { } while (0)
408409
# define lock_set_subclass(l, s, i) do { } while (0)
409-
# define lockdep_info() do { } while (0)
410+
# define lockdep_init() do { } while (0)
411+
# define lockdep_init_early() do { } while (0)
410412
# define lockdep_init_map(lock, name, key, sub) \
411413
do { (void)(name); (void)(key); } while (0)
412414
# define lockdep_set_class(lock, key) do { (void)(key); } while (0)
@@ -532,7 +534,7 @@ do { \
532534

533535
#endif /* CONFIG_LOCKDEP */
534536

535-
#ifdef CONFIG_TRACE_IRQFLAGS
537+
#ifdef CONFIG_PROVE_LOCKING
536538
extern void print_irqtrace_events(struct task_struct *curr);
537539
#else
538540
static inline void print_irqtrace_events(struct task_struct *curr)

include/linux/preempt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
*/
151151
#define in_atomic_preempt_off() (preempt_count() != PREEMPT_DISABLE_OFFSET)
152152

153-
#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER)
153+
#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_TRACE_PREEMPT_TOGGLE)
154154
extern void preempt_count_add(int val);
155155
extern void preempt_count_sub(int val);
156156
#define preempt_count_dec_and_test() \

include/trace/events/preemptirq.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#ifdef CONFIG_PREEMPTIRQ_EVENTS
1+
#ifdef CONFIG_PREEMPTIRQ_TRACEPOINTS
22

33
#undef TRACE_SYSTEM
44
#define TRACE_SYSTEM preemptirq
@@ -32,40 +32,45 @@ DECLARE_EVENT_CLASS(preemptirq_template,
3232
(void *)((unsigned long)(_stext) + __entry->parent_offs))
3333
);
3434

35-
#ifndef CONFIG_PROVE_LOCKING
35+
#ifdef CONFIG_TRACE_IRQFLAGS
3636
DEFINE_EVENT(preemptirq_template, irq_disable,
3737
TP_PROTO(unsigned long ip, unsigned long parent_ip),
3838
TP_ARGS(ip, parent_ip));
3939

4040
DEFINE_EVENT(preemptirq_template, irq_enable,
4141
TP_PROTO(unsigned long ip, unsigned long parent_ip),
4242
TP_ARGS(ip, parent_ip));
43+
#else
44+
#define trace_irq_enable(...)
45+
#define trace_irq_disable(...)
46+
#define trace_irq_enable_rcuidle(...)
47+
#define trace_irq_disable_rcuidle(...)
4348
#endif
4449

45-
#ifdef CONFIG_DEBUG_PREEMPT
50+
#ifdef CONFIG_TRACE_PREEMPT_TOGGLE
4651
DEFINE_EVENT(preemptirq_template, preempt_disable,
4752
TP_PROTO(unsigned long ip, unsigned long parent_ip),
4853
TP_ARGS(ip, parent_ip));
4954

5055
DEFINE_EVENT(preemptirq_template, preempt_enable,
5156
TP_PROTO(unsigned long ip, unsigned long parent_ip),
5257
TP_ARGS(ip, parent_ip));
58+
#else
59+
#define trace_preempt_enable(...)
60+
#define trace_preempt_disable(...)
61+
#define trace_preempt_enable_rcuidle(...)
62+
#define trace_preempt_disable_rcuidle(...)
5363
#endif
5464

5565
#endif /* _TRACE_PREEMPTIRQ_H */
5666

5767
#include <trace/define_trace.h>
5868

59-
#endif /* !CONFIG_PREEMPTIRQ_EVENTS */
60-
61-
#if !defined(CONFIG_PREEMPTIRQ_EVENTS) || defined(CONFIG_PROVE_LOCKING)
69+
#else /* !CONFIG_PREEMPTIRQ_TRACEPOINTS */
6270
#define trace_irq_enable(...)
6371
#define trace_irq_disable(...)
6472
#define trace_irq_enable_rcuidle(...)
6573
#define trace_irq_disable_rcuidle(...)
66-
#endif
67-
68-
#if !defined(CONFIG_PREEMPTIRQ_EVENTS) || !defined(CONFIG_DEBUG_PREEMPT)
6974
#define trace_preempt_enable(...)
7075
#define trace_preempt_disable(...)
7176
#define trace_preempt_enable_rcuidle(...)

init/main.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,9 @@ asmlinkage __visible void __init start_kernel(void)
648648
profile_init();
649649
call_function_init();
650650
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
651+
652+
lockdep_init_early();
653+
651654
early_boot_irqs_disabled = false;
652655
local_irq_enable();
653656

@@ -663,7 +666,7 @@ asmlinkage __visible void __init start_kernel(void)
663666
panic("Too many boot %s vars at `%s'", panic_later,
664667
panic_param);
665668

666-
lockdep_info();
669+
lockdep_init();
667670

668671
/*
669672
* Need to run this when irqs are enabled, because it wants

kernel/locking/lockdep.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555

5656
#include "lockdep_internals.h"
5757

58+
#include <trace/events/preemptirq.h>
5859
#define CREATE_TRACE_POINTS
5960
#include <trace/events/lock.h>
6061

@@ -2839,10 +2840,9 @@ static void __trace_hardirqs_on_caller(unsigned long ip)
28392840
debug_atomic_inc(hardirqs_on_events);
28402841
}
28412842

2842-
__visible void trace_hardirqs_on_caller(unsigned long ip)
2843+
static void lockdep_hardirqs_on(void *none, unsigned long ignore,
2844+
unsigned long ip)
28432845
{
2844-
time_hardirqs_on(CALLER_ADDR0, ip);
2845-
28462846
if (unlikely(!debug_locks || current->lockdep_recursion))
28472847
return;
28482848

@@ -2881,23 +2881,15 @@ __visible void trace_hardirqs_on_caller(unsigned long ip)
28812881
__trace_hardirqs_on_caller(ip);
28822882
current->lockdep_recursion = 0;
28832883
}
2884-
EXPORT_SYMBOL(trace_hardirqs_on_caller);
2885-
2886-
void trace_hardirqs_on(void)
2887-
{
2888-
trace_hardirqs_on_caller(CALLER_ADDR0);
2889-
}
2890-
EXPORT_SYMBOL(trace_hardirqs_on);
28912884

28922885
/*
28932886
* Hardirqs were disabled:
28942887
*/
2895-
__visible void trace_hardirqs_off_caller(unsigned long ip)
2888+
static void lockdep_hardirqs_off(void *none, unsigned long ignore,
2889+
unsigned long ip)
28962890
{
28972891
struct task_struct *curr = current;
28982892

2899-
time_hardirqs_off(CALLER_ADDR0, ip);
2900-
29012893
if (unlikely(!debug_locks || current->lockdep_recursion))
29022894
return;
29032895

@@ -2919,13 +2911,6 @@ __visible void trace_hardirqs_off_caller(unsigned long ip)
29192911
} else
29202912
debug_atomic_inc(redundant_hardirqs_off);
29212913
}
2922-
EXPORT_SYMBOL(trace_hardirqs_off_caller);
2923-
2924-
void trace_hardirqs_off(void)
2925-
{
2926-
trace_hardirqs_off_caller(CALLER_ADDR0);
2927-
}
2928-
EXPORT_SYMBOL(trace_hardirqs_off);
29292914

29302915
/*
29312916
* Softirqs will be enabled:
@@ -4330,7 +4315,15 @@ void lockdep_reset_lock(struct lockdep_map *lock)
43304315
raw_local_irq_restore(flags);
43314316
}
43324317

4333-
void __init lockdep_info(void)
4318+
void __init lockdep_init_early(void)
4319+
{
4320+
#ifdef CONFIG_PROVE_LOCKING
4321+
register_trace_prio_irq_disable(lockdep_hardirqs_off, NULL, INT_MAX);
4322+
register_trace_prio_irq_enable(lockdep_hardirqs_on, NULL, INT_MIN);
4323+
#endif
4324+
}
4325+
4326+
void __init lockdep_init(void)
43344327
{
43354328
printk("Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar\n");
43364329

kernel/sched/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3189,7 +3189,7 @@ static inline void sched_tick_stop(int cpu) { }
31893189
#endif
31903190

31913191
#if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \
3192-
defined(CONFIG_PREEMPT_TRACER))
3192+
defined(CONFIG_TRACE_PREEMPT_TOGGLE))
31933193
/*
31943194
* If the value passed in is equal to the current preempt count
31953195
* then we just disabled preemption. Start timing the latency.

kernel/trace/Kconfig

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ config RING_BUFFER_ALLOW_SWAP
8282
Allow the use of ring_buffer_swap_cpu.
8383
Adds a very slight overhead to tracing when enabled.
8484

85+
config PREEMPTIRQ_TRACEPOINTS
86+
bool
87+
depends on TRACE_PREEMPT_TOGGLE || TRACE_IRQFLAGS
88+
select TRACING
89+
default y
90+
help
91+
Create preempt/irq toggle tracepoints if needed, so that other parts
92+
of the kernel can use them to generate or add hooks to them.
93+
8594
# All tracer options should select GENERIC_TRACER. For those options that are
8695
# enabled by all tracers (context switch and event tracer) they select TRACING.
8796
# This allows those options to appear when no other tracer is selected. But the
@@ -155,18 +164,20 @@ config FUNCTION_GRAPH_TRACER
155164
the return value. This is done by setting the current return
156165
address on the current task structure into a stack of calls.
157166

167+
config TRACE_PREEMPT_TOGGLE
168+
bool
169+
help
170+
Enables hooks which will be called when preemption is first disabled,
171+
and last enabled.
158172

159173
config PREEMPTIRQ_EVENTS
160174
bool "Enable trace events for preempt and irq disable/enable"
161175
select TRACE_IRQFLAGS
162-
depends on DEBUG_PREEMPT || !PROVE_LOCKING
163-
depends on TRACING
176+
select TRACE_PREEMPT_TOGGLE if PREEMPT
177+
select GENERIC_TRACER
164178
default n
165179
help
166180
Enable tracing of disable and enable events for preemption and irqs.
167-
For tracing preempt disable/enable events, DEBUG_PREEMPT must be
168-
enabled. For tracing irq disable/enable events, PROVE_LOCKING must
169-
be disabled.
170181

171182
config IRQSOFF_TRACER
172183
bool "Interrupts-off Latency Tracer"
@@ -203,6 +214,7 @@ config PREEMPT_TRACER
203214
select RING_BUFFER_ALLOW_SWAP
204215
select TRACER_SNAPSHOT
205216
select TRACER_SNAPSHOT_PER_CPU_SWAP
217+
select TRACE_PREEMPT_TOGGLE
206218
help
207219
This option measures the time spent in preemption-off critical
208220
sections, with microsecond accuracy.

kernel/trace/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ obj-$(CONFIG_TRACING_MAP) += tracing_map.o
4141
obj-$(CONFIG_PREEMPTIRQ_DELAY_TEST) += preemptirq_delay_test.o
4242
obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
4343
obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o
44-
obj-$(CONFIG_PREEMPTIRQ_EVENTS) += trace_irqsoff.o
44+
obj-$(CONFIG_PREEMPTIRQ_TRACEPOINTS) += trace_preemptirq.o
4545
obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
4646
obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
4747
obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o

0 commit comments

Comments
 (0)