Add a flag to indicate deferrable timers in /proc/timer_stats
authorVenki Pallipadi <venkatesh.pallipadi@intel.com>
Mon, 16 Jul 2007 06:40:30 +0000 (23:40 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 16 Jul 2007 16:05:45 +0000 (09:05 -0700)
Add a flag in /proc/timer_stats to indicate deferrable timers.  This will
let developers/users to differentiate between types of tiemrs in
/proc/timer_stats.

Deferrable timer and normal timer will appear in /proc/timer_stats as below.
  10D,     1 swapper          queue_delayed_work_on (delayed_work_timer_fn)
   10,     1 swapper          queue_delayed_work_on (delayed_work_timer_fn)

Also version of timer_stats changes from v0.1 to v0.2

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/hrtimer/timer_stats.txt
include/linux/hrtimer.h
include/linux/timer.h
kernel/time/timer_stats.c
kernel/timer.c

index 22b0814d0ad0927024de028303a4af9cce0afc11..20d368c59814206d82dfa2236bdf6764fd5bee85 100644 (file)
@@ -67,3 +67,7 @@ executed on expiry.
 
     Thomas, Ingo
 
+Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable
+timer will appear as follows
+  10D,     1 swapper          queue_delayed_work_on (delayed_work_timer_fn)
+
index 17c29dca8354d2e88e8b971b5b02d290713e8b8b..540799bc85f864ad7569b50804ac7843ccdbe750 100644 (file)
@@ -329,12 +329,13 @@ extern void sysrq_timer_list_show(void);
 #ifdef CONFIG_TIMER_STATS
 
 extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
-                                    void *timerf, char * comm);
+                                    void *timerf, char *comm,
+                                    unsigned int timer_flag);
 
 static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
 {
        timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
-                                timer->function, timer->start_comm);
+                                timer->function, timer->start_comm, 0);
 }
 
 extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer,
index 2b59e6d4219cca2d66abc58db15a639b2427334a..78cf899b440969a44049f7c052e2f9e167b47bd5 100644 (file)
@@ -90,16 +90,13 @@ extern unsigned long get_next_timer_interrupt(unsigned long now);
  */
 #ifdef CONFIG_TIMER_STATS
 
+#define TIMER_STATS_FLAG_DEFERRABLE    0x1
+
 extern void init_timer_stats(void);
 
 extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
-                                    void *timerf, char * comm);
-
-static inline void timer_stats_account_timer(struct timer_list *timer)
-{
-       timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
-                                timer->function, timer->start_comm);
-}
+                                    void *timerf, char *comm,
+                                    unsigned int timer_flag);
 
 extern void __timer_stats_timer_set_start_info(struct timer_list *timer,
                                               void *addr);
@@ -118,10 +115,6 @@ static inline void init_timer_stats(void)
 {
 }
 
-static inline void timer_stats_account_timer(struct timer_list *timer)
-{
-}
-
 static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
 {
 }
index 321693724ad743a74d81c2b3add00f3d4ee21237..9b8a826236ddc4e4c3642f959d5186b52fa51269 100644 (file)
@@ -68,6 +68,7 @@ struct entry {
         * Number of timeout events:
         */
        unsigned long           count;
+       unsigned int            timer_flag;
 
        /*
         * We save the command-line string to preserve
@@ -231,7 +232,8 @@ static struct entry *tstat_lookup(struct entry *entry, char *comm)
  * incremented. Otherwise the timer is registered in a free slot.
  */
 void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
-                             void *timerf, char * comm)
+                             void *timerf, char *comm,
+                             unsigned int timer_flag)
 {
        /*
         * It doesnt matter which lock we take:
@@ -249,6 +251,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
        input.start_func = startf;
        input.expire_func = timerf;
        input.pid = pid;
+       input.timer_flag = timer_flag;
 
        spin_lock_irqsave(lock, flags);
        if (!active)
@@ -295,7 +298,7 @@ static int tstats_show(struct seq_file *m, void *v)
        period = ktime_to_timespec(time);
        ms = period.tv_nsec / 1000000;
 
-       seq_puts(m, "Timer Stats Version: v0.1\n");
+       seq_puts(m, "Timer Stats Version: v0.2\n");
        seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms);
        if (atomic_read(&overflow_count))
                seq_printf(m, "Overflow: %d entries\n",
@@ -303,8 +306,13 @@ static int tstats_show(struct seq_file *m, void *v)
 
        for (i = 0; i < nr_entries; i++) {
                entry = entries + i;
-               seq_printf(m, "%4lu, %5d %-16s ",
+               if (entry->timer_flag & TIMER_STATS_FLAG_DEFERRABLE) {
+                       seq_printf(m, "%4luD, %5d %-16s ",
                                entry->count, entry->pid, entry->comm);
+               } else {
+                       seq_printf(m, " %4lu, %5d %-16s ",
+                               entry->count, entry->pid, entry->comm);
+               }
 
                print_name_offset(m, (unsigned long)entry->start_func);
                seq_puts(m, " (");
index 1ab3106a2b5dba6c5f8de68a58b5e102f2eba720..1258371e0d2be3323ed7cb661c16a93355d30a2f 100644 (file)
@@ -305,6 +305,20 @@ void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
        memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
        timer->start_pid = current->pid;
 }
+
+static void timer_stats_account_timer(struct timer_list *timer)
+{
+       unsigned int flag = 0;
+
+       if (unlikely(tbase_get_deferrable(timer->base)))
+               flag |= TIMER_STATS_FLAG_DEFERRABLE;
+
+       timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
+                                timer->function, timer->start_comm, flag);
+}
+
+#else
+static void timer_stats_account_timer(struct timer_list *timer) {}
 #endif
 
 /**