mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls
@ 2026-09-18 13:33 Usama Arif
  2026-09-18 13:36 ` Usama Arif
  0 siblings, 1 reply; 5+ messages in thread
From: Usama Arif @ 2026-09-18 13:33 UTC (permalink / raw)
  To: axboe, cgroups, josef, linux-block, linux-kernel, tj
  Cc: hannes, mkoutny, shakeel.butt, riel, Usama Arif

tick_nohz_next_event() limits a CPU's sleep interval to the maximum
deferment supported by the current clocksource when that CPU owns the
do_timer() duty. If the duty is unassigned, the limit also applies when
the CPU's TS_FLAG_DO_TIMER_LAST flag is set.

After the early timer checks, the function currently reads the maximum
deferment unconditionally. It then replaces the result with KTIME_MAX
unless one of the two conditions above applies.

timekeeping_max_deferment() performs a seqcount-protected read of the
shared timekeeper and follows its clocksource pointer. Check the do_timer
state first and avoid this work when the result would be discarded. This
leaves the resulting expiry unchanged and reduces accesses to timekeeper
data that is modified regularly.

On x86-64 this removes 18-20 dynamically executed instructions, including
the call, from the common non-owner path when the seqcount does not retry.

Signed-off-by: Usama Arif <usama.arif@linux.dev>
---
v1 -> v2:
- Remove the unnecessary comment and delta variable (Frederic Weisbecker).
---
 kernel/time/tick-sched.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index c8f2c4a503b08..a7893a079a83f 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -816,7 +816,7 @@ u64 get_jiffies_update(unsigned long *basej)
  */
 static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
 {
-	u64 basemono, next_tick, delta, expires;
+	u64 basemono, next_tick, expires;
 	unsigned long basejiff;
 	int tick_cpu;
 
@@ -856,8 +856,7 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
 	 * If the tick is due in the next period, keep it ticking or
 	 * force prod the timer.
 	 */
-	delta = next_tick - basemono;
-	if (delta <= (u64)TICK_NSEC) {
+	if (next_tick - basemono <= (u64)TICK_NSEC) {
 		/*
 		 * We've not stopped the tick yet, and there's a timer in the
 		 * next period, so no point in stopping it either, bail.
@@ -873,17 +872,19 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
 	 * the sleep time to the timekeeping 'max_deferment' value.
 	 * Otherwise we can sleep as long as we want.
 	 */
-	delta = timekeeping_max_deferment();
 	tick_cpu = READ_ONCE(tick_do_timer_cpu);
 	if (tick_cpu != cpu &&
-	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
-		delta = KTIME_MAX;
-
-	/* Calculate the next expiry time */
-	if (delta < (KTIME_MAX - basemono))
-		expires = basemono + delta;
-	else
+	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST))) {
 		expires = KTIME_MAX;
+	} else {
+		expires = timekeeping_max_deferment();
+
+		/* Calculate the next expiry time */
+		if (expires < (KTIME_MAX - basemono))
+			expires += basemono;
+		else
+			expires = KTIME_MAX;
+	}
 
 	ts->timer_expires = min_t(u64, expires, next_tick);
 
-- 
2.53.0-Meta


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls
  2026-09-18 13:33 [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls Usama Arif
@ 2026-09-18 13:36 ` Usama Arif
  0 siblings, 0 replies; 5+ messages in thread
From: Usama Arif @ 2026-09-18 13:36 UTC (permalink / raw)
  To: axboe, cgroups, josef, linux-block, linux-kernel, tj
  Cc: hannes, mkoutny, shakeel.butt, riel



On 18/09/2026 14:33, Usama Arif wrote:
> tick_nohz_next_event() limits a CPU's sleep interval to the maximum
> deferment supported by the current clocksource when that CPU owns the
> do_timer() duty. If the duty is unassigned, the limit also applies when
> the CPU's TS_FLAG_DO_TIMER_LAST flag is set.
> 
> After the early timer checks, the function currently reads the maximum
> deferment unconditionally. It then replaces the result with KTIME_MAX
> unless one of the two conditions above applies.
> 
> timekeeping_max_deferment() performs a seqcount-protected read of the
> shared timekeeper and follows its clocksource pointer. Check the do_timer
> state first and avoid this work when the result would be discarded. This
> leaves the resulting expiry unchanged and reduces accesses to timekeeper
> data that is modified regularly.
> 
> On x86-64 this removes 18-20 dynamically executed instructions, including
> the call, from the common non-owner path when the seqcount does not retry.
> 
> Signed-off-by: Usama Arif <usama.arif@linux.dev>
> ---
> v1 -> v2:
> - Remove the unnecessary comment and delta variable (Frederic Weisbecker).
> ---
>  kernel/time/tick-sched.c | 23 ++++++++++++-----------
>  1 file changed, 12 insertions(+), 11 deletions(-)
> 
Sorry about the noise, please ignore, copied the wrong list of people to send to.
The correct list is [1]

