Messages in this thread Patch in this message | | | From | Anna-Maria Behnsen <> | Subject | [PATCH v8 17/25] timer: Retrieve next expiry of pinned/non-pinned timers separately | Date | Wed, 4 Oct 2023 14:34:46 +0200 |
| |
For the conversion of the NOHZ timer placement to a pull at expiry time model it's required to have separate expiry times for the pinned and the non-pinned (movable) timers. Therefore struct timer_events is introduced.
No functional change
Originally-by: Richard Cochran (linutronix GmbH) <richardcochran@gmail.com> Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> --- kernel/time/timer.c | 48 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 1cd214c2f3f1..4230fc6fa1ed 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -221,6 +221,11 @@ struct timer_base { static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]); +struct timer_events { + u64 local; + u64 global; +}; + #ifdef CONFIG_NO_HZ_COMMON static DEFINE_STATIC_KEY_FALSE(timers_nohz_active); @@ -1971,9 +1976,10 @@ static unsigned long next_timer_interrupt(struct timer_base *base) return base->next_expiry; } -static inline unsigned long __get_next_timer_interrupt(unsigned long basej, +static inline unsigned long __get_next_timer_interrupt(unsigned long basej, u64 basem, struct timer_base *base_local, - struct timer_base *base_global) + struct timer_base *base_global, + struct timer_events *tevt) { unsigned long nextevt, nextevt_local, nextevt_global; bool local_first; @@ -1996,12 +2002,32 @@ static inline unsigned long __get_next_timer_interrupt(unsigned long basej, nextevt = local_first ? nextevt_local : nextevt_global; - if (base_local->timers_pending || base_global->timers_pending) { + /* + * If the @nextevt is at max. one tick away, use @nextevt and store + * it in the local expiry value. The next global event is irrelevant in + * this case and can be left as KTIME_MAX. + */ + if (time_before_eq(nextevt, basej + 1)) { /* If we missed a tick already, force 0 delta */ if (time_before(nextevt, basej)) nextevt = basej; + tevt->local = basem + (u64)(nextevt - basej) * TICK_NSEC; + return tevt->local; } + /* + * Update tevt->* values: + * + * If the local queue expires first, then the global event can + * be ignored. If the global queue is empty, nothing to do + * either. + */ + if (!local_first && base_global->timers_pending) + tevt->global = basem + (u64)(nextevt_global - basej) * TICK_NSEC; + + if (base_local->timers_pending) + tevt->local = basem + (u64)(nextevt_local - basej) * TICK_NSEC; + return nextevt; } @@ -2015,16 +2041,15 @@ static inline unsigned long __get_next_timer_interrupt(unsigned long basej, */ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) { + struct timer_events tevt = { .local = KTIME_MAX, .global = KTIME_MAX }; struct timer_base *base_local, *base_global; - u64 expires = KTIME_MAX; - unsigned long nextevt; /* * Pretend that there is no timer pending if the cpu is offline. * Possible pending timers will be migrated later to an active cpu. */ if (cpu_is_offline(smp_processor_id())) - return expires; + return KTIME_MAX; base_local = this_cpu_ptr(&timer_bases[BASE_LOCAL]); base_global = this_cpu_ptr(&timer_bases[BASE_GLOBAL]); @@ -2032,14 +2057,14 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) raw_spin_lock(&base_local->lock); raw_spin_lock_nested(&base_global->lock, SINGLE_DEPTH_NESTING); - nextevt = __get_next_timer_interrupt(basej, base_local, base_global); + __get_next_timer_interrupt(basej, basem, base_local, base_global, &tevt); raw_spin_unlock(&base_global->lock); raw_spin_unlock(&base_local->lock); - expires = basem + (u64)(nextevt - basej) * TICK_NSEC; + tevt.local = min_t(u64, tevt.local, tevt.global); - return cmp_next_hrtimer_event(basem, expires); + return cmp_next_hrtimer_event(basem, tevt.local); } /** @@ -2055,6 +2080,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) */ u64 timer_set_idle(unsigned long basej, u64 basem, bool *idle) { + struct timer_events tevt = { .local = KTIME_MAX, .global = KTIME_MAX }; struct timer_base *base_local, *base_global; unsigned long nextevt; @@ -2073,7 +2099,7 @@ u64 timer_set_idle(unsigned long basej, u64 basem, bool *idle) raw_spin_lock(&base_local->lock); raw_spin_lock_nested(&base_global->lock, SINGLE_DEPTH_NESTING); - nextevt = __get_next_timer_interrupt(basej, base_local, base_global); + nextevt = __get_next_timer_interrupt(basej, basem, base_local, base_global, &tevt); /* * We have a fresh next event. Check whether we can forward the @@ -2097,7 +2123,7 @@ u64 timer_set_idle(unsigned long basej, u64 basem, bool *idle) raw_spin_unlock(&base_global->lock); raw_spin_unlock(&base_local->lock); - return basem + (u64)(nextevt - basej) * TICK_NSEC; + return min_t(u64, tevt.local, tevt.global); } /** -- 2.39.2
| |