Skip to content

Commit 7198e39

Browse files
Frederic WeisbeckerThomas Gleixner
authored andcommitted
sched/cputime: Handle idle irqtime gracefully
The dyntick-idle cputime accounting always assumes that interrupt time accounting is enabled and consequently stops elapsing the idle time during dyntick-idle interrupts. This doesn't mix up well with disabled interrupt time accounting because then idle interrupts become a cputime blind-spot. Also this feature is disabled on most configurations and the overhead of pausing dyntick-idle accounting while in idle interrupts could then be avoided. Fix the situation with conditionally pausing dyntick-idle accounting during idle interrupts only iff either native vtime (which does interrupt time accounting) or generic interrupt time accounting are enabled. Also make sure that the accumulated interrupt time is not accidentally substracted from later accounting. Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Tested-by: Shrikanth Hegde <sshegde@linux.ibm.com> Link: https://patch.msgid.link/20260508131647.43868-15-frederic@kernel.org
1 parent 3b45b4f commit 7198e39

1 file changed

Lines changed: 17 additions & 3 deletions

File tree

kernel/sched/cputime.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ static void irqtime_account_delta(struct irqtime *irqtime, u64 delta,
4747
u64_stats_update_begin(&irqtime->sync);
4848
cpustat[idx] += delta;
4949
irqtime->total += delta;
50-
irqtime->tick_delta += delta;
50+
if (!kcpustat_idle_dyntick())
51+
irqtime->tick_delta += delta;
5152
u64_stats_update_end(&irqtime->sync);
5253
}
5354

@@ -444,6 +445,10 @@ static void kcpustat_idle_stop(struct kernel_cpustat *kc, u64 now)
444445

445446
static void kcpustat_idle_start(struct kernel_cpustat *kc, u64 now)
446447
{
448+
/* Irqtime accounting might have been enabled in the middle of the IRQ */
449+
if (kc->idle_elapse)
450+
return;
451+
447452
write_seqcount_begin(&kc->idle_sleeptime_seq);
448453
kc->idle_entrytime = now;
449454
kc->idle_elapse = true;
@@ -478,15 +483,24 @@ void kcpustat_irq_enter(u64 now)
478483
{
479484
struct kernel_cpustat *kc = kcpustat_this_cpu;
480485

481-
if (!vtime_generic_enabled_this_cpu())
486+
if (!vtime_generic_enabled_this_cpu() &&
487+
(irqtime_enabled() || vtime_accounting_enabled_this_cpu()))
482488
kcpustat_idle_stop(kc, now);
483489
}
484490

485491
void kcpustat_irq_exit(u64 now)
486492
{
487493
struct kernel_cpustat *kc = kcpustat_this_cpu;
488494

489-
if (!vtime_generic_enabled_this_cpu())
495+
/*
496+
* Generic vtime already does its own idle accounting.
497+
* But irqtime accounting or arch vtime which also accounts IRQs
498+
* need to pause nohz accounting. Resume nohz accounting as long
499+
* as the irqtime config is enabled to handle case where irqtime
500+
* accounting got runtime disabled in the middle of an IRQ.
501+
*/
502+
if (!vtime_generic_enabled_this_cpu() &&
503+
(IS_ENABLED(CONFIG_IRQ_TIME_ACCOUNTING) || vtime_accounting_enabled_this_cpu()))
490504
kcpustat_idle_start(kc, now);
491505
}
492506

0 commit comments

Comments
 (0)