Skip to content

Commit 6a1f6a9

Browse files
Frederic WeisbeckerThomas Gleixner
authored andcommitted
tick/sched: Account tickless idle cputime only when tick is stopped
There is no real point in switching to dyntick-idle cputime accounting mode if the tick is not actually stopped. This just adds overhead, notably fetching the GTOD, on each idle exit and each idle IRQ entry for no reason during short idle trips. 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-12-frederic@kernel.org
1 parent 29807c5 commit 6a1f6a9

1 file changed

Lines changed: 26 additions & 24 deletions

File tree

kernel/time/tick-sched.c

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,8 +1157,10 @@ void tick_nohz_idle_stop_tick(void)
11571157
ts->idle_sleeps++;
11581158
ts->idle_expires = expires;
11591159

1160-
if (!was_stopped && tick_sched_flag_test(ts, TS_FLAG_STOPPED))
1160+
if (!was_stopped && tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
1161+
kcpustat_dyntick_start(ts->idle_entrytime);
11611162
nohz_balance_enter_idle(cpu);
1163+
}
11621164
} else {
11631165
tick_nohz_retain_tick(ts);
11641166
}
@@ -1200,7 +1202,6 @@ void tick_nohz_idle_enter(void)
12001202
WARN_ON_ONCE(ts->timer_expires_base);
12011203
tick_sched_flag_set(ts, TS_FLAG_INIDLE);
12021204
ts->idle_entrytime = ktime_get();
1203-
kcpustat_dyntick_start(ts->idle_entrytime);
12041205
tick_nohz_clock_sleep(ts);
12051206

12061207
local_irq_enable();
@@ -1230,9 +1231,10 @@ void tick_nohz_irq_exit(void)
12301231
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
12311232

12321233
if (tick_sched_flag_test(ts, TS_FLAG_INIDLE)) {
1233-
ts->idle_entrytime = ktime_get();
1234-
kcpustat_irq_exit(ts->idle_entrytime);
12351234
tick_nohz_clock_sleep(ts);
1235+
ts->idle_entrytime = ktime_get();
1236+
if (tick_sched_flag_test(ts, TS_FLAG_STOPPED))
1237+
kcpustat_irq_exit(ts->idle_entrytime);
12361238
} else {
12371239
tick_nohz_full_update_tick(ts);
12381240
}
@@ -1333,8 +1335,17 @@ void tick_nohz_idle_restart_tick(void)
13331335
{
13341336
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
13351337

1336-
if (tick_sched_flag_test(ts, TS_FLAG_STOPPED))
1337-
tick_nohz_restart_sched_tick(ts, ktime_get());
1338+
if (tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
1339+
/*
1340+
* Update entrytime here in case the tick restart is due to temporary
1341+
* polling on forced broadcast. The tick may be stopped again later within
1342+
* the same idle trip. The idle_entrytime was updated recently but make sure
1343+
* no tiny amount of idle time is accounted twice.
1344+
*/
1345+
ts->idle_entrytime = ktime_get();
1346+
kcpustat_dyntick_stop(ts->idle_entrytime);
1347+
tick_nohz_restart_sched_tick(ts, ts->idle_entrytime);
1348+
}
13381349
}
13391350

13401351
static void tick_nohz_idle_update_tick(struct tick_sched *ts, ktime_t now)
@@ -1364,7 +1375,6 @@ static void tick_nohz_idle_update_tick(struct tick_sched *ts, ktime_t now)
13641375
void tick_nohz_idle_exit(void)
13651376
{
13661377
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
1367-
bool idle_active, tick_stopped;
13681378
ktime_t now;
13691379

13701380
local_irq_disable();
@@ -1373,18 +1383,13 @@ void tick_nohz_idle_exit(void)
13731383
WARN_ON_ONCE(ts->timer_expires_base);
13741384

13751385
tick_sched_flag_clear(ts, TS_FLAG_INIDLE);
1376-
idle_active = tick_sched_flag_test(ts, TS_FLAG_IDLE_ACTIVE);
1377-
tick_stopped = tick_sched_flag_test(ts, TS_FLAG_STOPPED);
1386+
tick_nohz_clock_wakeup(ts);
13781387

1379-
if (idle_active || tick_stopped)
1388+
if (tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
13801389
now = ktime_get();
1381-
1382-
if (idle_active)
1383-
tick_nohz_clock_wakeup(ts);
1384-
1385-
if (tick_stopped)
1390+
kcpustat_dyntick_stop(now);
13861391
tick_nohz_idle_update_tick(ts, now);
1387-
kcpustat_dyntick_stop(now);
1392+
}
13881393

13891394
local_irq_enable();
13901395
}
@@ -1439,15 +1444,13 @@ static inline void tick_nohz_irq_enter(void)
14391444
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
14401445
ktime_t now;
14411446

1442-
if (!tick_sched_flag_test(ts, TS_FLAG_STOPPED | TS_FLAG_IDLE_ACTIVE))
1447+
tick_nohz_clock_wakeup(ts);
1448+
1449+
if (!tick_sched_flag_test(ts, TS_FLAG_STOPPED))
14431450
return;
14441451

14451452
now = ktime_get();
1446-
1447-
if (tick_sched_flag_test(ts, TS_FLAG_IDLE_ACTIVE)) {
1448-
tick_nohz_clock_wakeup(ts);
1449-
kcpustat_irq_enter(now);
1450-
}
1453+
kcpustat_irq_enter(now);
14511454

14521455
/*
14531456
* If all CPUs are idle we may need to update a stale jiffies value.
@@ -1456,8 +1459,7 @@ static inline void tick_nohz_irq_enter(void)
14561459
* rare case (typically stop machine). So we must make sure we have a
14571460
* last resort.
14581461
*/
1459-
if (tick_sched_flag_test(ts, TS_FLAG_STOPPED))
1460-
tick_nohz_update_jiffies(now);
1462+
tick_nohz_update_jiffies(now);
14611463
}
14621464

14631465
#else

0 commit comments

Comments
 (0)