root/kernel/sched/cpuacct.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. css_ca
  2. task_ca
  3. parent_ca
  4. cpuacct_css_alloc
  5. cpuacct_css_free
  6. cpuacct_cpuusage_read
  7. cpuacct_cpuusage_write
  8. __cpuusage_read
  9. cpuusage_user_read
  10. cpuusage_sys_read
  11. cpuusage_read
  12. cpuusage_write
  13. __cpuacct_percpu_seq_show
  14. cpuacct_percpu_user_seq_show
  15. cpuacct_percpu_sys_seq_show
  16. cpuacct_percpu_seq_show
  17. cpuacct_all_seq_show
  18. cpuacct_stats_show
  19. cpuacct_charge
  20. cpuacct_account_field

   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 ... */
  11 enum cpuacct_stat_index {
  12         CPUACCT_STAT_USER,      /* ... user mode */
  13         CPUACCT_STAT_SYSTEM,    /* ... kernel mode */
  14 
  15         CPUACCT_STAT_NSTATS,
  16 };
  17 
  18 static const char * const cpuacct_stat_desc[] = {
  19         [CPUACCT_STAT_USER] = "user",
  20         [CPUACCT_STAT_SYSTEM] = "system",
  21 };
  22 
  23 struct cpuacct_usage {
  24         u64     usages[CPUACCT_STAT_NSTATS];
  25 };
  26 
  27 /* track CPU usage of a group of tasks and its child groups */
  28 struct 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 
  35 static 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 */
  41 static inline struct cpuacct *task_ca(struct task_struct *tsk)
  42 {
  43         return css_ca(task_css(tsk, cpuacct_cgrp_id));
  44 }
  45 
  46 static inline struct cpuacct *parent_ca(struct cpuacct *ca)
  47 {
  48         return css_ca(ca->css.parent);
  49 }
  50 
  51 static DEFINE_PER_CPU(struct cpuacct_usage, root_cpuacct_cpuusage);
  52 static struct cpuacct root_cpuacct = {
  53         .cpustat        = &kernel_cpustat,
  54         .cpuusage       = &root_cpuacct_cpuusage,
  55 };
  56 
  57 /* Create a new CPU accounting group */
  58 static struct cgroup_subsys_state *
  59 cpuacct_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 
  80 out_free_cpuusage:
  81         free_percpu(ca->cpuusage);
  82 out_free_ca:
  83         kfree(ca);
  84 out:
  85         return ERR_PTR(-ENOMEM);
  86 }
  87 
  88 /* Destroy an existing CPU accounting group */
  89 static 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 
  98 static 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 
 134 static 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 */
 155 static 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 
 168 static u64 cpuusage_user_read(struct cgroup_subsys_state *css,
 169                               struct cftype *cft)
 170 {
 171         return __cpuusage_read(css, CPUACCT_STAT_USER);
 172 }
 173 
 174 static u64 cpuusage_sys_read(struct cgroup_subsys_state *css,
 175                              struct cftype *cft)
 176 {
 177         return __cpuusage_read(css, CPUACCT_STAT_SYSTEM);
 178 }
 179 
 180 static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
 181 {
 182         return __cpuusage_read(css, CPUACCT_STAT_NSTATS);
 183 }
 184 
 185 static 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 
 203 static 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 
 218 static 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 
 223 static 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 
 228 static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
 229 {
 230         return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS);
 231 }
 232 
 233 static 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 
 269 static 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 
 296 static 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  */
 338 void 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  */
 360 void 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 
 370 struct 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 };

/* [<][>][^][v][top][bottom][index][help] */