Skip to content

Commit 127b2eb

Browse files
Frederic WeisbeckerThomas Gleixner
authored andcommitted
tick/sched: Consolidate idle time fetching APIs
Fetching the idle cputime is available through a variety of accessors all over the place depending on the different accounting flavours and needs: - idle vtime generic accounting can be accessed by kcpustat_field(), kcpustat_cpu_fetch(), get_idle/iowait_time() and get_cpu_idle/iowait_time_us() - dynticks-idle accounting can only be accessed by get_idle/iowait_time() or get_cpu_idle/iowait_time_us() - CONFIG_NO_HZ_COMMON=n idle accounting can be accessed by kcpustat_field() kcpustat_cpu_fetch(), or get_idle/iowait_time() but not by get_cpu_idle/iowait_time_us() Moreover get_idle/iowait_time() relies on get_cpu_idle/iowait_time_us() with a non-sensical conversion to microseconds and back to nanoseconds on the way. Start consolidating the APIs with removing get_idle/iowait_time() and make kcpustat_field() and kcpustat_cpu_fetch() work for all cases. 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-13-frederic@kernel.org
1 parent 6a1f6a9 commit 127b2eb

4 files changed

Lines changed: 76 additions & 67 deletions

File tree

fs/proc/stat.c

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,6 @@
2222
#define arch_irq_stat() 0
2323
#endif
2424

