]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
sched/clock: Avoid false sharing for sched_clock_irqtime
authorWangyang Guo <wangyang.guo@intel.com>
Tue, 27 Jan 2026 07:25:09 +0000 (15:25 +0800)
committerPeter Zijlstra <peterz@infradead.org>
Tue, 3 Feb 2026 11:04:19 +0000 (12:04 +0100)
Read-mostly sched_clock_irqtime may share the same cacheline with
frequently updated nohz struct. Make it as static_key to avoid
false sharing issue.

The only user of disable_sched_clock_irqtime()
is tsc_.*mark_unstable() which may be invoked under atomic context
and require a workqueue to disable static_key. But both of them
calls clear_sched_clock_stable() just before doing
disable_sched_clock_irqtime(). We can reuse
"sched_clock_work" to also disable sched_clock_irqtime().

One additional case need to handle is if the tsc is marked unstable
before late_initcall() phase, sched_clock_work will not be invoked
and sched_clock_irqtime will stay enabled although clock is unstable:
  tsc_init()
    enable_sched_clock_irqtime() # irqtime accounting is enabled here
    ...
    if (unsynchronized_tsc()) # true
      mark_tsc_unstable()
        clear_sched_clock_stable()
          __sched_clock_stable_early = 0;
          ...
          if (static_key_count(&sched_clock_running.key) == 2)
            # Only happens at sched_clock_init_late()
            __clear_sched_clock_stable(); # Never executed
  ...

  # late_initcall() phase
  sched_clock_init_late()
    if (__sched_clock_stable_early) # Already false
      __set_sched_clock_stable(); # sched_clock is never marked stable
  # TSC unstable, but sched_clock_work won't run to disable irqtime

So we need to disable_sched_clock_irqtime() in sched_clock_init_late()
if clock is unstable.

Reported-by: Benjamin Lei <benjamin.lei@intel.com>
Suggested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Suggested-by: Shrikanth Hegde <sshegde@linux.ibm.com>
Signed-off-by: Wangyang Guo <wangyang.guo@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com>
Reviewed-by: Tim Chen <tim.c.chen@linux.intel.com>
Reviewed-by: Tianyou Li <tianyou.li@intel.com>
Reviewed-by: Shrikanth Hegde <sshegde@linux.ibm.com>
Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Link: https://patch.msgid.link/20260127072509.2627346-1-wangyang.guo@intel.com
arch/x86/kernel/tsc.c
kernel/sched/clock.c
kernel/sched/cputime.c
kernel/sched/sched.h

index 7d3e13e14eabe602acf57c30f1c5eab01c89ec75..7be44b5198cf2c59f99706743409bece9fd272b0 100644 (file)
@@ -1143,7 +1143,6 @@ static void tsc_cs_mark_unstable(struct clocksource *cs)
        tsc_unstable = 1;
        if (using_native_sched_clock())
                clear_sched_clock_stable();
-       disable_sched_clock_irqtime();
        pr_info("Marking TSC unstable due to clocksource watchdog\n");
 }
 
@@ -1213,7 +1212,6 @@ void mark_tsc_unstable(char *reason)
        tsc_unstable = 1;
        if (using_native_sched_clock())
                clear_sched_clock_stable();
-       disable_sched_clock_irqtime();
        pr_info("Marking TSC unstable due to %s\n", reason);
 
        clocksource_mark_unstable(&clocksource_tsc_early);
index f5e6dd6a6b3af529d227ff61cf3d479925db34b9..2ae4fbf13431fc83334832cf5666f951c760af95 100644 (file)
@@ -173,6 +173,7 @@ notrace static void __sched_clock_work(struct work_struct *work)
                        scd->tick_gtod, __gtod_offset,
                        scd->tick_raw,  __sched_clock_offset);
 
+       disable_sched_clock_irqtime();
        static_branch_disable(&__sched_clock_stable);
 }
 
@@ -238,6 +239,8 @@ static int __init sched_clock_init_late(void)
 
        if (__sched_clock_stable_early)
                __set_sched_clock_stable();
+       else
+               disable_sched_clock_irqtime();  /* disable if clock unstable. */
 
        return 0;
 }
index 4f97896887ecbb9fcd3d26e06f5c775d20e3c996..ff0dfca9542079cec7622c168e17d3c9fd9ac4a0 100644 (file)
@@ -12,6 +12,8 @@
 
 #ifdef CONFIG_IRQ_TIME_ACCOUNTING
 
+DEFINE_STATIC_KEY_FALSE(sched_clock_irqtime);
+
 /*
  * There are no locks covering percpu hardirq/softirq time.
  * They are only modified in vtime_account, on corresponding CPU
  */
 DEFINE_PER_CPU(struct irqtime, cpu_irqtime);
 
-int sched_clock_irqtime;
-
 void enable_sched_clock_irqtime(void)
 {
-       sched_clock_irqtime = 1;
+       static_branch_enable(&sched_clock_irqtime);
 }
 
 void disable_sched_clock_irqtime(void)
 {
-       sched_clock_irqtime = 0;
+       if (irqtime_enabled())
+               static_branch_disable(&sched_clock_irqtime);
 }
 
 static void irqtime_account_delta(struct irqtime *irqtime, u64 delta,
index 2aa4251c1520ab506f488fe5983d21202a1fa7bb..a821cc8b2dd8f6aeb7d253aef3a36a702254fb81 100644 (file)
@@ -3333,11 +3333,11 @@ struct irqtime {
 };
 
 DECLARE_PER_CPU(struct irqtime, cpu_irqtime);
-extern int sched_clock_irqtime;
+DECLARE_STATIC_KEY_FALSE(sched_clock_irqtime);
 
 static inline int irqtime_enabled(void)
 {
-       return sched_clock_irqtime;
+       return static_branch_likely(&sched_clock_irqtime);
 }
 
 /*