Branch data Line data Source code
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 [ + + # # : 91647554 : 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 : 39362908 : 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 : 404 : cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
60 : : {
61 : : struct cpuacct *ca;
62 : :
63 [ - + ]: 404 : if (!parent_css)
64 : : return &root_cpuacct.css;
65 : :
66 : 0 : ca = kzalloc(sizeof(*ca), GFP_KERNEL);
67 [ # # ]: 0 : if (!ca)
68 : : goto out;
69 : :
70 : 0 : ca->cpuusage = alloc_percpu(struct cpuacct_usage);
71 [ # # ]: 0 : if (!ca->cpuusage)
72 : : goto out_free_ca;
73 : :
74 : 0 : ca->cpustat = alloc_percpu(struct kernel_cpustat);
75 [ # # ]: 0 : if (!ca->cpustat)
76 : : goto out_free_cpuusage;
77 : :
78 : 0 : return &ca->css;
79 : :
80 : : out_free_cpuusage:
81 : 0 : free_percpu(ca->cpuusage);
82 : : out_free_ca:
83 : 0 : kfree(ca);
84 : : out:
85 : : return ERR_PTR(-ENOMEM);
86 : : }
87 : :
88 : : /* Destroy an existing CPU accounting group */
89 : 0 : static void cpuacct_css_free(struct cgroup_subsys_state *css)
90 : : {
91 : : struct cpuacct *ca = css_ca(css);
92 : :
93 : 0 : free_percpu(ca->cpustat);
94 : 0 : free_percpu(ca->cpuusage);
95 : 0 : kfree(ca);
96 : 0 : }
97 : :
98 : 0 : static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
99 : : enum cpuacct_stat_index index)
100 : : {
101 : 0 : 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 [ # # ]: 0 : 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 : 0 : raw_spin_lock_irq(&cpu_rq(cpu)->lock);
115 : : #endif
116 : :
117 [ # # ]: 0 : if (index == CPUACCT_STAT_NSTATS) {
118 : : int i = 0;
119 : :
120 : : data = 0;
121 [ # # ]: 0 : for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
122 : 0 : data += cpuusage->usages[i];
123 : : } else {
124 : 0 : data = cpuusage->usages[index];
125 : : }
126 : :
127 : : #ifndef CONFIG_64BIT
128 : 0 : raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
129 : : #endif
130 : :
131 : 0 : return data;
132 : : }
133 : :
134 : 0 : static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
135 : : {
136 : 0 : 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 : 0 : raw_spin_lock_irq(&cpu_rq(cpu)->lock);
144 : : #endif
145 : :
146 [ # # ]: 0 : for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
147 : 0 : cpuusage->usages[i] = val;
148 : :
149 : : #ifndef CONFIG_64BIT
150 : 0 : raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
151 : : #endif
152 : 0 : }
153 : :
154 : : /* Return total CPU usage (in nanoseconds) of a group */
155 : 0 : 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 [ # # ]: 0 : for_each_possible_cpu(i)
163 : 0 : totalcpuusage += cpuacct_cpuusage_read(ca, i, index);
164 : :
165 : 0 : return totalcpuusage;
166 : : }
167 : :
168 : 0 : static u64 cpuusage_user_read(struct cgroup_subsys_state *css,
169 : : struct cftype *cft)
170 : : {
171 : 0 : return __cpuusage_read(css, CPUACCT_STAT_USER);
172 : : }
173 : :
174 : 0 : static u64 cpuusage_sys_read(struct cgroup_subsys_state *css,
175 : : struct cftype *cft)
176 : : {
177 : 0 : return __cpuusage_read(css, CPUACCT_STAT_SYSTEM);
178 : : }
179 : :
180 : 0 : static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
181 : : {
182 : 0 : return __cpuusage_read(css, CPUACCT_STAT_NSTATS);
183 : : }
184 : :
185 : 0 : 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 [ # # ]: 0 : if (val)
195 : : return -EINVAL;
196 : :
197 [ # # ]: 0 : for_each_possible_cpu(cpu)
198 : 0 : cpuacct_cpuusage_write(ca, cpu, 0);
199 : :
200 : : return 0;
201 : : }
202 : :
203 : 0 : 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 [ # # ]: 0 : for_each_possible_cpu(i) {
211 : 0 : percpu = cpuacct_cpuusage_read(ca, i, index);
212 : 0 : seq_printf(m, "%llu ", (unsigned long long) percpu);
213 : : }
214 : 0 : seq_printf(m, "\n");
215 : 0 : return 0;
216 : : }
217 : :
218 : 0 : static int cpuacct_percpu_user_seq_show(struct seq_file *m, void *V)
219 : : {
220 : 0 : return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_USER);
221 : : }
222 : :
223 : 0 : static int cpuacct_percpu_sys_seq_show(struct seq_file *m, void *V)
224 : : {
225 : 0 : return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_SYSTEM);
226 : : }
227 : :
228 : 0 : static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
229 : : {
230 : 0 : return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS);
231 : : }
232 : :
233 : 0 : 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 : 0 : seq_puts(m, "cpu");
240 [ # # ]: 0 : for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
241 : 0 : seq_printf(m, " %s", cpuacct_stat_desc[index]);
242 : 0 : seq_puts(m, "\n");
243 : :
244 [ # # ]: 0 : for_each_possible_cpu(cpu) {
245 : 0 : struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
246 : :
247 : 0 : seq_printf(m, "%d", cpu);
248 : :
249 [ # # ]: 0 : 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 : 0 : raw_spin_lock_irq(&cpu_rq(cpu)->lock);
256 : : #endif
257 : :
258 : 0 : seq_printf(m, " %llu", cpuusage->usages[index]);
259 : :
260 : : #ifndef CONFIG_64BIT
261 : 0 : raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
262 : : #endif
263 : : }
264 : 0 : seq_puts(m, "\n");
265 : : }
266 : 0 : return 0;
267 : : }
268 : :
269 : 0 : 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 : 0 : memset(val, 0, sizeof(val));
277 [ # # ]: 0 : for_each_possible_cpu(cpu) {
278 : 0 : u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
279 : :
280 : 0 : val[CPUACCT_STAT_USER] += cpustat[CPUTIME_USER];
281 : 0 : val[CPUACCT_STAT_USER] += cpustat[CPUTIME_NICE];
282 : 0 : val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SYSTEM];
283 : 0 : val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_IRQ];
284 : 0 : val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SOFTIRQ];
285 : : }
286 : :
287 [ # # ]: 0 : for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) {
288 : 0 : seq_printf(sf, "%s %lld\n",
289 : : cpuacct_stat_desc[stat],
290 : 0 : (long long)nsec_to_clock_t(val[stat]));
291 : : }
292 : :
293 : 0 : 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 : 39525100 : void cpuacct_charge(struct task_struct *tsk, u64 cputime)
339 : : {
340 : : struct cpuacct *ca;
341 : : int index = CPUACCT_STAT_SYSTEM;
342 : 39525100 : struct pt_regs *regs = task_pt_regs(tsk);
343 : :
344 [ + + + + ]: 39525100 : if (regs && user_mode(regs))
345 : : index = CPUACCT_STAT_USER;
346 : :
347 : : rcu_read_lock();
348 : :
349 [ + + ]: 118391984 : for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
350 : 78725816 : this_cpu_ptr(ca->cpuusage)->usages[index] += cputime;
351 : :
352 : : rcu_read_unlock();
353 : 39519092 : }
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 : 12775660 : void cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
361 : : {
362 : : struct cpuacct *ca;
363 : :
364 : : rcu_read_lock();
365 [ - + ]: 25540216 : for (ca = task_ca(tsk); ca != &root_cpuacct; ca = parent_ca(ca))
366 : 0 : this_cpu_ptr(ca->cpustat)->cpustat[index] += val;
367 : : rcu_read_unlock();
368 : 12770382 : }
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 : : };
|