lkml.org 
[lkml]   [2022]   [Jan]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 683/846] sched/cpuacct: Fix user/system in shown cpuacct.usage*
    Date
    From: Andrey Ryabinin <arbn@yandex-team.com>

    commit dd02d4234c9a2214a81c57a16484304a1a51872a upstream.

    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: d740037fac70 ("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
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    kernel/sched/cpuacct.c | 79 +++++++++++++++++++------------------------------
    1 file changed, 32 insertions(+), 47 deletions(-)

    --- a/kernel/sched/cpuacct.c
    +++ b/kernel/sched/cpuacct.c
    @@ -21,15 +21,11 @@ static const char * const cpuacct_stat_d
    [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(
    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_s
    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 cgro
    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;

    /*
    @@ -115,14 +112,17 @@ static u64 cpuacct_cpuusage_read(struct
    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
    @@ -132,10 +132,14 @@ static u64 cpuacct_cpuusage_read(struct
    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
    /*
    @@ -143,9 +147,10 @@ static void cpuacct_cpuusage_write(struc
    */
    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));
    @@ -196,7 +201,7 @@ static int cpuusage_write(struct cgroup_
    return -EINVAL;

    for_each_possible_cpu(cpu)
    - cpuacct_cpuusage_write(ca, cpu, 0);
    + cpuacct_cpuusage_write(ca, cpu);

    return 0;
    }
    @@ -243,25 +248,10 @@ static int cpuacct_all_seq_show(struct s
    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;
    @@ -339,16 +329,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();
    }

    \
     
     \ /
      Last update: 2022-01-24 22:40    [W:2.379 / U:0.280 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site