mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
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
This commit is contained in:
committed by
Thomas Gleixner
parent
6a1f6a9dd0
commit
127b2eb44f
@@ -22,38 +22,6 @@
|
||||
#define arch_irq_stat() 0
|
||||
#endif
|
||||
|
||||
u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
|
||||
{
|
||||
u64 idle, idle_usecs = -1ULL;
|
||||
|
||||
if (cpu_online(cpu))
|
||||
idle_usecs = get_cpu_idle_time_us(cpu, NULL);
|
||||
|
||||
if (idle_usecs == -1ULL)
|
||||
/* !NO_HZ or cpu offline so we can rely on cpustat.idle */
|
||||
idle = kcs->cpustat[CPUTIME_IDLE];
|
||||
else
|
||||
idle = idle_usecs * NSEC_PER_USEC;
|
||||
|
||||
return idle;
|
||||
}
|
||||
|
||||
static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
|
||||
{
|
||||
u64 iowait, iowait_usecs = -1ULL;
|
||||
|
||||
if (cpu_online(cpu))
|
||||
iowait_usecs = get_cpu_iowait_time_us(cpu, NULL);
|
||||
|
||||
if (iowait_usecs == -1ULL)
|
||||
/* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
|
||||
iowait = kcs->cpustat[CPUTIME_IOWAIT];
|
||||
else
|
||||
iowait = iowait_usecs * NSEC_PER_USEC;
|
||||
|
||||
return iowait;
|
||||
}
|
||||
|
||||
static void show_irq_gap(struct seq_file *p, unsigned int gap)
|
||||
{
|
||||
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)
|
||||
user += cpustat[CPUTIME_USER];
|
||||
nice += cpustat[CPUTIME_NICE];
|
||||
system += cpustat[CPUTIME_SYSTEM];
|
||||
idle += get_idle_time(&kcpustat, i);
|
||||
iowait += get_iowait_time(&kcpustat, i);
|
||||
idle += cpustat[CPUTIME_IDLE];
|
||||
iowait += cpustat[CPUTIME_IOWAIT];
|
||||
irq += cpustat[CPUTIME_IRQ];
|
||||
softirq += cpustat[CPUTIME_SOFTIRQ];
|
||||
steal += cpustat[CPUTIME_STEAL];
|
||||
@@ -146,8 +114,8 @@ static int show_stat(struct seq_file *p, void *v)
|
||||
user = cpustat[CPUTIME_USER];
|
||||
nice = cpustat[CPUTIME_NICE];
|
||||
system = cpustat[CPUTIME_SYSTEM];
|
||||
idle = get_idle_time(&kcpustat, i);
|
||||
iowait = get_iowait_time(&kcpustat, i);
|
||||
idle = cpustat[CPUTIME_IDLE];
|
||||
iowait = cpustat[CPUTIME_IOWAIT];
|
||||
irq = cpustat[CPUTIME_IRQ];
|
||||
softirq = cpustat[CPUTIME_SOFTIRQ];
|
||||
steal = cpustat[CPUTIME_STEAL];
|
||||
|
||||
@@ -18,12 +18,8 @@ static int uptime_proc_show(struct seq_file *m, void *v)
|
||||
int i;
|
||||
|
||||
idle_nsec = 0;
|
||||
for_each_possible_cpu(i) {
|
||||
struct kernel_cpustat kcs;
|
||||
|
||||
kcpustat_cpu_fetch(&kcs, i);
|
||||
idle_nsec += get_idle_time(&kcs, i);
|
||||
}
|
||||
for_each_possible_cpu(i)
|
||||
idle_nsec += kcpustat_field(CPUTIME_IDLE, i);
|
||||
|
||||
ktime_get_boottime_ts64(&uptime);
|
||||
timens_add_boottime(&uptime);
|
||||
|
||||
@@ -110,32 +110,59 @@ extern void kcpustat_dyntick_start(u64 now);
|
||||
extern void kcpustat_dyntick_stop(u64 now);
|
||||
extern void kcpustat_irq_enter(u64 now);
|
||||
extern void kcpustat_irq_exit(u64 now);
|
||||
extern u64 kcpustat_field_idle(int cpu);
|
||||
extern u64 kcpustat_field_iowait(int cpu);
|
||||
|
||||
static inline bool kcpustat_idle_dyntick(void)
|
||||
{
|
||||
return __this_cpu_read(kernel_cpustat.idle_dyntick);
|
||||
}
|
||||
#else
|
||||
static inline u64 kcpustat_field_idle(int cpu)
|
||||
{
|
||||
return kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
|
||||
}
|
||||
static inline u64 kcpustat_field_iowait(int cpu)
|
||||
{
|
||||
return kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
|
||||
}
|
||||
|
||||
static inline bool kcpustat_idle_dyntick(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_NO_HZ_COMMON */
|
||||
|
||||
/* Fetch cputime values when vtime is disabled on a CPU */
|
||||
static inline u64 kcpustat_field_default(enum cpu_usage_stat usage, int cpu)
|
||||
{
|
||||
if (usage == CPUTIME_IDLE)
|
||||
return kcpustat_field_idle(cpu);
|
||||
if (usage == CPUTIME_IOWAIT)
|
||||
return kcpustat_field_iowait(cpu);
|
||||
return kcpustat_cpu(cpu).cpustat[usage];
|
||||
}
|
||||
|
||||
static inline void kcpustat_cpu_fetch_default(struct kernel_cpustat *dst, int cpu)
|
||||
{
|
||||
*dst = kcpustat_cpu(cpu);
|
||||
dst->cpustat[CPUTIME_IDLE] = kcpustat_field_idle(cpu);
|
||||
dst->cpustat[CPUTIME_IOWAIT] = kcpustat_field_iowait(cpu);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
|
||||
extern u64 kcpustat_field(enum cpu_usage_stat usage, int cpu);
|
||||
extern void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu);
|
||||
#else
|
||||
static inline u64 kcpustat_field(enum cpu_usage_stat usage, int cpu)
|
||||
{
|
||||
return kcpustat_cpu(cpu).cpustat[usage];
|
||||
return kcpustat_field_default(usage, cpu);
|
||||
}
|
||||
|
||||
static inline void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
|
||||
{
|
||||
*dst = kcpustat_cpu(cpu);
|
||||
kcpustat_cpu_fetch_default(dst, cpu);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_GEN */
|
||||
|
||||
extern void account_user_time(struct task_struct *, u64);
|
||||
@@ -145,7 +172,6 @@ extern void account_system_index_time(struct task_struct *, u64,
|
||||
enum cpu_usage_stat);
|
||||
extern void account_steal_time(u64);
|
||||
extern void account_idle_time(u64);
|
||||
extern u64 get_idle_time(struct kernel_cpustat *kcs, int cpu);
|
||||
|
||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
|
||||
static inline void account_process_tick(struct task_struct *tsk, int user)
|
||||
|
||||
@@ -490,24 +490,14 @@ void kcpustat_irq_exit(u64 now)
|
||||
kcpustat_idle_start(kc, now);
|
||||
}
|
||||
|
||||
static u64 get_cpu_sleep_time_us(int cpu, enum cpu_usage_stat idx,
|
||||
bool compute_delta, u64 *last_update_time)
|
||||
static u64 kcpustat_field_dyntick(int cpu, enum cpu_usage_stat idx,
|
||||
bool compute_delta, u64 now)
|
||||
{
|
||||
struct kernel_cpustat *kc = &kcpustat_cpu(cpu);
|
||||
u64 *cpustat = kc->cpustat;
|
||||
unsigned int seq;
|
||||
ktime_t now;
|
||||
u64 idle;
|
||||
|
||||
now = ktime_get();
|
||||
if (last_update_time)
|
||||
*last_update_time = ktime_to_us(now);
|
||||
|
||||
if (vtime_generic_enabled_cpu(cpu)) {
|
||||
idle = kcpustat_field(idx, cpu);
|
||||
goto to_us;
|
||||
}
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&kc->idle_sleeptime_seq);
|
||||
|
||||
@@ -516,12 +506,42 @@ static u64 get_cpu_sleep_time_us(int cpu, enum cpu_usage_stat idx,
|
||||
idle += (now - kc->idle_entrytime);
|
||||
} while (read_seqcount_retry(&kc->idle_sleeptime_seq, seq));
|
||||
|
||||
to_us:
|
||||
do_div(idle, NSEC_PER_USEC);
|
||||
|
||||
return idle;
|
||||
}
|
||||
|
||||
u64 kcpustat_field_idle(int cpu)
|
||||
{
|
||||
return kcpustat_field_dyntick(cpu, CPUTIME_IDLE,
|
||||
!nr_iowait_cpu(cpu), ktime_get());
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kcpustat_field_idle);
|
||||
|
||||
u64 kcpustat_field_iowait(int cpu)
|
||||
{
|
||||
return kcpustat_field_dyntick(cpu, CPUTIME_IOWAIT,
|
||||
nr_iowait_cpu(cpu), ktime_get());
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kcpustat_field_iowait);
|
||||
|
||||
static u64 get_cpu_sleep_time_us(int cpu, enum cpu_usage_stat idx,
|
||||
bool compute_delta, u64 *last_update_time)
|
||||
{
|
||||
ktime_t now = ktime_get();
|
||||
u64 res;
|
||||
|
||||
if (vtime_generic_enabled_cpu(cpu))
|
||||
res = kcpustat_field(idx, cpu);
|
||||
else
|
||||
res = kcpustat_field_dyntick(cpu, idx, compute_delta, now);
|
||||
|
||||
do_div(res, NSEC_PER_USEC);
|
||||
|
||||
if (last_update_time)
|
||||
*last_update_time = ktime_to_us(now);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_cpu_idle_time_us - get the total idle time of a CPU
|
||||
* @cpu: CPU number to query
|
||||
@@ -569,7 +589,6 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
|
||||
nr_iowait_cpu(cpu), last_update_time);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
|
||||
|
||||
#endif /* CONFIG_NO_HZ_COMMON */
|
||||
|
||||
/*
|
||||
@@ -1123,8 +1142,8 @@ u64 kcpustat_field(enum cpu_usage_stat usage, int cpu)
|
||||
struct rq *rq;
|
||||
int err;
|
||||
|
||||
if (!vtime_accounting_enabled_cpu(cpu))
|
||||
return val;
|
||||
if (!vtime_generic_enabled_cpu(cpu))
|
||||
return kcpustat_field_default(usage, cpu);
|
||||
|
||||
rq = cpu_rq(cpu);
|
||||
|
||||
@@ -1219,8 +1238,8 @@ void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
|
||||
struct rq *rq;
|
||||
int err;
|
||||
|
||||
if (!vtime_accounting_enabled_cpu(cpu)) {
|
||||
*dst = *src;
|
||||
if (!vtime_generic_enabled_cpu(cpu)) {
|
||||
kcpustat_cpu_fetch_default(dst, cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1233,7 +1252,7 @@ void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
|
||||
curr = rcu_dereference(rq->curr);
|
||||
if (WARN_ON_ONCE(!curr)) {
|
||||
rcu_read_unlock();
|
||||
*dst = *src;
|
||||
kcpustat_cpu_fetch_default(dst, cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user