[1] https://lore.kernel.org/all/20260918133408.2834751-1-usama.arif@linux.dev/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls
  2026-09-18 12:08 ` Frederic Weisbecker
@ 2026-09-18 13:37   ` Usama Arif
  0 siblings, 0 replies; 5+ messages in thread
From: Usama Arif @ 2026-09-18 13:37 UTC (permalink / raw)
  To: Frederic Weisbecker
  Cc: anna-maria, linux-kernel, mingo, tglx, hannes, shakeel.butt, riel



On 18/09/2026 13:08, Frederic Weisbecker wrote:
> Le Thu, Sep 17, 2026 at 09:39:29AM -0700, Usama Arif a écrit :
>> tick_nohz_next_event() limits a CPU's sleep interval to the maximum
>> deferment supported by the current clocksource when that CPU owns the
>> do_timer() duty. If the duty is unassigned, the limit also applies when
>> the CPU's TS_FLAG_DO_TIMER_LAST flag is set.
>>
>> After the early timer checks, the function currently reads the maximum
>> deferment unconditionally. It then replaces the result with KTIME_MAX
>> unless one of the two conditions above applies.
>>
>> timekeeping_max_deferment() performs a seqcount-protected read of the
>> shared timekeeper and follows its clocksource pointer. Check the do_timer
>> state first and avoid this work when the result would be discarded. This
>> leaves the resulting expiry unchanged and reduces accesses to timekeeper
>> data that is modified regularly.
>>
>> On x86-64 this removes 18-20 dynamically executed instructions, including
>> the call, from the common non-owner path when the seqcount does not retry.
>>
>> Signed-off-by: Usama Arif <usama.arif@linux.dev>
>> ---
>>  kernel/time/tick-sched.c | 23 +++++++++++++++--------
>>  1 file changed, 15 insertions(+), 8 deletions(-)
>>
>> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
>> index c8f2c4a503b08..e7c7c28311156 100644
>> --- a/kernel/time/tick-sched.c
>> +++ b/kernel/time/tick-sched.c
>> @@ -872,18 +872,25 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
>>  	 * If this CPU is the one which had the do_timer() duty last, we limit
>>  	 * the sleep time to the timekeeping 'max_deferment' value.
>>  	 * Otherwise we can sleep as long as we want.
>> +	 *
>> +	 * Only read the max deferment in the former case: it is a seqcount
>> +	 * read of the globally shared timekeeper, and on a large machine
>> +	 * almost every caller is not the do_timer() CPU and would throw the
>> +	 * value away.
> 
> I don't think that needs a comment.
> 
>>  	 */
>> -	delta = timekeeping_max_deferment();
>>  	tick_cpu = READ_ONCE(tick_do_timer_cpu);
>>  	if (tick_cpu != cpu &&
>> -	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
>> -		delta = KTIME_MAX;
>> -
>> -	/* Calculate the next expiry time */
>> -	if (delta < (KTIME_MAX - basemono))
>> -		expires = basemono + delta;
>> -	else
>> +	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST))) {
>>  		expires = KTIME_MAX;
>> +	} else {
>> +		delta = timekeeping_max_deferment();
>> +
>> +		/* Calculate the next expiry time */
>> +		if (delta < (KTIME_MAX - basemono))
>> +			expires = basemono + delta;
>> +		else
>> +			expires = KTIME_MAX;
>> +	}
> 
> If anything, it also makes the code more readable. You can even remove the delta
> variable because even in its former use in the function, it's an unecessary
> middle step.
> 
> Thanks.


Thanks for the review! I have sent a v2 to address above in [1].

[1] https://lore.kernel.org/all/20260918133408.2834751-1-usama.arif@linux.dev/

> 
>>  
>>  	ts->timer_expires = min_t(u64, expires, next_tick);
>>  
>> -- 
>> 2.53.0-Meta
>>
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls
  2026-09-17 16:39 Usama Arif
@ 2026-09-18 12:08 ` Frederic Weisbecker
  2026-09-18 13:37   ` Usama Arif
  0 siblings, 1 reply; 5+ messages in thread
From: Frederic Weisbecker @ 2026-09-18 12:08 UTC (permalink / raw)
  To: Usama Arif
  Cc: anna-maria, linux-kernel, mingo, tglx, hannes, shakeel.butt, riel