25-
u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
26-
{
27-
u64 idle, idle_usecs = -1ULL;
28-
29-
if (cpu_online(cpu))
30-
idle_usecs = get_cpu_idle_time_us(cpu, NULL);
31-
32-
if (idle_usecs == -1ULL)
33-
/* !NO_HZ or cpu offline so we can rely on cpustat.idle */
34-
idle = kcs->cpustat[CPUTIME_IDLE];
35-
else
36-
idle = idle_usecs * NSEC_PER_USEC;
37-
38-
return idle;
39-
}
40-
41-
static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
42-
{
43-
u64 iowait, iowait_usecs = -1ULL;
44-
45-
if (cpu_online(cpu))
46-
iowait_usecs = get_cpu_iowait_time_us(cpu, NULL);
47-
48-
if (iowait_usecs == -1ULL)
49-
/* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
50-
iowait = kcs->cpustat[CPUTIME_IOWAIT];
51-
else
52-
iowait = iowait_usecs * NSEC_PER_USEC;
53-
54-
return iowait;
55-
}
56-
5725
static void show_irq_gap(struct seq_file *p, unsigned int gap)
5826
{
5927
static const char zeros[] = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0";
@@ -105,8 +73,8 @@ static int show_stat(struct seq_file *p, void *v)
10573
user += cpustat[CPUTIME_USER];
10674
nice += cpustat[CPUTIME_NICE];
10775
system += cpustat[CPUTIME_SYSTEM];
108-
idle += get_idle_time(&kcpustat, i);
109-
iowait += get_iowait_time(&kcpustat, i);
76+
idle += cpustat[CPUTIME_IDLE];
77+
iowait += cpustat[CPUTIME_IOWAIT];
11078
irq += cpustat[CPUTIME_IRQ];
11179
softirq += cpustat[CPUTIME_SOFTIRQ];
11280
steal += cpustat[CPUTIME_STEAL];
@@ -146,8 +114,8 @@ static int show_stat(struct seq_file *p, void *v)
146114
user = cpustat[CPUTIME_USER];
147115
nice = cpustat[CPUTIME_NICE];
148116
system = cpustat[CPUTIME_SYSTEM];
149-
idle = get_idle_time(&kcpustat, i);
150-
iowait = get_iowait_time(&kcpustat, i);
117+
idle = cpustat[CPUTIME_IDLE];
118+
iowait = cpustat[CPUTIME_IOWAIT];
151119
irq = cpustat[CPUTIME_IRQ];
152120
softirq = cpustat[CPUTIME_SOFTIRQ];
153121
steal = cpustat[CPUTIME_STEAL];

fs/proc/uptime.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,8 @@ static int uptime_proc_show(struct seq_file *m, void *v)
1818
int i;
1919

2020
idle_nsec = 0;
21-
for_each_possible_cpu(i) {
22-
struct kernel_cpustat kcs;
23-
24-
kcpustat_cpu_fetch(&kcs, i);
25-
idle_nsec += get_idle_time(&kcs, i);
26-
}
21+
for_each_possible_cpu(i)
22+
idle_nsec += kcpustat_field(CPUTIME_IDLE, i);
2723

2824
ktime_get_boottime_ts64(&uptime);
2925
timens_add_boottime(&uptime);

include/linux/kernel_stat.h

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,32 +110,59 @@ extern void kcpustat_dyntick_start(u64 now);
110110
extern void kcpustat_dyntick_stop(u64 now);
111111
extern void kcpustat_irq_enter(u64 now);
112112
extern void kcpustat_irq_exit(u64 now);
113+
extern u64 kcpustat_field_idle(int cpu);
114+
extern u64 kcpustat_field_iowait(int cpu);
113115

114116
static inline bool kcpustat_idle_dyntick(void)
115117
{
116118
return __this_cpu_read(kernel_cpustat.idle_dyntick);
117119
}
118120
#else
121+
static inline u64 kcpustat_field_idle(int cpu)
122+
{
123+
return kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
124+
}
125+
static inline u64 kcpustat_field_iowait(int cpu)
126+
{
127+
return kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
128+
}
129+
119130
static inline bool kcpustat_idle_dyntick(void)
120131
{
121132
return false;
122133
}
123134
#endif /* CONFIG_NO_HZ_COMMON */
124135

136+
/* Fetch cputime values when vtime is disabled on a CPU */
137+
static inline u64 kcpustat_field_default(enum cpu_usage_stat usage, int cpu)
138+
{
139+
if (usage == CPUTIME_IDLE)
140+
return kcpustat_field_idle(cpu);
141+
if (usage == CPUTIME_IOWAIT)
142+
return kcpustat_field_iowait(cpu);
143+
return kcpustat_cpu(cpu).cpustat[usage];
144+
}
145+
146+
static inline void kcpustat_cpu_fetch_default(struct kernel_cpustat *dst, int cpu)
147+
{
148+
*dst = kcpustat_cpu(cpu);
149+
dst->cpustat[CPUTIME_IDLE] = kcpustat_field_idle(cpu);
150+
dst->cpustat[CPUTIME_IOWAIT] = kcpustat_field_iowait(cpu);
151+
}
152+
125153
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
126154
extern u64 kcpustat_field(enum cpu_usage_stat usage, int cpu);
127155
extern void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu);
128156
#else
129157
static inline u64 kcpustat_field(enum cpu_usage_stat usage, int cpu)
130158
{
131-
return kcpustat_cpu(cpu).cpustat[usage];
159+
return kcpustat_field_default(usage, cpu);
132160
}
133161

134162
static inline void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
135163
{
136-
*dst = kcpustat_cpu(cpu);
164+
kcpustat_cpu_fetch_default(dst, cpu);
137165
}
138-
139166
#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_GEN */
140167

141168
extern void account_user_time(struct task_struct *, u64);
@@ -145,7 +172,6 @@ extern void account_system_index_time(struct task_struct *, u64,
145172
enum cpu_usage_stat);
146173
extern void account_steal_time(u64);
147174
extern void account_idle_time(u64);
148-
extern u64 get_idle_time(struct kernel_cpustat *kcs, int cpu);
149175

150176
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
151177
static inline void account_process_tick(struct task_struct *tsk, int user)

kernel/sched/cputime.c

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -490,24 +490,14 @@ void kcpustat_irq_exit(u64 now)
490490
kcpustat_idle_start(kc, now);
491491
}
492492

493-
static u64 get_cpu_sleep_time_us(int cpu, enum cpu_usage_stat idx,
494-
bool compute_delta, u64 *last_update_time)
493+
static u64 kcpustat_field_dyntick(int cpu, enum cpu_usage_stat idx,
494+
bool compute_delta, u64 now)
495495
{
496496
struct kernel_cpustat *kc = &kcpustat_cpu(cpu);
497497
u64 *cpustat = kc->cpustat;
498498
unsigned int seq;
499-
ktime_t now;
500499
u64 idle;
501500

502-
now = ktime_get();
503-
if (last_update_time)
504-
*last_update_time = ktime_to_us(now);
505-
506-
if (vtime_generic_enabled_cpu(cpu)) {
507-
idle = kcpustat_field(idx, cpu);
508-
goto to_us;
509-
}
510-
511501
do {
512502
seq = read_seqcount_begin(&kc->idle_sleeptime_seq);
513503

@@ -516,12 +506,42 @@ static u64 get_cpu_sleep_time_us(int cpu, enum cpu_usage_stat idx,
516506
idle += (now - kc->idle_entrytime);
517507
} while (read_seqcount_retry(&kc->idle_sleeptime_seq, seq));
518508

519-
to_us:
520-
do_div(idle, NSEC_PER_USEC);
521-
522509
return idle;
523510
}
524511

512+
u64 kcpustat_field_idle(int cpu)
513+
{
514+
return kcpustat_field_dyntick(cpu, CPUTIME_IDLE,
515+
!nr_iowait_cpu(cpu), ktime_get());
516+
}
517+
EXPORT_SYMBOL_GPL(kcpustat_field_idle);
518+
519+
u64 kcpustat_field_iowait(int cpu)
520+
{
521+
return kcpustat_field_dyntick(cpu, CPUTIME_IOWAIT,
522+
nr_iowait_cpu(cpu), ktime_get());
523+
}
524+
EXPORT_SYMBOL_GPL(kcpustat_field_iowait);
525+
526+
static u64 get_cpu_sleep_time_us(int cpu, enum cpu_usage_stat idx,
527+
bool compute_delta, u64 *last_update_time)
528+
{
529+
ktime_t now = ktime_get();
530+
u64 res;
531+
532+
if (vtime_generic_enabled_cpu(cpu))
533+
res = kcpustat_field(idx, cpu);
534+
else
535+
res = kcpustat_field_dyntick(cpu, idx, compute_delta, now);
536+
537+
do_div(res, NSEC_PER_USEC);
538+
539+
if (last_update_time)
540+
*last_update_time = ktime_to_us(now);
541+
542+
return res;
543+
}
544+
525545
/**
526546
* get_cpu_idle_time_us - get the total idle time of a CPU
527547
* @cpu: CPU number to query
@@ -569,7 +589,6 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
569589
nr_iowait_cpu(cpu), last_update_time);
570590
}
571591
EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
572-
573592
#endif /* CONFIG_NO_HZ_COMMON */
574593

575594
/*
@@ -1123,8 +1142,8 @@ u64 kcpustat_field(enum cpu_usage_stat usage, int cpu)
11231142
struct rq *rq;
11241143
int err;
11251144

1126-
if (!vtime_accounting_enabled_cpu(cpu))
1127-
return val;
1145+
if (!vtime_generic_enabled_cpu(cpu))
1146+
return kcpustat_field_default(usage, cpu);
11281147

11291148
rq = cpu_rq(cpu);
11301149

@@ -1219,8 +1238,8 @@ void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
12191238
struct rq *rq;
12201239
int err;
12211240

1222-
if (!vtime_accounting_enabled_cpu(cpu)) {
1223-
*dst = *src;
1241+
if (!vtime_generic_enabled_cpu(cpu)) {
1242+
kcpustat_cpu_fetch_default(dst, cpu);
12241243
return;
12251244
}
12261245

@@ -1233,7 +1252,7 @@ void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
12331252
curr = rcu_dereference(rq->curr);
12341253
if (WARN_ON_ONCE(!curr)) {
12351254
rcu_read_unlock();
1236-
*dst = *src;
1255+
kcpustat_cpu_fetch_default(dst, cpu);
12371256
return;
12381257
}
12391258

0 commit comments

Comments
 (0)