linux/kernel/sched/cpuacct.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * CPU accounting code for task groups.
   4 *
   5 * Based on the work by Paul Menage (menage@google.com) and Balbir Singh
   6 * (balbir@in.ibm.com).
   7 */
   8#include "sched.h"
   9
  10/* Time spent by the tasks of the CPU accounting group executing in ... */
  11enum cpuacct_stat_index {
  12        CPUACCT_STAT_USER,      /* ... user mode */
  13        CPUACCT_STAT_SYSTEM,    /* ... kernel mode */
  14
  15        CPUACCT_STAT_NSTATS,
  16};
  17
  18static const char * const cpuacct_stat_desc[] = {
  19        [CPUACCT_STAT_USER] = "user",
  20        [CPUACCT_STAT_SYSTEM] = "system",
  21};
  22
  23struct cpuacct_usage {
  24        u64     usages[CPUACCT_STAT_NSTATS];
  25};
  26
  27/* track CPU usage of a group of tasks and its child groups */
  28struct cpuacct {
  29        struct cgroup_subsys_state      css;
  30        /* cpuusage holds pointer to a u64-type object on every CPU */
  31        struct cpuacct_usage __percpu   *cpuusage;
  32        struct kernel_cpustat __percpu  *cpustat;
  33};
  34
  35static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css)
  36{
  37        return css ? container_of(css, struct cpuacct, css) : NULL;
  38}
  39
  40/* Return CPU accounting group to which this task belongs */
  41static inline struct cpuacct *task_ca(struct task_struct *tsk)
  42{
  43        return css_ca(task_css(tsk, cpuacct_cgrp_id));
  44}
  45
  46static inline struct cpuacct *parent_ca(struct cpuacct *ca)
  47{
  48        return css_ca(ca->css.parent);
  49}
  50
  51static DEFINE_PER_CPU(struct cpuacct_usage, root_cpuacct_cpuusage);
  52static struct cpuacct root_cpuacct = {
  53        .cpustat        = &kernel_cpustat,
  54        .cpuusage       = &root_cpuacct_cpuusage,
  55};
  56
  57/* Create a new CPU accounting group */
  58static struct cgroup_subsys_state *
  59cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
  60{
  61        struct cpuacct *ca;
  62
  63        if (!parent_css)
  64                return &root_cpuacct.css;
  65
  66        ca = kzalloc(sizeof(*ca), GFP_KERNEL);
  67        if (!ca)
  68                goto out;
  69
  70        ca->cpuusage = alloc_percpu(struct cpuacct_usage);
  71        if (!ca->cpuusage)
  72                goto out_free_ca;
  73
  74        ca->cpustat = alloc_percpu(struct kernel_cpustat);
  75        if (!ca->cpustat)
  76                goto out_free_cpuusage;
  77
  78        return &ca->css;
  79
  80out_free_cpuusage:
  81        free_percpu(ca->cpuusage);
  82out_free_ca:
  83        kfree(ca);
  84out:
  85        return ERR_PTR(-ENOMEM);
  86}
  87
  88/* Destroy an existing CPU accounting group */
  89static void cpuacct_css_free(struct cgroup_subsys_state *css)
  90{
  91        struct cpuacct *ca = css_ca(css);
  92
  93        free_percpu(ca->cpustat);
  94        free_percpu(ca->cpuusage);
  95        kfree(ca);
  96}
  97
  98static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
  99                                 enum cpuacct_stat_index index)
 100{
 101        struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
 102        u64 data;
 103
 104        /*
 105         * We allow index == CPUACCT_STAT_NSTATS here to read
 106         * the sum of suages.
 107         */
 108        BUG_ON(index > CPUACCT_STAT_NSTATS);
 109
 110#ifndef CONFIG_64BIT
 111        /*
 112         * Take rq->lock to make 64-bit read safe on 32-bit platforms.
 113         */
 114        raw_spin_lock_irq(&cpu_rq(cpu)->lock);
 115#endif
 116
 117        if (index == CPUACCT_STAT_NSTATS) {
 118                int i = 0;
 119
 120                data = 0;
 121                for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
 122                        data += cpuusage->usages[i];
 123        } else {
 124                data = cpuusage->usages[index];
 125        }
 126
 127#ifndef CONFIG_64BIT
 128        raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
 129#endif
 130
 131        return data;
 132}
 133
 134static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
 135{
 136        struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
 137        int i;
 138
 139#ifndef CONFIG_64BIT
 140        /*
 141         * Take rq->lock to make 64-bit write safe on 32-bit platforms.
 142         */
 143        raw_spin_lock_irq(&cpu_rq(cpu)->lock);
 144#endif
 145
 146        for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
 147                cpuusage->usages[i] = val;
 148
 149#ifndef CONFIG_64BIT
 150        raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
 151#endif
 152}
 153
 154/* Return total CPU usage (in nanoseconds) of a group */
 155static u64 __cpuusage_read(struct cgroup_subsys_state *css,
 156                           enum cpuacct_stat_index index)
 157{
 158        struct cpuacct *ca = css_ca(css);
 159        u64 totalcpuusage = 0;
 160        int i;
 161
 162        for_each_possible_cpu(i)
 163                totalcpuusage += cpuacct_cpuusage_read(ca, i, index);
 164
 165        return totalcpuusage;
 166}
 167
 168static u64 cpuusage_user_read(struct cgroup_subsys_state *css,
 169                              struct cftype *cft)
 170{
 171        return __cpuusage_read(css, CPUACCT_STAT_USER);
 172}
 173
 174static u64 cpuusage_sys_read(struct cgroup_subsys_state *css,
 175                             struct cftype *cft)
 176{
 177        return __cpuusage_read(css, CPUACCT_STAT_SYSTEM);
 178}
 179
 180static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
 181{
 182        return __cpuusage_read(css, CPUACCT_STAT_NSTATS);
 183}
 184
 185static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
 186                          u64 val)
 187{
 188        struct cpuacct *ca = css_ca(css);
 189        int cpu;
 190
 191        /*
 192         * Only allow '0' here to do a reset.
 193         */
 194        if (val)
 195                return -EINVAL;
 196
 197        for_each_possible_cpu(cpu)
 198                cpuacct_cpuusage_write(ca, cpu, 0);
 199
 200        return 0;
 201}
 202
 203static int __cpuacct_percpu_seq_show(struct seq_file *m,
 204                                     enum cpuacct_stat_index index)
 205{
 206        struct cpuacct *ca = css_ca(seq_css(m));
 207        u64 percpu;
 208        int i;
 209
 210        for_each_possible_cpu(i) {
 211                percpu = cpuacct_cpuusage_read(ca, i, index);
 212                seq_printf(m, "%llu ", (unsigned long long) percpu);
 213        }
 214        seq_printf(m, "\n");
 215        return 0;
 216}
 217
 218static int cpuacct_percpu_user_seq_show(struct seq_file *m, void *V)
 219{
 220        return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_USER);
 221}
 222
 223static int cpuacct_percpu_sys_seq_show(struct seq_file *m, void *V)
 224{
 225        return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_SYSTEM);
 226}
 227
 228static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
 229{
 230        return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS);
 231}
 232
 233static int cpuacct_all_seq_show(struct seq_file *m, void *V)
 234{
 235        struct cpuacct *ca = css_ca(seq_css(m));
 236        int index;
 237        int cpu;
 238
 239        seq_puts(m, "cpu");
 240        for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
 241                seq_printf(m, " %s", cpuacct_stat_desc[index]);
 242        seq_puts(m, "\n");
 243
 244        for_each_possible_cpu(cpu) {
 245                struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
 246
 247                seq_printf(m, "%d", cpu);
 248
 249                for (index = 0; index < CPUACCT_STAT_NSTATS; index++) {
 250#ifndef CONFIG_64BIT
 251                        /*
 252                         * Take rq->lock to make 64-bit read safe on 32-bit
 253                         * platforms.
 254                         */
 255                        raw_spin_lock_irq(&cpu_rq(cpu)->lock);
 256#endif
 257
 258                        seq_printf(m, " %llu", cpuusage->usages[index]);
 259
 260#ifndef CONFIG_64BIT
 261                        raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
 262#endif
 263                }
 264                seq_puts(m, "\n");
 265        }
 266        return 0;
 267}
 268
 269static int cpuacct_stats_show(struct seq_file *sf, void *v)
 270{
 271        struct cpuacct *ca = css_ca(seq_css(sf));
 272        s64 val[CPUACCT_STAT_NSTATS];
 273        int cpu;
 274        int stat;
 275
 276        memset(val, 0, sizeof(val));
 277        for_each_possible_cpu(cpu) {
 278                u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
 279
 280                val[CPUACCT_STAT_USER]   += cpustat[CPUTIME_USER];
 281                val[CPUACCT_STAT_USER]   += cpustat[CPUTIME_NICE];
 282                val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SYSTEM];
 283                val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_IRQ];
 284                val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SOFTIRQ];
 285        }
 286
 287        for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) {
 288                seq_printf(sf, "%s %lld\n",
 289                           cpuacct_stat_desc[stat],
 290                           (long long)nsec_to_clock_t(val[stat]));
 291        }
 292
 293        return 0;
 294}
 295
 296static struct cftype files[] = {
 297        {
 298                .name = "usage",
 299                .read_u64 = cpuusage_read,
 300                .write_u64 = cpuusage_write,
 301        },
 302        {
 303                .name = "usage_user",
 304                .read_u64 = cpuusage_user_read,
 305        },
 306        {
 307                .name = "usage_sys",
 308                .read_u64 = cpuusage_sys_read,
 309        },
 310        {
 311                .name = "usage_percpu",
 312                .seq_show = cpuacct_percpu_seq_show,
 313        },
 314        {
 315                .name = "usage_percpu_user",
 316                .seq_show = cpuacct_percpu_user_seq_show,
 317        },
 318        {
 319                .name = "usage_percpu_sys",
 320                .seq_show = cpuacct_percpu_sys_seq_show,
 321        },
 322        {
 323                .name = "usage_all",
 324                .seq_show = cpuacct_all_seq_show,
 325        },
 326        {
 327                .name = "stat",
 328                .seq_show = cpuacct_stats_show,
 329        },
 330        { }     /* terminate */
 331};
 332
 333/*
 334 * charge this task's execution time to its accounting group.
 335 *
 336 * called with rq->lock held.
 337 */
 338void cpuacct_charge(struct task_struct *tsk, u64 cputime)
 339{
 340        struct cpuacct *ca;
 341        int index = CPUACCT_STAT_SYSTEM;
 342        struct pt_regs *regs = task_pt_regs(tsk);
 343
 344        if (regs && user_mode(regs))
 345                index = CPUACCT_STAT_USER;
 346
 347        rcu_read_lock();
 348
 349        for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
 350                this_cpu_ptr(ca->cpuusage)->usages[index] += cputime;
 351
 352        rcu_read_unlock();
 353}
 354
 355/*
 356 * Add user/system time to cpuacct.
 357 *
 358 * Note: it's the caller that updates the account of the root cgroup.
 359 */
 360void cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
 361{
 362        struct cpuacct *ca;
 363
 364        rcu_read_lock();
 365        for (ca = task_ca(tsk); ca != &root_cpuacct; ca = parent_ca(ca))
 366                this_cpu_ptr(ca->cpustat)->cpustat[index] += val;
 367        rcu_read_unlock();
 368}
 369
 370struct cgroup_subsys cpuacct_cgrp_subsys = {
 371        .css_alloc      = cpuacct_css_alloc,
 372        .css_free       = cpuacct_css_free,
 373        .legacy_cftypes = files,
 374        .early_init     = true,
 375};
 376