blob: 893eece65bfdac52f89ec782b8cfb99be836239e [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Li Zefan2e76c242013-03-29 14:36:31 +08002/*
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 */
Muchun Songdbe93372020-04-20 15:04:53 +08008#include <asm/irq_regs.h>
Ingo Molnar325ea102018-03-03 12:20:47 +01009#include "sched.h"
Li Zefan2e76c242013-03-29 14:36:31 +080010
Ingo Molnar97fb7a02018-03-03 14:01:12 +010011/* Time spent by the tasks of the CPU accounting group executing in ... */
Li Zefand1712792013-03-29 14:38:13 +080012enum cpuacct_stat_index {
13 CPUACCT_STAT_USER, /* ... user mode */
14 CPUACCT_STAT_SYSTEM, /* ... kernel mode */
15
16 CPUACCT_STAT_NSTATS,
17};
18
Zhao Lei9acacc22016-06-20 17:37:18 +080019static const char * const cpuacct_stat_desc[] = {
20 [CPUACCT_STAT_USER] = "user",
21 [CPUACCT_STAT_SYSTEM] = "system",
Dongsheng Yangd7400372016-03-22 16:37:08 +080022};
23
24struct cpuacct_usage {
Zhao Lei9acacc22016-06-20 17:37:18 +080025 u64 usages[CPUACCT_STAT_NSTATS];
Dongsheng Yangd7400372016-03-22 16:37:08 +080026};
27
Ingo Molnar97fb7a02018-03-03 14:01:12 +010028/* track CPU usage of a group of tasks and its child groups */
Li Zefand1712792013-03-29 14:38:13 +080029struct cpuacct {
Ingo Molnar97fb7a02018-03-03 14:01:12 +010030 struct cgroup_subsys_state css;
31 /* cpuusage holds pointer to a u64-type object on every CPU */
32 struct cpuacct_usage __percpu *cpuusage;
33 struct kernel_cpustat __percpu *cpustat;
Li Zefand1712792013-03-29 14:38:13 +080034};
35
Tejun Heoa7c6d552013-08-08 20:11:23 -040036static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css)
37{
38 return css ? container_of(css, struct cpuacct, css) : NULL;
39}
40
Ingo Molnar97fb7a02018-03-03 14:01:12 +010041/* Return CPU accounting group to which this task belongs */
Li Zefand1712792013-03-29 14:38:13 +080042static inline struct cpuacct *task_ca(struct task_struct *tsk)
43{
Tejun Heo073219e2014-02-08 10:36:58 -050044 return css_ca(task_css(tsk, cpuacct_cgrp_id));
Li Zefand1712792013-03-29 14:38:13 +080045}
46
Li Zefand1712792013-03-29 14:38:13 +080047static inline struct cpuacct *parent_ca(struct cpuacct *ca)
48{
Tejun Heo5c9d5352014-05-16 13:22:48 -040049 return css_ca(ca->css.parent);
Li Zefand1712792013-03-29 14:38:13 +080050}
51
Dongsheng Yangd7400372016-03-22 16:37:08 +080052static DEFINE_PER_CPU(struct cpuacct_usage, root_cpuacct_cpuusage);
Li Zefan14c6d3c2013-03-29 14:44:04 +080053static struct cpuacct root_cpuacct = {
54 .cpustat = &kernel_cpustat,
55 .cpuusage = &root_cpuacct_cpuusage,
56};
Li Zefan2e76c242013-03-29 14:36:31 +080057
Ingo Molnar97fb7a02018-03-03 14:01:12 +010058/* Create a new CPU accounting group */
Tejun Heoeb954192013-08-08 20:11:23 -040059static struct cgroup_subsys_state *
60cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
Li Zefan2e76c242013-03-29 14:36:31 +080061{
62 struct cpuacct *ca;
63
Tejun Heoeb954192013-08-08 20:11:23 -040064 if (!parent_css)
Li Zefan2e76c242013-03-29 14:36:31 +080065 return &root_cpuacct.css;
66
67 ca = kzalloc(sizeof(*ca), GFP_KERNEL);
68 if (!ca)
69 goto out;
70
Dongsheng Yangd7400372016-03-22 16:37:08 +080071 ca->cpuusage = alloc_percpu(struct cpuacct_usage);
Li Zefan2e76c242013-03-29 14:36:31 +080072 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
Ingo Molnar97fb7a02018-03-03 14:01:12 +010089/* Destroy an existing CPU accounting group */
Tejun Heoeb954192013-08-08 20:11:23 -040090static void cpuacct_css_free(struct cgroup_subsys_state *css)
Li Zefan2e76c242013-03-29 14:36:31 +080091{
Tejun Heoeb954192013-08-08 20:11:23 -040092 struct cpuacct *ca = css_ca(css);
Li Zefan2e76c242013-03-29 14:36:31 +080093
94 free_percpu(ca->cpustat);
95 free_percpu(ca->cpuusage);
96 kfree(ca);
97}
98
Dongsheng Yangd7400372016-03-22 16:37:08 +080099static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
Zhao Lei9acacc22016-06-20 17:37:18 +0800100 enum cpuacct_stat_index index)
Li Zefan2e76c242013-03-29 14:36:31 +0800101{
Dongsheng Yangd7400372016-03-22 16:37:08 +0800102 struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
Li Zefan2e76c242013-03-29 14:36:31 +0800103 u64 data;
104
Dongsheng Yangd7400372016-03-22 16:37:08 +0800105 /*
Zhao Lei9acacc22016-06-20 17:37:18 +0800106 * We allow index == CPUACCT_STAT_NSTATS here to read
Ingo Molnar3b037062021-03-18 13:38:50 +0100107 * the sum of usages.
Dongsheng Yangd7400372016-03-22 16:37:08 +0800108 */
Zhao Lei9acacc22016-06-20 17:37:18 +0800109 BUG_ON(index > CPUACCT_STAT_NSTATS);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800110
Li Zefan2e76c242013-03-29 14:36:31 +0800111#ifndef CONFIG_64BIT
112 /*
113 * Take rq->lock to make 64-bit read safe on 32-bit platforms.
114 */
Peter Zijlstra5cb9eaa2020-11-17 18:19:31 -0500115 raw_spin_rq_lock_irq(cpu_rq(cpu));
Dongsheng Yangd7400372016-03-22 16:37:08 +0800116#endif
117
Zhao Lei9acacc22016-06-20 17:37:18 +0800118 if (index == CPUACCT_STAT_NSTATS) {
Dongsheng Yangd7400372016-03-22 16:37:08 +0800119 int i = 0;
120
121 data = 0;
Zhao Lei9acacc22016-06-20 17:37:18 +0800122 for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
Dongsheng Yangd7400372016-03-22 16:37:08 +0800123 data += cpuusage->usages[i];
124 } else {
125 data = cpuusage->usages[index];
126 }
127
128#ifndef CONFIG_64BIT
Peter Zijlstra5cb9eaa2020-11-17 18:19:31 -0500129 raw_spin_rq_unlock_irq(cpu_rq(cpu));
Li Zefan2e76c242013-03-29 14:36:31 +0800130#endif
131
132 return data;
133}
134
135static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
136{
Dongsheng Yangd7400372016-03-22 16:37:08 +0800137 struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
138 int i;
Li Zefan2e76c242013-03-29 14:36:31 +0800139
140#ifndef CONFIG_64BIT
141 /*
142 * Take rq->lock to make 64-bit write safe on 32-bit platforms.
143 */
Peter Zijlstra5cb9eaa2020-11-17 18:19:31 -0500144 raw_spin_rq_lock_irq(cpu_rq(cpu));
Dongsheng Yangd7400372016-03-22 16:37:08 +0800145#endif
146
Zhao Lei9acacc22016-06-20 17:37:18 +0800147 for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
Dongsheng Yangd7400372016-03-22 16:37:08 +0800148 cpuusage->usages[i] = val;
149
150#ifndef CONFIG_64BIT
Peter Zijlstra5cb9eaa2020-11-17 18:19:31 -0500151 raw_spin_rq_unlock_irq(cpu_rq(cpu));
Li Zefan2e76c242013-03-29 14:36:31 +0800152#endif
153}
154
Ingo Molnar97fb7a02018-03-03 14:01:12 +0100155/* Return total CPU usage (in nanoseconds) of a group */
Dongsheng Yangd7400372016-03-22 16:37:08 +0800156static u64 __cpuusage_read(struct cgroup_subsys_state *css,
Zhao Lei9acacc22016-06-20 17:37:18 +0800157 enum cpuacct_stat_index index)
Li Zefan2e76c242013-03-29 14:36:31 +0800158{
Tejun Heo182446d2013-08-08 20:11:24 -0400159 struct cpuacct *ca = css_ca(css);
Li Zefan2e76c242013-03-29 14:36:31 +0800160 u64 totalcpuusage = 0;
161 int i;
162
Zhao Lei5ca37262016-03-22 16:37:07 +0800163 for_each_possible_cpu(i)
Dongsheng Yangd7400372016-03-22 16:37:08 +0800164 totalcpuusage += cpuacct_cpuusage_read(ca, i, index);
Li Zefan2e76c242013-03-29 14:36:31 +0800165
166 return totalcpuusage;
167}
168
Dongsheng Yangd7400372016-03-22 16:37:08 +0800169static u64 cpuusage_user_read(struct cgroup_subsys_state *css,
170 struct cftype *cft)
171{
Zhao Lei9acacc22016-06-20 17:37:18 +0800172 return __cpuusage_read(css, CPUACCT_STAT_USER);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800173}
174
175static u64 cpuusage_sys_read(struct cgroup_subsys_state *css,
176 struct cftype *cft)
177{
Zhao Lei9acacc22016-06-20 17:37:18 +0800178 return __cpuusage_read(css, CPUACCT_STAT_SYSTEM);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800179}
180
181static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
182{
Zhao Lei9acacc22016-06-20 17:37:18 +0800183 return __cpuusage_read(css, CPUACCT_STAT_NSTATS);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800184}
185
Tejun Heo182446d2013-08-08 20:11:24 -0400186static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
Dongsheng Yang1a736b72015-12-21 19:14:42 +0800187 u64 val)
Li Zefan2e76c242013-03-29 14:36:31 +0800188{
Tejun Heo182446d2013-08-08 20:11:24 -0400189 struct cpuacct *ca = css_ca(css);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800190 int cpu;
Li Zefan2e76c242013-03-29 14:36:31 +0800191
Dongsheng Yang1a736b72015-12-21 19:14:42 +0800192 /*
193 * Only allow '0' here to do a reset.
194 */
Dongsheng Yangd7400372016-03-22 16:37:08 +0800195 if (val)
196 return -EINVAL;
Li Zefan2e76c242013-03-29 14:36:31 +0800197
Dongsheng Yangd7400372016-03-22 16:37:08 +0800198 for_each_possible_cpu(cpu)
199 cpuacct_cpuusage_write(ca, cpu, 0);
Li Zefan2e76c242013-03-29 14:36:31 +0800200
Dongsheng Yangd7400372016-03-22 16:37:08 +0800201 return 0;
Li Zefan2e76c242013-03-29 14:36:31 +0800202}
203
Dongsheng Yangd7400372016-03-22 16:37:08 +0800204static int __cpuacct_percpu_seq_show(struct seq_file *m,
Zhao Lei9acacc22016-06-20 17:37:18 +0800205 enum cpuacct_stat_index index)
Li Zefan2e76c242013-03-29 14:36:31 +0800206{
Tejun Heo2da8ca82013-12-05 12:28:04 -0500207 struct cpuacct *ca = css_ca(seq_css(m));
Li Zefan2e76c242013-03-29 14:36:31 +0800208 u64 percpu;
209 int i;
210
Zhao Lei5ca37262016-03-22 16:37:07 +0800211 for_each_possible_cpu(i) {
Dongsheng Yangd7400372016-03-22 16:37:08 +0800212 percpu = cpuacct_cpuusage_read(ca, i, index);
Li Zefan2e76c242013-03-29 14:36:31 +0800213 seq_printf(m, "%llu ", (unsigned long long) percpu);
214 }
215 seq_printf(m, "\n");
216 return 0;
217}
218
Dongsheng Yangd7400372016-03-22 16:37:08 +0800219static int cpuacct_percpu_user_seq_show(struct seq_file *m, void *V)
220{
Zhao Lei9acacc22016-06-20 17:37:18 +0800221 return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_USER);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800222}
223
224static int cpuacct_percpu_sys_seq_show(struct seq_file *m, void *V)
225{
Zhao Lei9acacc22016-06-20 17:37:18 +0800226 return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_SYSTEM);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800227}
228
229static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
230{
Zhao Lei9acacc22016-06-20 17:37:18 +0800231 return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800232}
233
Zhao Lei277a13e2016-06-20 17:37:20 +0800234static int cpuacct_all_seq_show(struct seq_file *m, void *V)
235{
236 struct cpuacct *ca = css_ca(seq_css(m));
237 int index;
238 int cpu;
239
240 seq_puts(m, "cpu");
241 for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
242 seq_printf(m, " %s", cpuacct_stat_desc[index]);
243 seq_puts(m, "\n");
244
245 for_each_possible_cpu(cpu) {
246 struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
247
248 seq_printf(m, "%d", cpu);
249
250 for (index = 0; index < CPUACCT_STAT_NSTATS; index++) {
251#ifndef CONFIG_64BIT
252 /*
253 * Take rq->lock to make 64-bit read safe on 32-bit
254 * platforms.
255 */
Peter Zijlstra5cb9eaa2020-11-17 18:19:31 -0500256 raw_spin_rq_lock_irq(cpu_rq(cpu));
Zhao Lei277a13e2016-06-20 17:37:20 +0800257#endif
258
259 seq_printf(m, " %llu", cpuusage->usages[index]);
260
261#ifndef CONFIG_64BIT
Peter Zijlstra5cb9eaa2020-11-17 18:19:31 -0500262 raw_spin_rq_unlock_irq(cpu_rq(cpu));
Zhao Lei277a13e2016-06-20 17:37:20 +0800263#endif
264 }
265 seq_puts(m, "\n");
266 }
267 return 0;
268}
269
Tejun Heo2da8ca82013-12-05 12:28:04 -0500270static int cpuacct_stats_show(struct seq_file *sf, void *v)
Li Zefan2e76c242013-03-29 14:36:31 +0800271{
Tejun Heo2da8ca82013-12-05 12:28:04 -0500272 struct cpuacct *ca = css_ca(seq_css(sf));
Zhao Lei8e546bf2016-06-20 17:37:19 +0800273 s64 val[CPUACCT_STAT_NSTATS];
Li Zefan2e76c242013-03-29 14:36:31 +0800274 int cpu;
Zhao Lei8e546bf2016-06-20 17:37:19 +0800275 int stat;
Li Zefan2e76c242013-03-29 14:36:31 +0800276
Zhao Lei8e546bf2016-06-20 17:37:19 +0800277 memset(val, 0, sizeof(val));
Zhao Lei5ca37262016-03-22 16:37:07 +0800278 for_each_possible_cpu(cpu) {
Zhao Lei8e546bf2016-06-20 17:37:19 +0800279 u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
Li Zefan2e76c242013-03-29 14:36:31 +0800280
Zhao Lei8e546bf2016-06-20 17:37:19 +0800281 val[CPUACCT_STAT_USER] += cpustat[CPUTIME_USER];
282 val[CPUACCT_STAT_USER] += cpustat[CPUTIME_NICE];
283 val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SYSTEM];
284 val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_IRQ];
285 val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SOFTIRQ];
Li Zefan2e76c242013-03-29 14:36:31 +0800286 }
287
Zhao Lei8e546bf2016-06-20 17:37:19 +0800288 for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) {
289 seq_printf(sf, "%s %lld\n",
290 cpuacct_stat_desc[stat],
Frederic Weisbecker7fb13272017-01-31 04:09:19 +0100291 (long long)nsec_to_clock_t(val[stat]));
Zhao Lei8e546bf2016-06-20 17:37:19 +0800292 }
Li Zefan2e76c242013-03-29 14:36:31 +0800293
294 return 0;
295}
296
297static struct cftype files[] = {
298 {
299 .name = "usage",
300 .read_u64 = cpuusage_read,
301 .write_u64 = cpuusage_write,
302 },
303 {
Dongsheng Yangd7400372016-03-22 16:37:08 +0800304 .name = "usage_user",
305 .read_u64 = cpuusage_user_read,
306 },
307 {
308 .name = "usage_sys",
309 .read_u64 = cpuusage_sys_read,
310 },
311 {
Li Zefan2e76c242013-03-29 14:36:31 +0800312 .name = "usage_percpu",
Tejun Heo2da8ca82013-12-05 12:28:04 -0500313 .seq_show = cpuacct_percpu_seq_show,
Li Zefan2e76c242013-03-29 14:36:31 +0800314 },
315 {
Dongsheng Yangd7400372016-03-22 16:37:08 +0800316 .name = "usage_percpu_user",
317 .seq_show = cpuacct_percpu_user_seq_show,
318 },
319 {
320 .name = "usage_percpu_sys",
321 .seq_show = cpuacct_percpu_sys_seq_show,
322 },
323 {
Zhao Lei277a13e2016-06-20 17:37:20 +0800324 .name = "usage_all",
325 .seq_show = cpuacct_all_seq_show,
326 },
327 {
Li Zefan2e76c242013-03-29 14:36:31 +0800328 .name = "stat",
Tejun Heo2da8ca82013-12-05 12:28:04 -0500329 .seq_show = cpuacct_stats_show,
Li Zefan2e76c242013-03-29 14:36:31 +0800330 },
331 { } /* terminate */
332};
333
334/*
335 * charge this task's execution time to its accounting group.
336 *
337 * called with rq->lock held.
338 */
339void cpuacct_charge(struct task_struct *tsk, u64 cputime)
340{
341 struct cpuacct *ca;
Zhao Lei9acacc22016-06-20 17:37:18 +0800342 int index = CPUACCT_STAT_SYSTEM;
Muchun Songdbe93372020-04-20 15:04:53 +0800343 struct pt_regs *regs = get_irq_regs() ? : task_pt_regs(tsk);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800344
Anton Blanchardbd928832016-04-06 21:59:50 +1000345 if (regs && user_mode(regs))
Zhao Lei9acacc22016-06-20 17:37:18 +0800346 index = CPUACCT_STAT_USER;
Li Zefan2e76c242013-03-29 14:36:31 +0800347
348 rcu_read_lock();
Dongsheng Yangd7400372016-03-22 16:37:08 +0800349
Zhao Lei73e6aaf2016-03-17 12:19:43 +0800350 for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
Muchun Song12aa2582020-05-07 11:10:39 +0800351 __this_cpu_add(ca->cpuusage->usages[index], cputime);
Dongsheng Yangd7400372016-03-22 16:37:08 +0800352
Li Zefan2e76c242013-03-29 14:36:31 +0800353 rcu_read_unlock();
354}
355
Li Zefan1966aaf2013-03-29 14:37:06 +0800356/*
357 * Add user/system time to cpuacct.
358 *
359 * Note: it's the caller that updates the account of the root cgroup.
360 */
Zhao Lei73e6aaf2016-03-17 12:19:43 +0800361void cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
Li Zefan1966aaf2013-03-29 14:37:06 +0800362{
Li Zefan1966aaf2013-03-29 14:37:06 +0800363 struct cpuacct *ca;
364
Li Zefan1966aaf2013-03-29 14:37:06 +0800365 rcu_read_lock();
Zhao Lei73e6aaf2016-03-17 12:19:43 +0800366 for (ca = task_ca(tsk); ca != &root_cpuacct; ca = parent_ca(ca))
Muchun Song12aa2582020-05-07 11:10:39 +0800367 __this_cpu_add(ca->cpustat->cpustat[index], val);
Li Zefan1966aaf2013-03-29 14:37:06 +0800368 rcu_read_unlock();
369}
370
Tejun Heo073219e2014-02-08 10:36:58 -0500371struct cgroup_subsys cpuacct_cgrp_subsys = {
Li Zefan621e2de2013-03-29 14:44:15 +0800372 .css_alloc = cpuacct_css_alloc,
373 .css_free = cpuacct_css_free,
Tejun Heo55779642014-07-15 11:05:09 -0400374 .legacy_cftypes = files,
Tejun Heob38e42e2016-02-23 10:00:50 -0500375 .early_init = true,
Li Zefan2e76c242013-03-29 14:36:31 +0800376};