Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /*
0004  * CPU accounting code for task groups.
0005  *
0006  * Based on the work by Paul Menage (menage@google.com) and Balbir Singh
0007  * (balbir@in.ibm.com).
0008  */
0009 
0010 /* Time spent by the tasks of the CPU accounting group executing in ... */
0011 enum cpuacct_stat_index {
0012     CPUACCT_STAT_USER,  /* ... user mode */
0013     CPUACCT_STAT_SYSTEM,    /* ... kernel mode */
0014 
0015     CPUACCT_STAT_NSTATS,
0016 };
0017 
0018 static const char * const cpuacct_stat_desc[] = {
0019     [CPUACCT_STAT_USER] = "user",
0020     [CPUACCT_STAT_SYSTEM] = "system",
0021 };
0022 
0023 /* track CPU usage of a group of tasks and its child groups */
0024 struct cpuacct {
0025     struct cgroup_subsys_state  css;
0026     /* cpuusage holds pointer to a u64-type object on every CPU */
0027     u64 __percpu    *cpuusage;
0028     struct kernel_cpustat __percpu  *cpustat;
0029 };
0030 
0031 static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css)
0032 {
0033     return css ? container_of(css, struct cpuacct, css) : NULL;
0034 }
0035 
0036 /* Return CPU accounting group to which this task belongs */
0037 static inline struct cpuacct *task_ca(struct task_struct *tsk)
0038 {
0039     return css_ca(task_css(tsk, cpuacct_cgrp_id));
0040 }
0041 
0042 static inline struct cpuacct *parent_ca(struct cpuacct *ca)
0043 {
0044     return css_ca(ca->css.parent);
0045 }
0046 
0047 static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage);
0048 static struct cpuacct root_cpuacct = {
0049     .cpustat    = &kernel_cpustat,
0050     .cpuusage   = &root_cpuacct_cpuusage,
0051 };
0052 
0053 /* Create a new CPU accounting group */
0054 static struct cgroup_subsys_state *
0055 cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
0056 {
0057     struct cpuacct *ca;
0058 
0059     if (!parent_css)
0060         return &root_cpuacct.css;
0061 
0062     ca = kzalloc(sizeof(*ca), GFP_KERNEL);
0063     if (!ca)
0064         goto out;
0065 
0066     ca->cpuusage = alloc_percpu(u64);
0067     if (!ca->cpuusage)
0068         goto out_free_ca;
0069 
0070     ca->cpustat = alloc_percpu(struct kernel_cpustat);
0071     if (!ca->cpustat)
0072         goto out_free_cpuusage;
0073 
0074     return &ca->css;
0075 
0076 out_free_cpuusage:
0077     free_percpu(ca->cpuusage);
0078 out_free_ca:
0079     kfree(ca);
0080 out:
0081     return ERR_PTR(-ENOMEM);
0082 }
0083 
0084 /* Destroy an existing CPU accounting group */
0085 static void cpuacct_css_free(struct cgroup_subsys_state *css)
0086 {
0087     struct cpuacct *ca = css_ca(css);
0088 
0089     free_percpu(ca->cpustat);
0090     free_percpu(ca->cpuusage);
0091     kfree(ca);
0092 }
0093 
0094 static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
0095                  enum cpuacct_stat_index index)
0096 {
0097     u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
0098     u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
0099     u64 data;
0100 
0101     /*
0102      * We allow index == CPUACCT_STAT_NSTATS here to read
0103      * the sum of usages.
0104      */
0105     if (WARN_ON_ONCE(index > CPUACCT_STAT_NSTATS))
0106         return 0;
0107 
0108 #ifndef CONFIG_64BIT
0109     /*
0110      * Take rq->lock to make 64-bit read safe on 32-bit platforms.
0111      */
0112     raw_spin_rq_lock_irq(cpu_rq(cpu));
0113 #endif
0114 
0115     switch (index) {
0116     case CPUACCT_STAT_USER:
0117         data = cpustat[CPUTIME_USER] + cpustat[CPUTIME_NICE];
0118         break;
0119     case CPUACCT_STAT_SYSTEM:
0120         data = cpustat[CPUTIME_SYSTEM] + cpustat[CPUTIME_IRQ] +
0121             cpustat[CPUTIME_SOFTIRQ];
0122         break;
0123     case CPUACCT_STAT_NSTATS:
0124         data = *cpuusage;
0125         break;
0126     }
0127 
0128 #ifndef CONFIG_64BIT
0129     raw_spin_rq_unlock_irq(cpu_rq(cpu));
0130 #endif
0131 
0132     return data;
0133 }
0134 
0135 static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu)
0136 {
0137     u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
0138     u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
0139 
0140     /* Don't allow to reset global kernel_cpustat */
0141     if (ca == &root_cpuacct)
0142         return;
0143 
0144 #ifndef CONFIG_64BIT
0145     /*
0146      * Take rq->lock to make 64-bit write safe on 32-bit platforms.
0147      */
0148     raw_spin_rq_lock_irq(cpu_rq(cpu));
0149 #endif
0150     *cpuusage = 0;
0151     cpustat[CPUTIME_USER] = cpustat[CPUTIME_NICE] = 0;
0152     cpustat[CPUTIME_SYSTEM] = cpustat[CPUTIME_IRQ] = 0;
0153     cpustat[CPUTIME_SOFTIRQ] = 0;
0154 
0155 #ifndef CONFIG_64BIT
0156     raw_spin_rq_unlock_irq(cpu_rq(cpu));
0157 #endif
0158 }
0159 
0160 /* Return total CPU usage (in nanoseconds) of a group */
0161 static u64 __cpuusage_read(struct cgroup_subsys_state *css,
0162                enum cpuacct_stat_index index)
0163 {
0164     struct cpuacct *ca = css_ca(css);
0165     u64 totalcpuusage = 0;
0166     int i;
0167 
0168     for_each_possible_cpu(i)
0169         totalcpuusage += cpuacct_cpuusage_read(ca, i, index);
0170 
0171     return totalcpuusage;
0172 }
0173 
0174 static u64 cpuusage_user_read(struct cgroup_subsys_state *css,
0175                   struct cftype *cft)
0176 {
0177     return __cpuusage_read(css, CPUACCT_STAT_USER);
0178 }
0179 
0180 static u64 cpuusage_sys_read(struct cgroup_subsys_state *css,
0181                  struct cftype *cft)
0182 {
0183     return __cpuusage_read(css, CPUACCT_STAT_SYSTEM);
0184 }
0185 
0186 static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
0187 {
0188     return __cpuusage_read(css, CPUACCT_STAT_NSTATS);
0189 }
0190 
0191 static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
0192               u64 val)
0193 {
0194     struct cpuacct *ca = css_ca(css);
0195     int cpu;
0196 
0197     /*
0198      * Only allow '0' here to do a reset.
0199      */
0200     if (val)
0201         return -EINVAL;
0202 
0203     for_each_possible_cpu(cpu)
0204         cpuacct_cpuusage_write(ca, cpu);
0205 
0206     return 0;
0207 }
0208 
0209 static int __cpuacct_percpu_seq_show(struct seq_file *m,
0210                      enum cpuacct_stat_index index)
0211 {
0212     struct cpuacct *ca = css_ca(seq_css(m));
0213     u64 percpu;
0214     int i;
0215 
0216     for_each_possible_cpu(i) {
0217         percpu = cpuacct_cpuusage_read(ca, i, index);
0218         seq_printf(m, "%llu ", (unsigned long long) percpu);
0219     }
0220     seq_printf(m, "\n");
0221     return 0;
0222 }
0223 
0224 static int cpuacct_percpu_user_seq_show(struct seq_file *m, void *V)
0225 {
0226     return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_USER);
0227 }
0228 
0229 static int cpuacct_percpu_sys_seq_show(struct seq_file *m, void *V)
0230 {
0231     return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_SYSTEM);
0232 }
0233 
0234 static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
0235 {
0236     return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS);
0237 }
0238 
0239 static int cpuacct_all_seq_show(struct seq_file *m, void *V)
0240 {
0241     struct cpuacct *ca = css_ca(seq_css(m));
0242     int index;
0243     int cpu;
0244 
0245     seq_puts(m, "cpu");
0246     for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
0247         seq_printf(m, " %s", cpuacct_stat_desc[index]);
0248     seq_puts(m, "\n");
0249 
0250     for_each_possible_cpu(cpu) {
0251         seq_printf(m, "%d", cpu);
0252         for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
0253             seq_printf(m, " %llu",
0254                    cpuacct_cpuusage_read(ca, cpu, index));
0255         seq_puts(m, "\n");
0256     }
0257     return 0;
0258 }
0259 
0260 static int cpuacct_stats_show(struct seq_file *sf, void *v)
0261 {
0262     struct cpuacct *ca = css_ca(seq_css(sf));
0263     struct task_cputime cputime;
0264     u64 val[CPUACCT_STAT_NSTATS];
0265     int cpu;
0266     int stat;
0267 
0268     memset(&cputime, 0, sizeof(cputime));
0269     for_each_possible_cpu(cpu) {
0270         u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
0271 
0272         cputime.utime += cpustat[CPUTIME_USER];
0273         cputime.utime += cpustat[CPUTIME_NICE];
0274         cputime.stime += cpustat[CPUTIME_SYSTEM];
0275         cputime.stime += cpustat[CPUTIME_IRQ];
0276         cputime.stime += cpustat[CPUTIME_SOFTIRQ];
0277 
0278         cputime.sum_exec_runtime += *per_cpu_ptr(ca->cpuusage, cpu);
0279     }
0280 
0281     cputime_adjust(&cputime, &seq_css(sf)->cgroup->prev_cputime,
0282         &val[CPUACCT_STAT_USER], &val[CPUACCT_STAT_SYSTEM]);
0283 
0284     for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) {
0285         seq_printf(sf, "%s %llu\n", cpuacct_stat_desc[stat],
0286             nsec_to_clock_t(val[stat]));
0287     }
0288 
0289     return 0;
0290 }
0291 
0292 static struct cftype files[] = {
0293     {
0294         .name = "usage",
0295         .read_u64 = cpuusage_read,
0296         .write_u64 = cpuusage_write,
0297     },
0298     {
0299         .name = "usage_user",
0300         .read_u64 = cpuusage_user_read,
0301     },
0302     {
0303         .name = "usage_sys",
0304         .read_u64 = cpuusage_sys_read,
0305     },
0306     {
0307         .name = "usage_percpu",
0308         .seq_show = cpuacct_percpu_seq_show,
0309     },
0310     {
0311         .name = "usage_percpu_user",
0312         .seq_show = cpuacct_percpu_user_seq_show,
0313     },
0314     {
0315         .name = "usage_percpu_sys",
0316         .seq_show = cpuacct_percpu_sys_seq_show,
0317     },
0318     {
0319         .name = "usage_all",
0320         .seq_show = cpuacct_all_seq_show,
0321     },
0322     {
0323         .name = "stat",
0324         .seq_show = cpuacct_stats_show,
0325     },
0326     { } /* terminate */
0327 };
0328 
0329 /*
0330  * charge this task's execution time to its accounting group.
0331  *
0332  * called with rq->lock held.
0333  */
0334 void cpuacct_charge(struct task_struct *tsk, u64 cputime)
0335 {
0336     unsigned int cpu = task_cpu(tsk);
0337     struct cpuacct *ca;
0338 
0339     lockdep_assert_rq_held(cpu_rq(cpu));
0340 
0341     for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
0342         *per_cpu_ptr(ca->cpuusage, cpu) += cputime;
0343 }
0344 
0345 /*
0346  * Add user/system time to cpuacct.
0347  *
0348  * Note: it's the caller that updates the account of the root cgroup.
0349  */
0350 void cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
0351 {
0352     struct cpuacct *ca;
0353 
0354     for (ca = task_ca(tsk); ca != &root_cpuacct; ca = parent_ca(ca))
0355         __this_cpu_add(ca->cpustat->cpustat[index], val);
0356 }
0357 
0358 struct cgroup_subsys cpuacct_cgrp_subsys = {
0359     .css_alloc  = cpuacct_css_alloc,
0360     .css_free   = cpuacct_css_free,
0361     .legacy_cftypes = files,
0362     .early_init = true,
0363 };