Commit 2b022e3d4bf9885f781221c59d86283a2cdfc2ed

Authored by Xiao Guangrong
Committed by Thomas Gleixner
1 parent f71bb0ac5e

timers: Add tracepoints for timer_list timers

Add tracepoints which cover the timer life cycle. The tracepoints are
integrated with the already existing debug_object debug points as far
as possible.

Based on patches from
Mathieu: http://marc.info/?l=linux-kernel&m=123791201816247&w=2
and
Anton: http://marc.info/?l=linux-kernel&m=124331396919301&w=2

[ tglx: Fixed timeout value in timer_start tracepoint, massaged
  comments and made the printk's more readable ]

Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Cc: Anton Blanchard <anton@samba.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Zhaolei <zhaolei@cn.fujitsu.com>
LKML-Reference: <4A7F8A9B.3040201@cn.fujitsu.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Showing 2 changed files with 165 additions and 4 deletions Side-by-side Diff

include/trace/events/timer.h
  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>
... ... @@ -46,6 +46,9 @@
46 46 #include <asm/timex.h>
47 47 #include <asm/io.h>
48 48  
  49 +#define CREATE_TRACE_POINTS
  50 +#include <trace/events/timer.h>
  51 +
49 52 u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
50 53  
51 54 EXPORT_SYMBOL(jiffies_64);
... ... @@ -521,6 +524,25 @@
521 524 static inline void debug_timer_deactivate(struct timer_list *timer) { }
522 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 546 static void __init_timer(struct timer_list *timer,
525 547 const char *name,
526 548 struct lock_class_key *key)
... ... @@ -549,7 +571,7 @@
549 571 const char *name,
550 572 struct lock_class_key *key)
551 573 {
552   - debug_timer_init(timer);
  574 + debug_init(timer);
553 575 __init_timer(timer, name, key);
554 576 }
555 577 EXPORT_SYMBOL(init_timer_key);
... ... @@ -568,7 +590,7 @@
568 590 {
569 591 struct list_head *entry = &timer->entry;
570 592  
571   - debug_timer_deactivate(timer);
  593 + debug_deactivate(timer);
572 594  
573 595 __list_del(entry->prev, entry->next);
574 596 if (clear_pending)
... ... @@ -632,7 +654,7 @@
632 654 goto out_unlock;
633 655 }
634 656  
635   - debug_timer_activate(timer);
  657 + debug_activate(timer, expires);
636 658  
637 659 new_base = __get_cpu_var(tvec_bases);
638 660  
... ... @@ -787,7 +809,7 @@
787 809 BUG_ON(timer_pending(timer) || !timer->function);
788 810 spin_lock_irqsave(&base->lock, flags);
789 811 timer_set_base(timer, base);
790   - debug_timer_activate(timer);
  812 + debug_activate(timer, timer->expires);
791 813 if (time_before(timer->expires, base->next_timer) &&
792 814 !tbase_get_deferrable(timer->base))
793 815 base->next_timer = timer->expires;
794 816  
... ... @@ -1000,7 +1022,9 @@
1000 1022 */
1001 1023 lock_map_acquire(&lockdep_map);
1002 1024  
  1025 + trace_timer_expire_entry(timer);
1003 1026 fn(data);
  1027 + trace_timer_expire_exit(timer);
1004 1028  
1005 1029 lock_map_release(&lockdep_map);
1006 1030