sched/cpuacct: Fix user/system in shown cpuacct.usage*
cpuacct has 2 different ways of accounting and showing user
and system times.
The first one uses cpuacct_account_field() to account times
and cpuacct.stat file to expose them. And this one seems to work ok.
The second one is uses cpuacct_charge() function for accounting and
set of cpuacct.usage* files to show times. Despite some attempts to
fix it in the past it still doesn't work. Sometimes while running KVM
guest the cpuacct_charge() accounts most of the guest time as
system time. This doesn't match with user&system times shown in
cpuacct.stat or proc/<pid>/stat.
Demonstration:
# git clone https://github.com/aryabinin/kvmsample
# make
# mkdir /sys/fs/cgroup/cpuacct/test
# echo $$ > /sys/fs/cgroup/cpuacct/test/tasks
# ./kvmsample &
# for i in {1..5}; do cat /sys/fs/cgroup/cpuacct/test/cpuacct.usage_sys; sleep 1; done
1976535645
2979839428
3979832704
4983603153
5983604157
Use cpustats accounted in cpuacct_account_field() as the source
of user/sys times for cpuacct.usage* files. Make cpuacct_charge()
to account only summary execution time.
Fixes: d740037fac
("sched/cpuacct: Split usage accounting into user_usage and sys_usage")
Signed-off-by: Andrey Ryabinin <arbn@yandex-team.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20211115164607.23784-3-arbn@yandex-team.com
This commit is contained in:
parent
c7ccbf4b61
commit
dd02d4234c
|
@ -21,15 +21,11 @@ static const char * const cpuacct_stat_desc[] = {
|
|||
[CPUACCT_STAT_SYSTEM] = "system",
|
||||
};
|
||||
|
||||
struct cpuacct_usage {
|
||||
u64 usages[CPUACCT_STAT_NSTATS];
|
||||
};
|
||||
|
||||
/* track CPU usage of a group of tasks and its child groups */
|
||||
struct cpuacct {
|
||||
struct cgroup_subsys_state css;
|
||||
/* cpuusage holds pointer to a u64-type object on every CPU */
|
||||
struct cpuacct_usage __percpu *cpuusage;
|
||||
u64 __percpu *cpuusage;
|
||||
struct kernel_cpustat __percpu *cpustat;
|
||||
};
|
||||
|
||||
|
@ -49,7 +45,7 @@ static inline struct cpuacct *parent_ca(struct cpuacct *ca)
|
|||
return css_ca(ca->css.parent);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct cpuacct_usage, root_cpuacct_cpuusage);
|
||||
static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage);
|
||||
static struct cpuacct root_cpuacct = {
|
||||
.cpustat = &kernel_cpustat,
|
||||
.cpuusage = &root_cpuacct_cpuusage,
|
||||
|
@ -68,7 +64,7 @@ cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
|
|||
if (!ca)
|
||||
goto out;
|
||||
|
||||
ca->cpuusage = alloc_percpu(struct cpuacct_usage);
|
||||
ca->cpuusage = alloc_percpu(u64);
|
||||
if (!ca->cpuusage)
|
||||
goto out_free_ca;
|
||||
|
||||
|
@ -99,7 +95,8 @@ static void cpuacct_css_free(struct cgroup_subsys_state *css)
|
|||
static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
|
||||
enum cpuacct_stat_index index)
|
||||
{
|
||||
struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
|
||||
u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
|
||||
u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
|
||||
u64 data;
|
||||
|
||||
/*
|
||||
|
@ -116,14 +113,17 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
|
|||
raw_spin_rq_lock_irq(cpu_rq(cpu));
|
||||
#endif
|
||||
|
||||
if (index == CPUACCT_STAT_NSTATS) {
|
||||
int i = 0;
|
||||
|
||||
data = 0;
|
||||
for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
|
||||
data += cpuusage->usages[i];
|
||||
} else {
|
||||
data = cpuusage->usages[index];
|
||||
switch (index) {
|
||||
case CPUACCT_STAT_USER:
|
||||
data = cpustat[CPUTIME_USER] + cpustat[CPUTIME_NICE];
|
||||
break;
|
||||
case CPUACCT_STAT_SYSTEM:
|
||||
data = cpustat[CPUTIME_SYSTEM] + cpustat[CPUTIME_IRQ] +
|
||||
cpustat[CPUTIME_SOFTIRQ];
|
||||
break;
|
||||
case CPUACCT_STAT_NSTATS:
|
||||
data = *cpuusage;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
|
@ -133,10 +133,14 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
|
|||
return data;
|
||||
}
|
||||
|
||||
static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
|
||||
static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu)
|
||||
{
|
||||
struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
|
||||
int i;
|
||||
u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
|
||||
u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
|
||||
|
||||
/* Don't allow to reset global kernel_cpustat */
|
||||
if (ca == &root_cpuacct)
|
||||
return;
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
/*
|
||||
|
@ -144,9 +148,10 @@ static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
|
|||
*/
|
||||
raw_spin_rq_lock_irq(cpu_rq(cpu));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
|
||||
cpuusage->usages[i] = val;
|
||||
*cpuusage = 0;
|
||||
cpustat[CPUTIME_USER] = cpustat[CPUTIME_NICE] = 0;
|
||||
cpustat[CPUTIME_SYSTEM] = cpustat[CPUTIME_IRQ] = 0;
|
||||
cpustat[CPUTIME_SOFTIRQ] = 0;
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
raw_spin_rq_unlock_irq(cpu_rq(cpu));
|
||||
|
@ -197,7 +202,7 @@ static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
return -EINVAL;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
cpuacct_cpuusage_write(ca, cpu, 0);
|
||||
cpuacct_cpuusage_write(ca, cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -244,25 +249,10 @@ static int cpuacct_all_seq_show(struct seq_file *m, void *V)
|
|||
seq_puts(m, "\n");
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
|
||||
|
||||
seq_printf(m, "%d", cpu);
|
||||
|
||||
for (index = 0; index < CPUACCT_STAT_NSTATS; index++) {
|
||||
#ifndef CONFIG_64BIT
|
||||
/*
|
||||
* Take rq->lock to make 64-bit read safe on 32-bit
|
||||
* platforms.
|
||||
*/
|
||||
raw_spin_rq_lock_irq(cpu_rq(cpu));
|
||||
#endif
|
||||
|
||||
seq_printf(m, " %llu", cpuusage->usages[index]);
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
raw_spin_rq_unlock_irq(cpu_rq(cpu));
|
||||
#endif
|
||||
}
|
||||
for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
|
||||
seq_printf(m, " %llu",
|
||||
cpuacct_cpuusage_read(ca, cpu, index));
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
return 0;
|
||||
|
@ -340,16 +330,11 @@ static struct cftype files[] = {
|
|||
void cpuacct_charge(struct task_struct *tsk, u64 cputime)
|
||||
{
|
||||
struct cpuacct *ca;
|
||||
int index = CPUACCT_STAT_SYSTEM;
|
||||
struct pt_regs *regs = get_irq_regs() ? : task_pt_regs(tsk);
|
||||
|
||||
if (regs && user_mode(regs))
|
||||
index = CPUACCT_STAT_USER;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
|
||||
__this_cpu_add(ca->cpuusage->usages[index], cputime);
|
||||
__this_cpu_add(*ca->cpuusage, cputime);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue