diff options
author | Ingo Molnar <mingo@elte.hu> | 2007-02-16 04:28:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:59 -0500 |
commit | 82f67cd9fca8c8762c15ba7ed0d5747588c1e221 (patch) | |
tree | 1ff7e5cc496580b85bb42fb1d7b19dcbef7b7776 /include/linux | |
parent | 8bfd9a7a229b5f3d3eda5d7d45c2eebec5b4ba16 (diff) |
[PATCH] Add debugging feature /proc/timer_stat
Add /proc/timer_stats support: debugging feature to profile timer expiration.
Both the starting site, process/PID and the expiration function is captured.
This allows the quick identification of timer event sources in a system.
Sample output:
# echo 1 > /proc/timer_stats
# cat /proc/timer_stats
Timer Stats Version: v0.1
Sample period: 4.010 s
24, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick)
11, 0 swapper sk_reset_timer (tcp_delack_timer)
6, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick)
2, 1 swapper queue_delayed_work_on (delayed_work_timer_fn)
17, 0 swapper hrtimer_restart_sched_tick (hrtimer_sched_tick)
2, 1 swapper queue_delayed_work_on (delayed_work_timer_fn)
4, 2050 pcscd do_nanosleep (hrtimer_wakeup)
5, 4179 sshd sk_reset_timer (tcp_write_timer)
4, 2248 yum-updatesd schedule_timeout (process_timeout)
18, 0 swapper hrtimer_restart_sched_tick (hrtimer_sched_tick)
3, 0 swapper sk_reset_timer (tcp_delack_timer)
1, 1 swapper neigh_table_init_no_netlink (neigh_periodic_timer)
2, 1 swapper e1000_up (e1000_watchdog)
1, 1 init schedule_timeout (process_timeout)
100 total events, 25.24 events/sec
[ cleanups and hrtimers support from Thomas Gleixner <tglx@linutronix.de> ]
[bunk@stusta.de: nr_entries can become static]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Roman Zippel <zippel@linux-m68k.org>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/hrtimer.h | 45 | ||||
-rw-r--r-- | include/linux/timer.h | 54 |
2 files changed, 99 insertions, 0 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 4ecd991431b4..93b8757c1ea2 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -119,6 +119,11 @@ struct hrtimer { | |||
119 | enum hrtimer_cb_mode cb_mode; | 119 | enum hrtimer_cb_mode cb_mode; |
120 | struct list_head cb_entry; | 120 | struct list_head cb_entry; |
121 | #endif | 121 | #endif |
122 | #ifdef CONFIG_TIMER_STATS | ||
123 | void *start_site; | ||
124 | char start_comm[16]; | ||
125 | int start_pid; | ||
126 | #endif | ||
122 | }; | 127 | }; |
123 | 128 | ||
124 | /** | 129 | /** |
@@ -311,4 +316,44 @@ extern unsigned long ktime_divns(const ktime_t kt, s64 div); | |||
311 | # define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div)) | 316 | # define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div)) |
312 | #endif | 317 | #endif |
313 | 318 | ||
319 | /* | ||
320 | * Timer-statistics info: | ||
321 | */ | ||
322 | #ifdef CONFIG_TIMER_STATS | ||
323 | |||
324 | extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | ||
325 | void *timerf, char * comm); | ||
326 | |||
327 | static inline void timer_stats_account_hrtimer(struct hrtimer *timer) | ||
328 | { | ||
329 | timer_stats_update_stats(timer, timer->start_pid, timer->start_site, | ||
330 | timer->function, timer->start_comm); | ||
331 | } | ||
332 | |||
333 | extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, | ||
334 | void *addr); | ||
335 | |||
336 | static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) | ||
337 | { | ||
338 | __timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0)); | ||
339 | } | ||
340 | |||
341 | static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer) | ||
342 | { | ||
343 | timer->start_site = NULL; | ||
344 | } | ||
345 | #else | ||
346 | static inline void timer_stats_account_hrtimer(struct hrtimer *timer) | ||
347 | { | ||
348 | } | ||
349 | |||
350 | static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) | ||
351 | { | ||
352 | } | ||
353 | |||
354 | static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer) | ||
355 | { | ||
356 | } | ||
357 | #endif | ||
358 | |||
314 | #endif | 359 | #endif |
diff --git a/include/linux/timer.h b/include/linux/timer.h index 44d41e9d7818..719113b652dd 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _LINUX_TIMER_H | 2 | #define _LINUX_TIMER_H |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <linux/ktime.h> | ||
5 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
6 | #include <linux/stddef.h> | 7 | #include <linux/stddef.h> |
7 | 8 | ||
@@ -15,6 +16,11 @@ struct timer_list { | |||
15 | unsigned long data; | 16 | unsigned long data; |
16 | 17 | ||
17 | struct tvec_t_base_s *base; | 18 | struct tvec_t_base_s *base; |
19 | #ifdef CONFIG_TIMER_STATS | ||
20 | void *start_site; | ||
21 | char start_comm[16]; | ||
22 | int start_pid; | ||
23 | #endif | ||
18 | }; | 24 | }; |
19 | 25 | ||
20 | extern struct tvec_t_base_s boot_tvec_bases; | 26 | extern struct tvec_t_base_s boot_tvec_bases; |
@@ -73,6 +79,54 @@ extern unsigned long next_timer_interrupt(void); | |||
73 | */ | 79 | */ |
74 | extern unsigned long get_next_timer_interrupt(unsigned long now); | 80 | extern unsigned long get_next_timer_interrupt(unsigned long now); |
75 | 81 | ||
82 | /* | ||
83 | * Timer-statistics info: | ||
84 | */ | ||
85 | #ifdef CONFIG_TIMER_STATS | ||
86 | |||
87 | extern void init_timer_stats(void); | ||
88 | |||
89 | extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, | ||
90 | void *timerf, char * comm); | ||
91 | |||
92 | static inline void timer_stats_account_timer(struct timer_list *timer) | ||
93 | { | ||
94 | timer_stats_update_stats(timer, timer->start_pid, timer->start_site, | ||
95 | timer->function, timer->start_comm); | ||
96 | } | ||
97 | |||
98 | extern void __timer_stats_timer_set_start_info(struct timer_list *timer, | ||
99 | void *addr); | ||
100 | |||
101 | static inline void timer_stats_timer_set_start_info(struct timer_list *timer) | ||
102 | { | ||
103 | __timer_stats_timer_set_start_info(timer, __builtin_return_address(0)); | ||
104 | } | ||
105 | |||
106 | static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) | ||
107 | { | ||
108 | timer->start_site = NULL; | ||
109 | } | ||
110 | #else | ||
111 | static inline void init_timer_stats(void) | ||
112 | { | ||
113 | } | ||
114 | |||
115 | static inline void timer_stats_account_timer(struct timer_list *timer) | ||
116 | { | ||
117 | } | ||
118 | |||
119 | static inline void timer_stats_timer_set_start_info(struct timer_list *timer) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) | ||
124 | { | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | extern void delayed_work_timer_fn(unsigned long __data); | ||
129 | |||
76 | /** | 130 | /** |
77 | * add_timer - start a timer | 131 | * add_timer - start a timer |
78 | * @timer: the timer to be added | 132 | * @timer: the timer to be added |