Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hrtimers: Avoid touching inactive timer bases

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>

+29 -19
+5 -2
include/linux/hrtimer.h
··· 143 143 */ 144 144 struct hrtimer_clock_base { 145 145 struct hrtimer_cpu_base *cpu_base; 146 - clockid_t index; 146 + int index; 147 + clockid_t clockid; 147 148 struct timerqueue_head active; 148 149 ktime_t resolution; 149 150 ktime_t (*get_time)(void); ··· 163 162 * struct hrtimer_cpu_base - the per cpu clock bases 164 163 * @lock: lock protecting the base and associated clock bases 165 164 * and timers 166 - * @clock_base: array of clock bases for this cpu 165 + * @active_bases: Bitfield to mark bases with active timers 167 166 * @expires_next: absolute time of the next event which was scheduled 168 167 * via clock_set_next_event() 169 168 * @hres_active: State of high resolution mode ··· 172 171 * @nr_retries: Total number of hrtimer interrupt retries 173 172 * @nr_hangs: Total number of hrtimer interrupt hangs 174 173 * @max_hang_time: Maximum time spent in hrtimer_interrupt 174 + * @clock_base: array of clock bases for this cpu 175 175 */ 176 176 struct hrtimer_cpu_base { 177 177 raw_spinlock_t lock; 178 + unsigned long active_bases; 178 179 #ifdef CONFIG_HIGH_RES_TIMERS 179 180 ktime_t expires_next; 180 181 int hres_active;
+1 -1
include/linux/thread_info.h
··· 29 29 } futex; 30 30 /* For nanosleep */ 31 31 struct { 32 - clockid_t index; 32 + clockid_t clockid; 33 33 struct timespec __user *rmtp; 34 34 #ifdef CONFIG_COMPAT 35 35 struct compat_timespec __user *compat_rmtp;
+18 -11
kernel/hrtimer.c
··· 64 64 .clock_base = 65 65 { 66 66 { 67 - .index = CLOCK_REALTIME, 67 + .index = HRTIMER_BASE_REALTIME, 68 + .clockid = CLOCK_REALTIME, 68 69 .get_time = &ktime_get_real, 69 70 .resolution = KTIME_LOW_RES, 70 71 }, 71 72 { 72 - .index = CLOCK_MONOTONIC, 73 + .index = HRTIMER_BASE_MONOTONIC, 74 + .clockid = CLOCK_MONOTONIC, 73 75 .get_time = &ktime_get, 74 76 .resolution = KTIME_LOW_RES, 75 77 }, 76 78 { 77 - .index = CLOCK_BOOTTIME, 79 + .index = HRTIMER_BASE_BOOTTIME, 80 + .clockid = CLOCK_BOOTTIME, 78 81 .get_time = &ktime_get_boottime, 79 82 .resolution = KTIME_LOW_RES, 80 83 }, ··· 199 196 struct hrtimer_cpu_base *new_cpu_base; 200 197 int this_cpu = smp_processor_id(); 201 198 int cpu = hrtimer_get_target(this_cpu, pinned); 202 - int basenum = hrtimer_clockid_to_base(base->index); 199 + int basenum = base->index; 203 200 204 201 again: 205 202 new_cpu_base = &per_cpu(hrtimer_bases, cpu); ··· 860 857 debug_activate(timer); 861 858 862 859 timerqueue_add(&base->active, &timer->node); 860 + base->cpu_base->active_bases |= 1 << base->index; 863 861 864 862 /* 865 863 * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the ··· 902 898 #endif 903 899 } 904 900 timerqueue_del(&base->active, &timer->node); 901 + if (!timerqueue_getnext(&base->active)) 902 + base->cpu_base->active_bases &= ~(1 << base->index); 905 903 out: 906 904 timer->state = newstate; 907 905 } ··· 1241 1235 void hrtimer_interrupt(struct clock_event_device *dev) 1242 1236 { 1243 1237 struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); 1244 - struct hrtimer_clock_base *base; 1245 1238 ktime_t expires_next, now, entry_time, delta; 1246 1239 int i, retries = 0; 1247 1240 ··· 1262 1257 */ 1263 1258 cpu_base->expires_next.tv64 = KTIME_MAX; 1264 1259 1265 - base = cpu_base->clock_base; 1266 - 1267 1260 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { 1268 - ktime_t basenow; 1261 + struct hrtimer_clock_base *base; 1269 1262 struct timerqueue_node *node; 1263 + ktime_t basenow; 1270 1264 1265 + if (!(cpu_base->active_bases & (1 << i))) 1266 + continue; 1267 + 1268 + base = cpu_base->clock_base + i; 1271 1269 basenow = ktime_add(now, base->offset); 1272 1270 1273 1271 while ((node = timerqueue_getnext(&base->active))) { ··· 1303 1295 1304 1296 __run_hrtimer(timer, &basenow); 1305 1297 } 1306 - base++; 1307 1298 } 1308 1299 1309 1300 /* ··· 1533 1526 struct timespec __user *rmtp; 1534 1527 int ret = 0; 1535 1528 1536 - hrtimer_init_on_stack(&t.timer, restart->nanosleep.index, 1529 + hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, 1537 1530 HRTIMER_MODE_ABS); 1538 1531 hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); 1539 1532 ··· 1585 1578 1586 1579 restart = &current_thread_info()->restart_block; 1587 1580 restart->fn = hrtimer_nanosleep_restart; 1588 - restart->nanosleep.index = t.timer.base->index; 1581 + restart->nanosleep.clockid = t.timer.base->clockid; 1589 1582 restart->nanosleep.rmtp = rmtp; 1590 1583 restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); 1591 1584
+2 -2
kernel/posix-cpu-timers.c
··· 1514 1514 return -EFAULT; 1515 1515 1516 1516 restart_block->fn = posix_cpu_nsleep_restart; 1517 - restart_block->nanosleep.index = which_clock; 1517 + restart_block->nanosleep.clockid = which_clock; 1518 1518 restart_block->nanosleep.rmtp = rmtp; 1519 1519 restart_block->nanosleep.expires = timespec_to_ns(rqtp); 1520 1520 } ··· 1523 1523 1524 1524 static long posix_cpu_nsleep_restart(struct restart_block *restart_block) 1525 1525 { 1526 - clockid_t which_clock = restart_block->nanosleep.index; 1526 + clockid_t which_clock = restart_block->nanosleep.clockid; 1527 1527 struct timespec t; 1528 1528 struct itimerspec it; 1529 1529 int error;
+1 -1
kernel/posix-timers.c
··· 1056 1056 */ 1057 1057 long clock_nanosleep_restart(struct restart_block *restart_block) 1058 1058 { 1059 - clockid_t which_clock = restart_block->nanosleep.index; 1059 + clockid_t which_clock = restart_block->nanosleep.clockid; 1060 1060 struct k_clock *kc = clockid_to_kclock(which_clock); 1061 1061 1062 1062 if (WARN_ON_ONCE(!kc || !kc->nsleep_restart))
+2 -2
kernel/time/alarmtimer.c
··· 494 494 */ 495 495 static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) 496 496 { 497 - enum alarmtimer_type type = restart->nanosleep.index; 497 + enum alarmtimer_type type = restart->nanosleep.clockid; 498 498 ktime_t exp; 499 499 struct timespec __user *rmtp; 500 500 struct alarm alarm; ··· 573 573 574 574 restart = &current_thread_info()->restart_block; 575 575 restart->fn = alarm_timer_nsleep_restart; 576 - restart->nanosleep.index = type; 576 + restart->nanosleep.clockid = type; 577 577 restart->nanosleep.expires = exp.tv64; 578 578 restart->nanosleep.rmtp = rmtp; 579 579 ret = -ERESTART_RESTARTBLOCK;