When the kernel is configured with CONFIG_TIMER_STATS but timer
stats are runtime disabled we still get calls to
__timer_stats_timer_set_start_info which initializes some
fields in the corresponding struct timer_list.
So add some quick checks in the the timer stats setup functions
to avoid function calls to __timer_stats_timer_set_start_info
when timer stats are disabled.
In an artificial workload that does nothing but playing ping
pong with a single tcp packet via loopback this decreases cpu
consumption by 1 - 1.5%.
This is part of a modified function trace output on SLES11:
 perl-2497  [00] 
28630647177732388 [+  125]: sk_reset_timer <-tcp_v4_rcv
 perl-2497  [00] 
28630647177732513 [+  125]: mod_timer <-sk_reset_timer
 perl-2497  [00] 
28630647177732638 [+  125]: __timer_stats_timer_set_start_info <-mod_timer
 perl-2497  [00] 
28630647177732763 [+  125]: __mod_timer <-mod_timer
 perl-2497  [00] 
28630647177732888 [+  125]: __timer_stats_timer_set_start_info <-__mod_timer
 perl-2497  [00] 
28630647177733013 [+   93]: lock_timer_base <-__mod_timer
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Mustafa Mesanovic <mustafa.mesanovic@de.ibm.com>
Cc: Arjan van de Ven <arjan@infradead.org>
LKML-Reference: <
20090623153811.GA4641@osiris.boeblingen.de.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
 
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/percpu.h>
+#include <linux/timer.h>
 
 
 struct hrtimer_clock_base;
 
 static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
 {
+       if (likely(!timer->start_pid))
+               return;
        timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
                                 timer->function, timer->start_comm, 0);
 }
 
 static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer)
 {
+       if (likely(!timer_stats_active))
+               return;
        __timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0));
 }
 
 
  */
 #ifdef CONFIG_TIMER_STATS
 
+extern int timer_stats_active;
+
 #define TIMER_STATS_FLAG_DEFERRABLE    0x1
 
 extern void init_timer_stats(void);
 
 static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
 {
+       if (likely(!timer_stats_active))
+               return;
        __timer_stats_timer_set_start_info(timer, __builtin_return_address(0));
 }
 
 
 /*
  * Collection status, active/inactive:
  */
-static int __read_mostly active;
+int __read_mostly timer_stats_active;
 
 /*
  * Beginning/end timestamps of measurement:
        struct entry *entry, input;
        unsigned long flags;
 
-       if (likely(!active))
+       if (likely(!timer_stats_active))
                return;
 
        lock = &per_cpu(lookup_lock, raw_smp_processor_id());
        input.timer_flag = timer_flag;
 
        spin_lock_irqsave(lock, flags);
-       if (!active)
+       if (!timer_stats_active)
                goto out_unlock;
 
        entry = tstat_lookup(&input, comm);
        /*
         * If still active then calculate up to now:
         */
-       if (active)
+       if (timer_stats_active)
                time_stop = ktime_get();
 
        time = ktime_sub(time_stop, time_start);
        mutex_lock(&show_mutex);
        switch (ctl[0]) {
        case '0':
-               if (active) {
-                       active = 0;
+               if (timer_stats_active) {
+                       timer_stats_active = 0;
                        time_stop = ktime_get();
                        sync_access();
                }
                break;
        case '1':
-               if (!active) {
+               if (!timer_stats_active) {
                        reset_entries();
                        time_start = ktime_get();
                        smp_mb();
-                       active = 1;
+                       timer_stats_active = 1;
                }
                break;
        default:
 
 {
        unsigned int flag = 0;
 
+       if (likely(!timer->start_site))
+               return;
        if (unlikely(tbase_get_deferrable(timer->base)))
                flag |= TIMER_STATS_FLAG_DEFERRABLE;