diff options
Diffstat (limited to 'kernel/timer.c')
-rw-r--r-- | kernel/timer.c | 31 |
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 | ||
268 | void __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 | } |
278 | EXPORT_SYMBOL(init_timer); | 296 | EXPORT_SYMBOL(init_timer); |
279 | 297 | ||
280 | static inline void detach_timer(struct timer_list *timer, | 298 | static 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); |