diff options
-rw-r--r-- | include/trace/events/timer.h | 137 | ||||
-rw-r--r-- | kernel/timer.c | 32 |
2 files changed, 165 insertions, 4 deletions
diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h new file mode 100644 index 000000000000..725892a93b49 --- /dev/null +++ b/include/trace/events/timer.h | |||
@@ -0,0 +1,137 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM timer | ||
3 | |||
4 | #if !defined(_TRACE_TIMER_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _TRACE_TIMER_H | ||
6 | |||
7 | #include <linux/tracepoint.h> | ||
8 | #include <linux/timer.h> | ||
9 | |||
10 | /** | ||
11 | * timer_init - called when the timer is initialized | ||
12 | * @timer: pointer to struct timer_list | ||
13 | */ | ||
14 | TRACE_EVENT(timer_init, | ||
15 | |||
16 | TP_PROTO(struct timer_list *timer), | ||
17 | |||
18 | TP_ARGS(timer), | ||
19 | |||
20 | TP_STRUCT__entry( | ||
21 | __field( void *, timer ) | ||
22 | ), | ||
23 | |||
24 | TP_fast_assign( | ||
25 | __entry->timer = timer; | ||
26 | ), | ||
27 | |||
28 | TP_printk("timer %p", __entry->timer) | ||
29 | ); | ||
30 | |||
31 | /** | ||
32 | * timer_start - called when the timer is started | ||
33 | * @timer: pointer to struct timer_list | ||
34 | * @expires: the timers expiry time | ||
35 | */ | ||
36 | TRACE_EVENT(timer_start, | ||
37 | |||
38 | TP_PROTO(struct timer_list *timer, unsigned long expires), | ||
39 | |||
40 | TP_ARGS(timer, expires), | ||
41 | |||
42 | TP_STRUCT__entry( | ||
43 | __field( void *, timer ) | ||
44 | __field( void *, function ) | ||
45 | __field( unsigned long, expires ) | ||
46 | __field( unsigned long, now ) | ||
47 | ), | ||
48 | |||
49 | TP_fast_assign( | ||
50 | __entry->timer = timer; | ||
51 | __entry->function = timer->function; | ||
52 | __entry->expires = expires; | ||
53 | __entry->now = jiffies; | ||
54 | ), | ||
55 | |||
56 | TP_printk("timer %p: func %pf, expires %lu, timeout %ld", | ||
57 | __entry->timer, __entry->function, __entry->expires, | ||
58 | (long)__entry->expires - __entry->now) | ||
59 | ); | ||
60 | |||
61 | /** | ||
62 | * timer_expire_entry - called immediately before the timer callback | ||
63 | * @timer: pointer to struct timer_list | ||
64 | * | ||
65 | * Allows to determine the timer latency. | ||
66 | */ | ||
67 | TRACE_EVENT(timer_expire_entry, | ||
68 | |||
69 | TP_PROTO(struct timer_list *timer), | ||
70 | |||
71 | TP_ARGS(timer), | ||
72 | |||
73 | TP_STRUCT__entry( | ||
74 | __field( void *, timer ) | ||
75 | __field( unsigned long, now ) | ||
76 | ), | ||
77 | |||
78 | TP_fast_assign( | ||
79 | __entry->timer = timer; | ||
80 | __entry->now = jiffies; | ||
81 | ), | ||
82 | |||
83 | TP_printk("timer %p: now %lu", __entry->timer, __entry->now) | ||
84 | ); | ||
85 | |||
86 | /** | ||
87 | * timer_expire_exit - called immediately after the timer callback returns | ||
88 | * @timer: pointer to struct timer_list | ||
89 | * | ||
90 | * When used in combination with the timer_expire_entry tracepoint we can | ||
91 | * determine the runtime of the timer callback function. | ||
92 | * | ||
93 | * NOTE: Do NOT derefernce timer in TP_fast_assign. The pointer might | ||
94 | * be invalid. We solely track the pointer. | ||
95 | */ | ||
96 | TRACE_EVENT(timer_expire_exit, | ||
97 | |||
98 | TP_PROTO(struct timer_list *timer), | ||
99 | |||
100 | TP_ARGS(timer), | ||
101 | |||
102 | TP_STRUCT__entry( | ||
103 | __field(void *, timer ) | ||
104 | ), | ||
105 | |||
106 | TP_fast_assign( | ||
107 | __entry->timer = timer; | ||
108 | ), | ||
109 | |||
110 | TP_printk("timer %p", __entry->timer) | ||
111 | ); | ||
112 | |||
113 | /** | ||
114 | * timer_cancel - called when the timer is canceled | ||
115 | * @timer: pointer to struct timer_list | ||
116 | */ | ||
117 | TRACE_EVENT(timer_cancel, | ||
118 | |||
119 | TP_PROTO(struct timer_list *timer), | ||
120 | |||
121 | TP_ARGS(timer), | ||
122 | |||
123 | TP_STRUCT__entry( | ||
124 | __field( void *, timer ) | ||
125 | ), | ||
126 | |||
127 | TP_fast_assign( | ||
128 | __entry->timer = timer; | ||
129 | ), | ||
130 | |||
131 | TP_printk("timer %p", __entry->timer) | ||
132 | ); | ||
133 | |||
134 | #endif /* _TRACE_TIMER_H */ | ||
135 | |||
136 | /* This part must be outside protection */ | ||
137 | #include <trace/define_trace.h> | ||
diff --git a/kernel/timer.c b/kernel/timer.c index 8e92be654dad..a7352b00703c 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -46,6 +46,9 @@ | |||
46 | #include <asm/timex.h> | 46 | #include <asm/timex.h> |
47 | #include <asm/io.h> | 47 | #include <asm/io.h> |
48 | 48 | ||
49 | #define CREATE_TRACE_POINTS | ||
50 | #include <trace/events/timer.h> | ||
51 | |||
49 | u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; | 52 | u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; |
50 | 53 | ||
51 | EXPORT_SYMBOL(jiffies_64); | 54 | EXPORT_SYMBOL(jiffies_64); |
@@ -521,6 +524,25 @@ static inline void debug_timer_activate(struct timer_list *timer) { } | |||
521 | static inline void debug_timer_deactivate(struct timer_list *timer) { } | 524 | static inline void debug_timer_deactivate(struct timer_list *timer) { } |
522 | #endif | 525 | #endif |
523 | 526 | ||
527 | static inline void debug_init(struct timer_list *timer) | ||
528 | { | ||
529 | debug_timer_init(timer); | ||
530 | trace_timer_init(timer); | ||
531 | } | ||
532 | |||
533 | static inline void | ||
534 | debug_activate(struct timer_list *timer, unsigned long expires) | ||
535 | { | ||
536 | debug_timer_activate(timer); | ||
537 | trace_timer_start(timer, expires); | ||
538 | } | ||
539 | |||
540 | static inline void debug_deactivate(struct timer_list *timer) | ||
541 | { | ||
542 | debug_timer_deactivate(timer); | ||
543 | trace_timer_cancel(timer); | ||
544 | } | ||
545 | |||
524 | static void __init_timer(struct timer_list *timer, | 546 | static void __init_timer(struct timer_list *timer, |
525 | const char *name, | 547 | const char *name, |
526 | struct lock_class_key *key) | 548 | struct lock_class_key *key) |
@@ -549,7 +571,7 @@ void init_timer_key(struct timer_list *timer, | |||
549 | const char *name, | 571 | const char *name, |
550 | struct lock_class_key *key) | 572 | struct lock_class_key *key) |
551 | { | 573 | { |
552 | debug_timer_init(timer); | 574 | debug_init(timer); |
553 | __init_timer(timer, name, key); | 575 | __init_timer(timer, name, key); |
554 | } | 576 | } |
555 | EXPORT_SYMBOL(init_timer_key); | 577 | EXPORT_SYMBOL(init_timer_key); |
@@ -568,7 +590,7 @@ static inline void detach_timer(struct timer_list *timer, | |||
568 | { | 590 | { |
569 | struct list_head *entry = &timer->entry; | 591 | struct list_head *entry = &timer->entry; |
570 | 592 | ||
571 | debug_timer_deactivate(timer); | 593 | debug_deactivate(timer); |
572 | 594 | ||
573 | __list_del(entry->prev, entry->next); | 595 | __list_del(entry->prev, entry->next); |
574 | if (clear_pending) | 596 | if (clear_pending) |
@@ -632,7 +654,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, | |||
632 | goto out_unlock; | 654 | goto out_unlock; |
633 | } | 655 | } |
634 | 656 | ||
635 | debug_timer_activate(timer); | 657 | debug_activate(timer, expires); |
636 | 658 | ||
637 | new_base = __get_cpu_var(tvec_bases); | 659 | new_base = __get_cpu_var(tvec_bases); |
638 | 660 | ||
@@ -787,7 +809,7 @@ void add_timer_on(struct timer_list *timer, int cpu) | |||
787 | BUG_ON(timer_pending(timer) || !timer->function); | 809 | BUG_ON(timer_pending(timer) || !timer->function); |
788 | spin_lock_irqsave(&base->lock, flags); | 810 | spin_lock_irqsave(&base->lock, flags); |
789 | timer_set_base(timer, base); | 811 | timer_set_base(timer, base); |
790 | debug_timer_activate(timer); | 812 | debug_activate(timer, timer->expires); |
791 | if (time_before(timer->expires, base->next_timer) && | 813 | if (time_before(timer->expires, base->next_timer) && |
792 | !tbase_get_deferrable(timer->base)) | 814 | !tbase_get_deferrable(timer->base)) |
793 | base->next_timer = timer->expires; | 815 | base->next_timer = timer->expires; |
@@ -1000,7 +1022,9 @@ static inline void __run_timers(struct tvec_base *base) | |||
1000 | */ | 1022 | */ |
1001 | lock_map_acquire(&lockdep_map); | 1023 | lock_map_acquire(&lockdep_map); |
1002 | 1024 | ||
1025 | trace_timer_expire_entry(timer); | ||
1003 | fn(data); | 1026 | fn(data); |
1027 | trace_timer_expire_exit(timer); | ||
1004 | 1028 | ||
1005 | lock_map_release(&lockdep_map); | 1029 | lock_map_release(&lockdep_map); |
1006 | 1030 | ||