hrtimers: Avoid touching inactive timer bases
Thomas Gleixner [Fri, 20 May 2011 11:05:15 +0000 (13:05 +0200)]
Instead of iterating over all possible timer bases avoid it by marking
the active bases in the cpu base.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Peter Zijlstra <peterz@infradead.org>

include/linux/hrtimer.h
include/linux/thread_info.h
kernel/hrtimer.c
kernel/posix-cpu-timers.c
kernel/posix-timers.c
kernel/time/alarmtimer.c

index cc5f5f5..771c958 100644 (file)
@@ -143,7 +143,8 @@ struct hrtimer_sleeper {
  */
 struct hrtimer_clock_base {
        struct hrtimer_cpu_base *cpu_base;
-       clockid_t               index;
+       int                     index;
+       clockid_t               clockid;
        struct timerqueue_head  active;
        ktime_t                 resolution;
        ktime_t                 (*get_time)(void);
@@ -162,7 +163,7 @@ enum  hrtimer_base_type {
  * struct hrtimer_cpu_base - the per cpu clock bases
  * @lock:              lock protecting the base and associated clock bases
  *                     and timers
- * @clock_base:                array of clock bases for this cpu
+ * @active_bases:      Bitfield to mark bases with active timers
  * @expires_next:      absolute time of the next event which was scheduled
  *                     via clock_set_next_event()
  * @hres_active:       State of high resolution mode
@@ -171,9 +172,11 @@ enum  hrtimer_base_type {
  * @nr_retries:                Total number of hrtimer interrupt retries
  * @nr_hangs:          Total number of hrtimer interrupt hangs
  * @max_hang_time:     Maximum time spent in hrtimer_interrupt
+ * @clock_base:                array of clock bases for this cpu
  */
 struct hrtimer_cpu_base {
        raw_spinlock_t                  lock;
+       unsigned long                   active_bases;
 #ifdef CONFIG_HIGH_RES_TIMERS
        ktime_t                         expires_next;
        int                             hres_active;
index 20fc303..8d03f07 100644 (file)
@@ -29,7 +29,7 @@ struct restart_block {
                } futex;
                /* For nanosleep */
                struct {
-                       clockid_t index;
+                       clockid_t clockid;
                        struct timespec __user *rmtp;
 #ifdef CONFIG_COMPAT
                        struct compat_timespec __user *compat_rmtp;
index 26dd32f..1b08f6d 100644 (file)
@@ -64,17 +64,20 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
        .clock_base =
        {
                {
-                       .index = CLOCK_REALTIME,
+                       .index = HRTIMER_BASE_REALTIME,
+                       .clockid = CLOCK_REALTIME,
                        .get_time = &ktime_get_real,
                        .resolution = KTIME_LOW_RES,
                },
                {
-                       .index = CLOCK_MONOTONIC,
+                       .index = HRTIMER_BASE_MONOTONIC,
+                       .clockid = CLOCK_MONOTONIC,
                        .get_time = &ktime_get,
                        .resolution = KTIME_LOW_RES,
                },
                {
-                       .index = CLOCK_BOOTTIME,
+                       .index = HRTIMER_BASE_BOOTTIME,
+                       .clockid = CLOCK_BOOTTIME,
                        .get_time = &ktime_get_boottime,
                        .resolution = KTIME_LOW_RES,
                },
@@ -196,7 +199,7 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
        struct hrtimer_cpu_base *new_cpu_base;
        int this_cpu = smp_processor_id();
        int cpu = hrtimer_get_target(this_cpu, pinned);
-       int basenum = hrtimer_clockid_to_base(base->index);
+       int basenum = base->index;
 
 again:
        new_cpu_base = &per_cpu(hrtimer_bases, cpu);
@@ -857,6 +860,7 @@ static int enqueue_hrtimer(struct hrtimer *timer,
        debug_activate(timer);
 
        timerqueue_add(&base->active, &timer->node);
+       base->cpu_base->active_bases |= 1 << base->index;
 
        /*
         * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the
@@ -898,6 +902,8 @@ static void __remove_hrtimer(struct hrtimer *timer,
 #endif
        }
        timerqueue_del(&base->active, &timer->node);
+       if (!timerqueue_getnext(&base->active))
+               base->cpu_base->active_bases &= ~(1 << base->index);
 out:
        timer->state = newstate;
 }
@@ -1235,7 +1241,6 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now)
 void hrtimer_interrupt(struct clock_event_device *dev)
 {
        struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
-       struct hrtimer_clock_base *base;
        ktime_t expires_next, now, entry_time, delta;
        int i, retries = 0;
 
@@ -1257,12 +1262,15 @@ retry:
         */
        cpu_base->expires_next.tv64 = KTIME_MAX;
 
-       base = cpu_base->clock_base;
-
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
-               ktime_t basenow;
+               struct hrtimer_clock_base *base;
                struct timerqueue_node *node;
+               ktime_t basenow;
+
+               if (!(cpu_base->active_bases & (1 << i)))
+                       continue;
 
+               base = cpu_base->clock_base + i;
                basenow = ktime_add(now, base->offset);
 
                while ((node = timerqueue_getnext(&base->active))) {
@@ -1295,7 +1303,6 @@ retry:
 
                        __run_hrtimer(timer, &basenow);
                }
-               base++;
        }
 
        /*
@@ -1526,7 +1533,7 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
        struct timespec __user  *rmtp;
        int ret = 0;
 
-       hrtimer_init_on_stack(&t.timer, restart->nanosleep.index,
+       hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid,
                                HRTIMER_MODE_ABS);
        hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires);
 
@@ -1578,7 +1585,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
 
        restart = &current_thread_info()->restart_block;
        restart->fn = hrtimer_nanosleep_restart;
-       restart->nanosleep.index = t.timer.base->index;
+       restart->nanosleep.clockid = t.timer.base->clockid;
        restart->nanosleep.rmtp = rmtp;
        restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
 
index 0791b13..58f405b 100644 (file)
@@ -1514,7 +1514,7 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
                        return -EFAULT;
 
                restart_block->fn = posix_cpu_nsleep_restart;
-               restart_block->nanosleep.index = which_clock;
+               restart_block->nanosleep.clockid = which_clock;
                restart_block->nanosleep.rmtp = rmtp;
                restart_block->nanosleep.expires = timespec_to_ns(rqtp);
        }
@@ -1523,7 +1523,7 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
 
 static long posix_cpu_nsleep_restart(struct restart_block *restart_block)
 {
-       clockid_t which_clock = restart_block->nanosleep.index;
+       clockid_t which_clock = restart_block->nanosleep.clockid;
        struct timespec t;
        struct itimerspec it;
        int error;
index e5498d7..a1b5edf 100644 (file)
@@ -1056,7 +1056,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
  */
 long clock_nanosleep_restart(struct restart_block *restart_block)
 {
-       clockid_t which_clock = restart_block->nanosleep.index;
+       clockid_t which_clock = restart_block->nanosleep.clockid;
        struct k_clock *kc = clockid_to_kclock(which_clock);
 
        if (WARN_ON_ONCE(!kc || !kc->nsleep_restart))
index c6027fe..2d96624 100644 (file)
@@ -494,7 +494,7 @@ static int update_rmtp(ktime_t exp, enum  alarmtimer_type type,
  */
 static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
 {
-       enum  alarmtimer_type type = restart->nanosleep.index;
+       enum  alarmtimer_type type = restart->nanosleep.clockid;
        ktime_t exp;
        struct timespec __user  *rmtp;
        struct alarm alarm;
@@ -573,7 +573,7 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
 
        restart = &current_thread_info()->restart_block;
        restart->fn = alarm_timer_nsleep_restart;
-       restart->nanosleep.index = type;
+       restart->nanosleep.clockid = type;
        restart->nanosleep.expires = exp.tv64;
        restart->nanosleep.rmtp = rmtp;
        ret = -ERESTART_RESTARTBLOCK;