aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/timer.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2007-02-16 04:28:13 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:13:59 -0500
commit82f67cd9fca8c8762c15ba7ed0d5747588c1e221 (patch)
tree1ff7e5cc496580b85bb42fb1d7b19dcbef7b7776 /kernel/timer.c
parent8bfd9a7a229b5f3d3eda5d7d45c2eebec5b4ba16 (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 'kernel/timer.c')
-rw-r--r--kernel/timer.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index f058e6cfd50c..c3c67f3c0190 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -35,6 +35,7 @@
35#include <linux/syscalls.h> 35#include <linux/syscalls.h>
36#include <linux/delay.h> 36#include <linux/delay.h>
37#include <linux/tick.h> 37#include <linux/tick.h>
38#include <linux/kallsyms.h>
38 39
39#include <asm/uaccess.h> 40#include <asm/uaccess.h>
40#include <asm/unistd.h> 41#include <asm/unistd.h>
@@ -263,6 +264,18 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
263 list_add_tail(&timer->entry, vec); 264 list_add_tail(&timer->entry, vec);
264} 265}
265 266
267#ifdef CONFIG_TIMER_STATS
268void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
269{
270 if (timer->start_site)
271 return;
272
273 timer->start_site = addr;
274 memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
275 timer->start_pid = current->pid;
276}
277#endif
278
266/** 279/**
267 * init_timer - initialize a timer. 280 * init_timer - initialize a timer.
268 * @timer: the timer to be initialized 281 * @timer: the timer to be initialized
@@ -274,11 +287,16 @@ void fastcall init_timer(struct timer_list *timer)
274{ 287{
275 timer->entry.next = NULL; 288 timer->entry.next = NULL;
276 timer->base = __raw_get_cpu_var(tvec_bases); 289 timer->base = __raw_get_cpu_var(tvec_bases);
290#ifdef CONFIG_TIMER_STATS
291 timer->start_site = NULL;
292 timer->start_pid = -1;
293 memset(timer->start_comm, 0, TASK_COMM_LEN);
294#endif
277} 295}
278EXPORT_SYMBOL(init_timer); 296EXPORT_SYMBOL(init_timer);
279 297
280static inline void detach_timer(struct timer_list *timer, 298static inline void detach_timer(struct timer_list *timer,
281 int clear_pending) 299 int clear_pending)
282{ 300{
283 struct list_head *entry = &timer->entry; 301 struct list_head *entry = &timer->entry;
284 302
@@ -325,6 +343,7 @@ int __mod_timer(struct timer_list *timer, unsigned long expires)
325 unsigned long flags; 343 unsigned long flags;
326 int ret = 0; 344 int ret = 0;
327 345
346 timer_stats_timer_set_start_info(timer);
328 BUG_ON(!timer->function); 347 BUG_ON(!timer->function);
329 348
330 base = lock_timer_base(timer, &flags); 349 base = lock_timer_base(timer, &flags);
@@ -375,6 +394,7 @@ void add_timer_on(struct timer_list *timer, int cpu)
375 tvec_base_t *base = per_cpu(tvec_bases, cpu); 394 tvec_base_t *base = per_cpu(tvec_bases, cpu);
376 unsigned long flags; 395 unsigned long flags;
377 396
397 timer_stats_timer_set_start_info(timer);
378 BUG_ON(timer_pending(timer) || !timer->function); 398 BUG_ON(timer_pending(timer) || !timer->function);
379 spin_lock_irqsave(&base->lock, flags); 399 spin_lock_irqsave(&base->lock, flags);
380 timer->base = base; 400 timer->base = base;
@@ -407,6 +427,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
407{ 427{
408 BUG_ON(!timer->function); 428 BUG_ON(!timer->function);
409 429
430 timer_stats_timer_set_start_info(timer);
410 /* 431 /*
411 * This is a common optimization triggered by the 432 * This is a common optimization triggered by the
412 * networking code - if the timer is re-modified 433 * networking code - if the timer is re-modified
@@ -437,6 +458,7 @@ int del_timer(struct timer_list *timer)
437 unsigned long flags; 458 unsigned long flags;
438 int ret = 0; 459 int ret = 0;
439 460
461 timer_stats_timer_clear_start_info(timer);
440 if (timer_pending(timer)) { 462 if (timer_pending(timer)) {
441 base = lock_timer_base(timer, &flags); 463 base = lock_timer_base(timer, &flags);
442 if (timer_pending(timer)) { 464 if (timer_pending(timer)) {
@@ -570,6 +592,8 @@ static inline void __run_timers(tvec_base_t *base)
570 fn = timer->function; 592 fn = timer->function;
571 data = timer->data; 593 data = timer->data;
572 594
595 timer_stats_account_timer(timer);
596
573 set_running_timer(base, timer); 597 set_running_timer(base, timer);
574 detach_timer(timer, 1); 598 detach_timer(timer, 1);
575 spin_unlock_irq(&base->lock); 599 spin_unlock_irq(&base->lock);
@@ -1229,7 +1253,8 @@ static void run_timer_softirq(struct softirq_action *h)
1229{ 1253{
1230 tvec_base_t *base = __get_cpu_var(tvec_bases); 1254 tvec_base_t *base = __get_cpu_var(tvec_bases);
1231 1255
1232 hrtimer_run_queues(); 1256 hrtimer_run_queues();
1257
1233 if (time_after_eq(jiffies, base->timer_jiffies)) 1258 if (time_after_eq(jiffies, base->timer_jiffies))
1234 __run_timers(base); 1259 __run_timers(base);
1235} 1260}
@@ -1675,6 +1700,8 @@ void __init init_timers(void)
1675 int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, 1700 int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
1676 (void *)(long)smp_processor_id()); 1701 (void *)(long)smp_processor_id());
1677 1702
1703 init_timer_stats();
1704
1678 BUG_ON(err == NOTIFY_BAD); 1705 BUG_ON(err == NOTIFY_BAD);
1679 register_cpu_notifier(&timers_nb); 1706 register_cpu_notifier(&timers_nb);
1680 open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL); 1707 open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);