Skip to content

Commit

Permalink
hrtimers: Avoid touching inactive timer bases
Browse files Browse the repository at this point in the history
Instead of iterating over all possible timer bases avoid it by marking
the active bases in the cpu base.

Signed-off-by: Thomas Gleixner <[email protected]>
Reviewed-by: Peter Zijlstra <[email protected]>
  • Loading branch information
KAGA-KOKO committed May 23, 2011
1 parent f24444b commit ab8177b
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 19 deletions.
7 changes: 5 additions & 2 deletions include/linux/hrtimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/linux/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 18 additions & 11 deletions kernel/hrtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand All @@ -1257,12 +1262,15 @@ void hrtimer_interrupt(struct clock_event_device *dev)
*/
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))) {
Expand Down Expand Up @@ -1295,7 +1303,6 @@ void hrtimer_interrupt(struct clock_event_device *dev)

__run_hrtimer(timer, &basenow);
}
base++;
}

/*
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions kernel/posix-cpu-timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion kernel/posix-timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions kernel/time/alarmtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit ab8177b

Please sign in to comment.