linux/kernel/sched/cpuacct.c
<<
>>
Prefs
   1#include <linux/cgroup.h>
   2#include <linux/slab.h>
   3#include <linux/percpu.h>
   4#include <linux/spinlock.h>
   5#include <linux/cpumask.h>
   6#include <linux/seq_file.h>
   7#include <linux/rcupdate.h>
   8#include <linux/kernel_stat.h>
   9#include <linux/err.h>
  10
  11#include "sched.h"
  12
  13/*
  14 * CPU accounting code for task groups.
  15 *
  16 * Based on the work by Paul Menage (menage@google.com) and Balbir Singh
  17 * (balbir@in.ibm.com).
  18 */
  19
  20/* Time spent by the tasks of the cpu accounting group executing in ... */
  21enum cpuacct_stat_index {
  22        CPUACCT_STAT_USER,      /* ... user mode */
  23        CPUACCT_STAT_SYSTEM,    /* ... kernel mode */
  24
  25        CPUACCT_STAT_NSTATS,
  26};
  27
  28/* track cpu usage of a group of tasks and its child groups */
  29struct cpuacct {
  30        struct cgroup_subsys_state css;
  31        /* cpuusage holds pointer to a u64-type object on every cpu */
  32        u64 __percpu *cpuusage;
  33        struct kernel_cpustat __percpu *cpustat;
  34};
  35
  36static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css)
  37{
  38        return css ? container_of(css, struct cpuacct, css) : NULL;
  39}
  40
  41/* return cpu accounting group to which this task belongs */
  42static inline struct cpuacct *task_ca(struct task_struct *tsk)
  43{
  44        return css_ca(task_css(tsk, cpuacct_cgrp_id));
  45}
  46
  47static inline struct cpuacct *parent_ca(struct cpuacct *ca)
  48{
  49        return css_ca(ca->css.parent);
  50}
  51
  52static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage);
  53static struct cpuacct root_cpuacct = {
  54        .cpustat        = &kernel_cpustat,
  55        .cpuusage       = &root_cpuacct_cpuusage,
  56};
  57
  58/* create a new cpu accounting group */
  59static struct cgroup_subsys_state *
  60cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
  61{
  62        struct cpuacct *ca;
  63
  64        if (!parent_css)
  65                return &root_cpuacct.css;
  66
  67        ca = kzalloc(sizeof(*ca), GFP_KERNEL);
  68        if (!ca)
  69                goto out;
  70
  71        ca->cpuusage = alloc_percpu(u64);
  72        if (!ca->cpuusage)
  73                goto out_free_ca;
  74
  75        ca->cpustat = alloc_percpu(struct kernel_cpustat);
  76        if (!ca->cpustat)
  77                goto out_free_cpuusage;
  78
  79        return &ca->css;
  80
  81out_free_cpuusage:
  82        free_percpu(ca->cpuusage);
  83out_free_ca:
  84        kfree(ca);
  85out:
  86        return ERR_PTR(-ENOMEM);
  87}
  88
  89/* destroy an existing cpu accounting group */
  90static void cpuacct_css_free(struct cgroup_subsys_state *css)
  91{
  92        struct cpuacct *ca = css_ca(css);
  93
  94        free_percpu(ca->cpustat);
  95        free_percpu(ca->cpuusage);
  96        kfree(ca);
  97}
  98
  99static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu)
 100{
 101        u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
 102        u64 data;
 103
 104#ifndef CONFIG_64BIT
 105        /*
 106         * Take rq->lock to make 64-bit read safe on 32-bit platforms.
 107         */
 108        raw_spin_lock_irq(&cpu_rq(cpu)->lock);
 109        data = *cpuusage;
 110        raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
 111#else
 112        data = *cpuusage;
 113#endif
 114
 115        return data;
 116}
 117
 118static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
 119{
 120        u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
 121
 122#ifndef CONFIG_64BIT
 123        /*
 124         * Take rq->lock to make 64-bit write safe on 32-bit platforms.
 125         */
 126        raw_spin_lock_irq(&cpu_rq(cpu)->lock);
 127        *cpuusage = val;
 128        raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
 129#else
 130        *cpuusage = val;
 131#endif
 132}
 133
 134/* return total cpu usage (in nanoseconds) of a group */
 135static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
 136{
 137        struct cpuacct *ca = css_ca(css);
 138        u64 totalcpuusage = 0;
 139        int i;
 140
 141        for_each_present_cpu(i)
 142                totalcpuusage += cpuacct_cpuusage_read(ca, i);
 143
 144        return totalcpuusage;
 145}
 146
 147static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
 148                          u64 reset)
 149{
 150        struct cpuacct *ca = css_ca(css);
 151        int err = 0;
 152        int i;
 153
 154        if (reset) {
 155                err = -EINVAL;
 156                goto out;
 157        }
 158
 159        for_each_present_cpu(i)
 160                cpuacct_cpuusage_write(ca, i, 0);
 161
 162out:
 163        return err;
 164}
 165
 166static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
 167{
 168        struct cpuacct *ca = css_ca(seq_css(m));
 169        u64 percpu;
 170        int i;
 171
 172        for_each_present_cpu(i) {
 173                percpu = cpuacct_cpuusage_read(ca, i);
 174                seq_printf(m, "%llu ", (unsigned long long) percpu);
 175        }
 176        seq_printf(m, "\n");
 177        return 0;
 178}
 179
 180static const char * const cpuacct_stat_desc[] = {
 181        [CPUACCT_STAT_USER] = "user",
 182        [CPUACCT_STAT_SYSTEM] = "system",
 183};
 184
 185static int cpuacct_stats_show(struct seq_file *sf, void *v)
 186{
 187        struct cpuacct *ca = css_ca(seq_css(sf));
 188        int cpu;
 189        s64 val = 0;
 190
 191        for_each_online_cpu(cpu) {
 192                struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu);
 193                val += kcpustat->cpustat[CPUTIME_USER];
 194                val += kcpustat->cpustat[CPUTIME_NICE];
 195        }
 196        val = cputime64_to_clock_t(val);
 197        seq_printf(sf, "%s %lld\n", cpuacct_stat_desc[CPUACCT_STAT_USER], val);
 198
 199        val = 0;
 200        for_each_online_cpu(cpu) {
 201                struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu);
 202                val += kcpustat->cpustat[CPUTIME_SYSTEM];
 203                val += kcpustat->cpustat[CPUTIME_IRQ];
 204                val += kcpustat->cpustat[CPUTIME_SOFTIRQ];
 205        }
 206
 207        val = cputime64_to_clock_t(val);
 208        seq_printf(sf, "%s %lld\n", cpuacct_stat_desc[CPUACCT_STAT_SYSTEM], val);
 209
 210        return 0;
 211}
 212
 213static struct cftype files[] = {
 214        {
 215                .name = "usage",
 216                .read_u64 = cpuusage_read,
 217                .write_u64 = cpuusage_write,
 218        },
 219        {
 220                .name = "usage_percpu",
 221                .seq_show = cpuacct_percpu_seq_show,
 222        },
 223        {
 224                .name = "stat",
 225                .seq_show = cpuacct_stats_show,
 226        },
 227        { }     /* terminate */
 228};
 229
 230/*
 231 * charge this task's execution time to its accounting group.
 232 *
 233 * called with rq->lock held.
 234 */
 235void cpuacct_charge(struct task_struct *tsk, u64 cputime)
 236{
 237        struct cpuacct *ca;
 238        int cpu;
 239
 240        cpu = task_cpu(tsk);
 241
 242        rcu_read_lock();
 243
 244        ca = task_ca(tsk);
 245
 246        while (true) {
 247                u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
 248                *cpuusage += cputime;
 249
 250                ca = parent_ca(ca);
 251                if (!ca)
 252                        break;
 253        }
 254
 255        rcu_read_unlock();
 256}
 257
 258/*
 259 * Add user/system time to cpuacct.
 260 *
 261 * Note: it's the caller that updates the account of the root cgroup.
 262 */
 263void cpuacct_account_field(struct task_struct *p, int index, u64 val)
 264{
 265        struct kernel_cpustat *kcpustat;
 266        struct cpuacct *ca;
 267
 268        rcu_read_lock();
 269        ca = task_ca(p);
 270        while (ca != &root_cpuacct) {
 271                kcpustat = this_cpu_ptr(ca->cpustat);
 272                kcpustat->cpustat[index] += val;
 273                ca = parent_ca(ca);
 274        }
 275        rcu_read_unlock();
 276}
 277
 278struct cgroup_subsys cpuacct_cgrp_subsys = {
 279        .css_alloc      = cpuacct_css_alloc,
 280        .css_free       = cpuacct_css_free,
 281        .legacy_cftypes = files,
 282        .early_init     = 1,
 283};
 284