Le Thu, Sep 17, 2026 at 09:39:29AM -0700, Usama Arif a écrit :
> tick_nohz_next_event() limits a CPU's sleep interval to the maximum
> deferment supported by the current clocksource when that CPU owns the
> do_timer() duty. If the duty is unassigned, the limit also applies when
> the CPU's TS_FLAG_DO_TIMER_LAST flag is set.
> 
> After the early timer checks, the function currently reads the maximum
> deferment unconditionally. It then replaces the result with KTIME_MAX
> unless one of the two conditions above applies.
> 
> timekeeping_max_deferment() performs a seqcount-protected read of the
> shared timekeeper and follows its clocksource pointer. Check the do_timer
> state first and avoid this work when the result would be discarded. This
> leaves the resulting expiry unchanged and reduces accesses to timekeeper
> data that is modified regularly.
> 
> On x86-64 this removes 18-20 dynamically executed instructions, including
> the call, from the common non-owner path when the seqcount does not retry.
> 
> Signed-off-by: Usama Arif <usama.arif@linux.dev>
> ---
>  kernel/time/tick-sched.c | 23 +++++++++++++++--------
>  1 file changed, 15 insertions(+), 8 deletions(-)
> 
> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
> index c8f2c4a503b08..e7c7c28311156 100644
> --- a/kernel/time/tick-sched.c
> +++ b/kernel/time/tick-sched.c
> @@ -872,18 +872,25 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
>  	 * If this CPU is the one which had the do_timer() duty last, we limit
>  	 * the sleep time to the timekeeping 'max_deferment' value.
>  	 * Otherwise we can sleep as long as we want.
> +	 *
> +	 * Only read the max deferment in the former case: it is a seqcount
> +	 * read of the globally shared timekeeper, and on a large machine
> +	 * almost every caller is not the do_timer() CPU and would throw the
> +	 * value away.

I don't think that needs a comment.

>  	 */
> -	delta = timekeeping_max_deferment();
>  	tick_cpu = READ_ONCE(tick_do_timer_cpu);
>  	if (tick_cpu != cpu &&
> -	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
> -		delta = KTIME_MAX;
> -
> -	/* Calculate the next expiry time */
> -	if (delta < (KTIME_MAX - basemono))
> -		expires = basemono + delta;
> -	else
> +	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST))) {
>  		expires = KTIME_MAX;
> +	} else {
> +		delta = timekeeping_max_deferment();
> +
> +		/* Calculate the next expiry time */
> +		if (delta < (KTIME_MAX - basemono))
> +			expires = basemono + delta;
> +		else
> +			expires = KTIME_MAX;
> +	}

If anything, it also makes the code more readable. You can even remove the delta
variable because even in its former use in the function, it's an unecessary
middle step.

Thanks.

>  
>  	ts->timer_expires = min_t(u64, expires, next_tick);
>  
> -- 
> 2.53.0-Meta
> 

-- 
Frederic Weisbecker
SUSE Labs

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls
@ 2026-09-17 16:39 Usama Arif
  2026-09-18 12:08 ` Frederic Weisbecker
  0 siblings, 1 reply; 5+ messages in thread
From: Usama Arif @ 2026-09-17 16:39 UTC (permalink / raw)
  To: anna-maria, frederic, linux-kernel, mingo, tglx
  Cc: hannes, shakeel.butt, riel, Usama Arif

tick_nohz_next_event() limits a CPU's sleep interval to the maximum
deferment supported by the current clocksource when that CPU owns the
do_timer() duty. If the duty is unassigned, the limit also applies when
the CPU's TS_FLAG_DO_TIMER_LAST flag is set.

After the early timer checks, the function currently reads the maximum
deferment unconditionally. It then replaces the result with KTIME_MAX
unless one of the two conditions above applies.

timekeeping_max_deferment() performs a seqcount-protected read of the
shared timekeeper and follows its clocksource pointer. Check the do_timer
state first and avoid this work when the result would be discarded. This
leaves the resulting expiry unchanged and reduces accesses to timekeeper
data that is modified regularly.

On x86-64 this removes 18-20 dynamically executed instructions, including
the call, from the common non-owner path when the seqcount does not retry.

Signed-off-by: Usama Arif <usama.arif@linux.dev>
---
 kernel/time/tick-sched.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index c8f2c4a503b08..e7c7c28311156 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -872,18 +872,25 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
 	 * If this CPU is the one which had the do_timer() duty last, we limit
 	 * the sleep time to the timekeeping 'max_deferment' value.
 	 * Otherwise we can sleep as long as we want.
+	 *
+	 * Only read the max deferment in the former case: it is a seqcount
+	 * read of the globally shared timekeeper, and on a large machine
+	 * almost every caller is not the do_timer() CPU and would throw the
+	 * value away.
 	 */
-	delta = timekeeping_max_deferment();
 	tick_cpu = READ_ONCE(tick_do_timer_cpu);
 	if (tick_cpu != cpu &&
-	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
-		delta = KTIME_MAX;
-
-	/* Calculate the next expiry time */
-	if (delta < (KTIME_MAX - basemono))
-		expires = basemono + delta;
-	else
+	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST))) {
 		expires = KTIME_MAX;
+	} else {
+		delta = timekeeping_max_deferment();
+
+		/* Calculate the next expiry time */
+		if (delta < (KTIME_MAX - basemono))
+			expires = basemono + delta;
+		else
+			expires = KTIME_MAX;
+	}
 
 	ts->timer_expires = min_t(u64, expires, next_tick);
 
-- 
2.53.0-Meta


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-18 13:37 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 13:33 [PATCH] tick/nohz: Avoid unused timekeeping_max_deferment() calls Usama Arif
2026-09-18 13:36 ` Usama Arif
  -- strict thread matches above, loose matches on Subject: below --
2026-09-17 16:39 Usama Arif
2026-09-18 12:08 ` Frederic Weisbecker
2026-09-18 13:37   ` Usama Arif

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®