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

Configure Feed

Select the types of activity you want to include in your feed.

hrtimer: Provide LAZY_REARM mode

The hrtick timer is frequently rearmed before expiry and most of the time
the new expiry is past the armed one. As this happens on every context
switch it becomes expensive with scheduling heavy work loads especially in
virtual machines as the "hardware" reprogamming implies a VM exit.

Add a lazy rearm mode flag which skips the reprogamming if:

1) The timer was the first expiring timer before the rearm

2) The new expiry time is farther out than the armed time

This avoids a massive amount of reprogramming operations of the hrtick
timer for the price of eventually taking the alredy armed interrupt for
nothing.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.408524456@kernel.org

+27 -1
+8
include/linux/hrtimer.h
··· 31 31 * soft irq context 32 32 * HRTIMER_MODE_HARD - Timer callback function will be executed in 33 33 * hard irq context even on PREEMPT_RT. 34 + * HRTIMER_MODE_LAZY_REARM - Avoid reprogramming if the timer was the 35 + * first expiring timer and is moved into the 36 + * future. Special mode for the HRTICK timer to 37 + * avoid extensive reprogramming of the hardware, 38 + * which is expensive in virtual machines. Risks 39 + * a pointless expiry, but that's better than 40 + * reprogramming on every context switch, 34 41 */ 35 42 enum hrtimer_mode { 36 43 HRTIMER_MODE_ABS = 0x00, ··· 45 38 HRTIMER_MODE_PINNED = 0x02, 46 39 HRTIMER_MODE_SOFT = 0x04, 47 40 HRTIMER_MODE_HARD = 0x08, 41 + HRTIMER_MODE_LAZY_REARM = 0x10, 48 42 49 43 HRTIMER_MODE_ABS_PINNED = HRTIMER_MODE_ABS | HRTIMER_MODE_PINNED, 50 44 HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL | HRTIMER_MODE_PINNED,
+3
include/linux/hrtimer_types.h
··· 33 33 * @is_soft: Set if hrtimer will be expired in soft interrupt context. 34 34 * @is_hard: Set if hrtimer will be expired in hard interrupt context 35 35 * even on RT. 36 + * @is_lazy: Set if the timer is frequently rearmed to avoid updates 37 + * of the clock event device 36 38 * 37 39 * The hrtimer structure must be initialized by hrtimer_setup() 38 40 */ ··· 47 45 u8 is_rel; 48 46 u8 is_soft; 49 47 u8 is_hard; 48 + u8 is_lazy; 50 49 }; 51 50 52 51 #endif /* _LINUX_HRTIMER_TYPES_H */
+16 -1
kernel/time/hrtimer.c
··· 1152 1152 * an superfluous call to hrtimer_force_reprogram() on the 1153 1153 * remote cpu later on if the same timer gets enqueued again. 1154 1154 */ 1155 - if (reprogram && timer == cpu_base->next_timer) 1155 + if (reprogram && timer == cpu_base->next_timer && !timer->is_lazy) 1156 1156 hrtimer_force_reprogram(cpu_base, 1); 1157 1157 } 1158 1158 ··· 1319 1319 smp_call_function_single_async(new_cpu_base->cpu, &new_cpu_base->csd); 1320 1320 } 1321 1321 return 0; 1322 + } 1323 + 1324 + /* 1325 + * Special case for the HRTICK timer. It is frequently rearmed and most 1326 + * of the time moves the expiry into the future. That's expensive in 1327 + * virtual machines and it's better to take the pointless already armed 1328 + * interrupt than reprogramming the hardware on every context switch. 1329 + * 1330 + * If the new expiry is before the armed time, then reprogramming is 1331 + * required. 1332 + */ 1333 + if (timer->is_lazy) { 1334 + if (new_base->cpu_base->expires_next <= hrtimer_get_expires(timer)) 1335 + return 0; 1322 1336 } 1323 1337 1324 1338 /* ··· 1689 1675 base += hrtimer_clockid_to_base(clock_id); 1690 1676 timer->is_soft = softtimer; 1691 1677 timer->is_hard = !!(mode & HRTIMER_MODE_HARD); 1678 + timer->is_lazy = !!(mode & HRTIMER_MODE_LAZY_REARM); 1692 1679 timer->base = &cpu_base->clock_base[base]; 1693 1680 timerqueue_init(&timer->node); 1694 1681