Blame view

kernel/cgroup/rstat.c 11.8 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
041cd640b   Tejun Heo   cgroup: Implement...
2
3
4
  #include "cgroup-internal.h"
  
  #include <linux/sched/cputime.h>
0fa294fb1   Tejun Heo   cgroup: Replace c...
5
  static DEFINE_SPINLOCK(cgroup_rstat_lock);
c58632b36   Tejun Heo   cgroup: Rename st...
6
  static DEFINE_PER_CPU(raw_spinlock_t, cgroup_rstat_cpu_lock);
041cd640b   Tejun Heo   cgroup: Implement...
7

a17556f8d   Tejun Heo   cgroup: Reorganiz...
8
  static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu);
c58632b36   Tejun Heo   cgroup: Rename st...
9
  static struct cgroup_rstat_cpu *cgroup_rstat_cpu(struct cgroup *cgrp, int cpu)
041cd640b   Tejun Heo   cgroup: Implement...
10
  {
c58632b36   Tejun Heo   cgroup: Rename st...
11
  	return per_cpu_ptr(cgrp->rstat_cpu, cpu);
041cd640b   Tejun Heo   cgroup: Implement...
12
13
14
  }
  
  /**
6162cef0f   Tejun Heo   cgroup: Factor ou...
15
   * cgroup_rstat_updated - keep track of updated rstat_cpu
041cd640b   Tejun Heo   cgroup: Implement...
16
   * @cgrp: target cgroup
c58632b36   Tejun Heo   cgroup: Rename st...
17
   * @cpu: cpu on which rstat_cpu was updated
041cd640b   Tejun Heo   cgroup: Implement...
18
   *
c58632b36   Tejun Heo   cgroup: Rename st...
19
20
21
   * @cgrp's rstat_cpu on @cpu was updated.  Put it on the parent's matching
   * rstat_cpu->updated_children list.  See the comment on top of
   * cgroup_rstat_cpu definition for details.
041cd640b   Tejun Heo   cgroup: Implement...
22
   */
6162cef0f   Tejun Heo   cgroup: Factor ou...
23
  void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
041cd640b   Tejun Heo   cgroup: Implement...
24
  {
c58632b36   Tejun Heo   cgroup: Rename st...
25
  	raw_spinlock_t *cpu_lock = per_cpu_ptr(&cgroup_rstat_cpu_lock, cpu);
041cd640b   Tejun Heo   cgroup: Implement...
26
27
  	struct cgroup *parent;
  	unsigned long flags;
c43c5ea75   Tejun Heo   cgroup: Make cgro...
28
29
30
  	/* nothing to do for root */
  	if (!cgroup_parent(cgrp))
  		return;
041cd640b   Tejun Heo   cgroup: Implement...
31
  	/*
d8ef4b38c   Tejun Heo   Revert "cgroup: A...
32
33
34
  	 * Speculative already-on-list test. This may race leading to
  	 * temporary inaccuracies, which is fine.
  	 *
041cd640b   Tejun Heo   cgroup: Implement...
35
36
37
38
  	 * Because @parent's updated_children is terminated with @parent
  	 * instead of NULL, we can tell whether @cgrp is on the list by
  	 * testing the next pointer for NULL.
  	 */
c58632b36   Tejun Heo   cgroup: Rename st...
39
  	if (cgroup_rstat_cpu(cgrp, cpu)->updated_next)
041cd640b   Tejun Heo   cgroup: Implement...
40
41
42
43
44
45
46
  		return;
  
  	raw_spin_lock_irqsave(cpu_lock, flags);
  
  	/* put @cgrp and all ancestors on the corresponding updated lists */
  	for (parent = cgroup_parent(cgrp); parent;
  	     cgrp = parent, parent = cgroup_parent(cgrp)) {
c58632b36   Tejun Heo   cgroup: Rename st...
47
48
  		struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
  		struct cgroup_rstat_cpu *prstatc = cgroup_rstat_cpu(parent, cpu);
041cd640b   Tejun Heo   cgroup: Implement...
49
50
51
52
53
  
  		/*
  		 * Both additions and removals are bottom-up.  If a cgroup
  		 * is already in the tree, all ancestors are.
  		 */
c58632b36   Tejun Heo   cgroup: Rename st...
54
  		if (rstatc->updated_next)
041cd640b   Tejun Heo   cgroup: Implement...
55
  			break;
c58632b36   Tejun Heo   cgroup: Rename st...
56
57
  		rstatc->updated_next = prstatc->updated_children;
  		prstatc->updated_children = cgrp;
041cd640b   Tejun Heo   cgroup: Implement...
58
59
60
61
62
63
  	}
  
  	raw_spin_unlock_irqrestore(cpu_lock, flags);
  }
  
  /**
c58632b36   Tejun Heo   cgroup: Rename st...
64
   * cgroup_rstat_cpu_pop_updated - iterate and dismantle rstat_cpu updated tree
041cd640b   Tejun Heo   cgroup: Implement...
65
66
67
68
   * @pos: current position
   * @root: root of the tree to traversal
   * @cpu: target cpu
   *
c58632b36   Tejun Heo   cgroup: Rename st...
69
   * Walks the udpated rstat_cpu tree on @cpu from @root.  %NULL @pos starts
041cd640b   Tejun Heo   cgroup: Implement...
70
71
   * the traversal and %NULL return indicates the end.  During traversal,
   * each returned cgroup is unlinked from the tree.  Must be called with the
c58632b36   Tejun Heo   cgroup: Rename st...
72
   * matching cgroup_rstat_cpu_lock held.
041cd640b   Tejun Heo   cgroup: Implement...
73
74
75
76
77
   *
   * The only ordering guarantee is that, for a parent and a child pair
   * covered by a given traversal, if a child is visited, its parent is
   * guaranteed to be visited afterwards.
   */
c58632b36   Tejun Heo   cgroup: Rename st...
78
79
  static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos,
  						   struct cgroup *root, int cpu)
041cd640b   Tejun Heo   cgroup: Implement...
80
  {
c58632b36   Tejun Heo   cgroup: Rename st...
81
  	struct cgroup_rstat_cpu *rstatc;
041cd640b   Tejun Heo   cgroup: Implement...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  
  	if (pos == root)
  		return NULL;
  
  	/*
  	 * We're gonna walk down to the first leaf and visit/remove it.  We
  	 * can pick whatever unvisited node as the starting point.
  	 */
  	if (!pos)
  		pos = root;
  	else
  		pos = cgroup_parent(pos);
  
  	/* walk down to the first leaf */
  	while (true) {
c58632b36   Tejun Heo   cgroup: Rename st...
97
98
  		rstatc = cgroup_rstat_cpu(pos, cpu);
  		if (rstatc->updated_children == pos)
041cd640b   Tejun Heo   cgroup: Implement...
99
  			break;
c58632b36   Tejun Heo   cgroup: Rename st...
100
  		pos = rstatc->updated_children;
041cd640b   Tejun Heo   cgroup: Implement...
101
102
103
104
105
106
107
108
  	}
  
  	/*
  	 * Unlink @pos from the tree.  As the updated_children list is
  	 * singly linked, we have to walk it to find the removal point.
  	 * However, due to the way we traverse, @pos will be the first
  	 * child in most cases. The only exception is @root.
  	 */
b4ff1b44b   Tejun Heo   cgroup, rstat: Do...
109
110
  	if (rstatc->updated_next) {
  		struct cgroup *parent = cgroup_parent(pos);
c58632b36   Tejun Heo   cgroup: Rename st...
111
112
  		struct cgroup_rstat_cpu *prstatc = cgroup_rstat_cpu(parent, cpu);
  		struct cgroup_rstat_cpu *nrstatc;
041cd640b   Tejun Heo   cgroup: Implement...
113
  		struct cgroup **nextp;
c58632b36   Tejun Heo   cgroup: Rename st...
114
  		nextp = &prstatc->updated_children;
041cd640b   Tejun Heo   cgroup: Implement...
115
  		while (true) {
c58632b36   Tejun Heo   cgroup: Rename st...
116
  			nrstatc = cgroup_rstat_cpu(*nextp, cpu);
041cd640b   Tejun Heo   cgroup: Implement...
117
118
119
120
  			if (*nextp == pos)
  				break;
  
  			WARN_ON_ONCE(*nextp == parent);
c58632b36   Tejun Heo   cgroup: Rename st...
121
  			nextp = &nrstatc->updated_next;
041cd640b   Tejun Heo   cgroup: Implement...
122
  		}
c58632b36   Tejun Heo   cgroup: Rename st...
123
124
  		*nextp = rstatc->updated_next;
  		rstatc->updated_next = NULL;
9a9e97b2f   Tejun Heo   cgroup: Add memor...
125

b4ff1b44b   Tejun Heo   cgroup, rstat: Do...
126
  		return pos;
041cd640b   Tejun Heo   cgroup: Implement...
127
  	}
b4ff1b44b   Tejun Heo   cgroup, rstat: Do...
128
129
  	/* only happens for @root */
  	return NULL;
041cd640b   Tejun Heo   cgroup: Implement...
130
  }
a17556f8d   Tejun Heo   cgroup: Reorganiz...
131
  /* see cgroup_rstat_flush() */
0fa294fb1   Tejun Heo   cgroup: Replace c...
132
133
  static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep)
  	__releases(&cgroup_rstat_lock) __acquires(&cgroup_rstat_lock)
a17556f8d   Tejun Heo   cgroup: Reorganiz...
134
135
  {
  	int cpu;
0fa294fb1   Tejun Heo   cgroup: Replace c...
136
  	lockdep_assert_held(&cgroup_rstat_lock);
a17556f8d   Tejun Heo   cgroup: Reorganiz...
137
138
139
140
141
  
  	for_each_possible_cpu(cpu) {
  		raw_spinlock_t *cpu_lock = per_cpu_ptr(&cgroup_rstat_cpu_lock,
  						       cpu);
  		struct cgroup *pos = NULL;
0fa294fb1   Tejun Heo   cgroup: Replace c...
142
  		raw_spin_lock(cpu_lock);
8f53470ba   Tejun Heo   cgroup: Add cgrou...
143
144
  		while ((pos = cgroup_rstat_cpu_pop_updated(pos, cgrp, cpu))) {
  			struct cgroup_subsys_state *css;
a17556f8d   Tejun Heo   cgroup: Reorganiz...
145
  			cgroup_base_stat_flush(pos, cpu);
8f53470ba   Tejun Heo   cgroup: Add cgrou...
146
147
148
149
150
151
152
  
  			rcu_read_lock();
  			list_for_each_entry_rcu(css, &pos->rstat_css_list,
  						rstat_css_node)
  				css->ss->css_rstat_flush(css, cpu);
  			rcu_read_unlock();
  		}
0fa294fb1   Tejun Heo   cgroup: Replace c...
153
154
155
156
157
158
159
160
161
162
  		raw_spin_unlock(cpu_lock);
  
  		/* if @may_sleep, play nice and yield if necessary */
  		if (may_sleep && (need_resched() ||
  				  spin_needbreak(&cgroup_rstat_lock))) {
  			spin_unlock_irq(&cgroup_rstat_lock);
  			if (!cond_resched())
  				cpu_relax();
  			spin_lock_irq(&cgroup_rstat_lock);
  		}
a17556f8d   Tejun Heo   cgroup: Reorganiz...
163
164
165
166
167
168
169
170
171
172
173
174
175
  	}
  }
  
  /**
   * cgroup_rstat_flush - flush stats in @cgrp's subtree
   * @cgrp: target cgroup
   *
   * Collect all per-cpu stats in @cgrp's subtree into the global counters
   * and propagate them upwards.  After this function returns, all cgroups in
   * the subtree have up-to-date ->stat.
   *
   * This also gets all cgroups in the subtree including @cgrp off the
   * ->updated_children lists.
0fa294fb1   Tejun Heo   cgroup: Replace c...
176
177
   *
   * This function may block.
a17556f8d   Tejun Heo   cgroup: Reorganiz...
178
179
180
   */
  void cgroup_rstat_flush(struct cgroup *cgrp)
  {
0fa294fb1   Tejun Heo   cgroup: Replace c...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  	might_sleep();
  
  	spin_lock_irq(&cgroup_rstat_lock);
  	cgroup_rstat_flush_locked(cgrp, true);
  	spin_unlock_irq(&cgroup_rstat_lock);
  }
  
  /**
   * cgroup_rstat_flush_irqsafe - irqsafe version of cgroup_rstat_flush()
   * @cgrp: target cgroup
   *
   * This function can be called from any context.
   */
  void cgroup_rstat_flush_irqsafe(struct cgroup *cgrp)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&cgroup_rstat_lock, flags);
  	cgroup_rstat_flush_locked(cgrp, false);
  	spin_unlock_irqrestore(&cgroup_rstat_lock, flags);
a17556f8d   Tejun Heo   cgroup: Reorganiz...
201
  }
6162cef0f   Tejun Heo   cgroup: Factor ou...
202
203
204
205
206
207
  /**
   * cgroup_rstat_flush_begin - flush stats in @cgrp's subtree and hold
   * @cgrp: target cgroup
   *
   * Flush stats in @cgrp's subtree and prevent further flushes.  Must be
   * paired with cgroup_rstat_flush_release().
0fa294fb1   Tejun Heo   cgroup: Replace c...
208
209
   *
   * This function may block.
6162cef0f   Tejun Heo   cgroup: Factor ou...
210
211
   */
  void cgroup_rstat_flush_hold(struct cgroup *cgrp)
0fa294fb1   Tejun Heo   cgroup: Replace c...
212
  	__acquires(&cgroup_rstat_lock)
6162cef0f   Tejun Heo   cgroup: Factor ou...
213
  {
0fa294fb1   Tejun Heo   cgroup: Replace c...
214
215
216
  	might_sleep();
  	spin_lock_irq(&cgroup_rstat_lock);
  	cgroup_rstat_flush_locked(cgrp, true);
6162cef0f   Tejun Heo   cgroup: Factor ou...
217
218
219
220
221
222
  }
  
  /**
   * cgroup_rstat_flush_release - release cgroup_rstat_flush_hold()
   */
  void cgroup_rstat_flush_release(void)
0fa294fb1   Tejun Heo   cgroup: Replace c...
223
  	__releases(&cgroup_rstat_lock)
6162cef0f   Tejun Heo   cgroup: Factor ou...
224
  {
0fa294fb1   Tejun Heo   cgroup: Replace c...
225
  	spin_unlock_irq(&cgroup_rstat_lock);
6162cef0f   Tejun Heo   cgroup: Factor ou...
226
  }
a17556f8d   Tejun Heo   cgroup: Reorganiz...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  int cgroup_rstat_init(struct cgroup *cgrp)
  {
  	int cpu;
  
  	/* the root cgrp has rstat_cpu preallocated */
  	if (!cgrp->rstat_cpu) {
  		cgrp->rstat_cpu = alloc_percpu(struct cgroup_rstat_cpu);
  		if (!cgrp->rstat_cpu)
  			return -ENOMEM;
  	}
  
  	/* ->updated_children list is self terminated */
  	for_each_possible_cpu(cpu) {
  		struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
  
  		rstatc->updated_children = cgrp;
  		u64_stats_init(&rstatc->bsync);
  	}
  
  	return 0;
  }
  
  void cgroup_rstat_exit(struct cgroup *cgrp)
  {
  	int cpu;
  
  	cgroup_rstat_flush(cgrp);
  
  	/* sanity check */
  	for_each_possible_cpu(cpu) {
  		struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
  
  		if (WARN_ON_ONCE(rstatc->updated_children != cgrp) ||
  		    WARN_ON_ONCE(rstatc->updated_next))
  			return;
  	}
  
  	free_percpu(cgrp->rstat_cpu);
  	cgrp->rstat_cpu = NULL;
  }
  
  void __init cgroup_rstat_boot(void)
  {
  	int cpu;
  
  	for_each_possible_cpu(cpu)
  		raw_spin_lock_init(per_cpu_ptr(&cgroup_rstat_cpu_lock, cpu));
  
  	BUG_ON(cgroup_rstat_init(&cgrp_dfl_root.cgrp));
  }
  
  /*
   * Functions for cgroup basic resource statistics implemented on top of
   * rstat.
   */
1bb5ec2ee   Tejun Heo   cgroup: use cgrou...
282
283
  static void cgroup_base_stat_add(struct cgroup_base_stat *dst_bstat,
  				 struct cgroup_base_stat *src_bstat)
041cd640b   Tejun Heo   cgroup: Implement...
284
  {
d4ff749b5   Tejun Heo   cgroup: Distingui...
285
286
287
  	dst_bstat->cputime.utime += src_bstat->cputime.utime;
  	dst_bstat->cputime.stime += src_bstat->cputime.stime;
  	dst_bstat->cputime.sum_exec_runtime += src_bstat->cputime.sum_exec_runtime;
041cd640b   Tejun Heo   cgroup: Implement...
288
  }
1bb5ec2ee   Tejun Heo   cgroup: use cgrou...
289
290
291
292
293
294
295
  static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat,
  				 struct cgroup_base_stat *src_bstat)
  {
  	dst_bstat->cputime.utime -= src_bstat->cputime.utime;
  	dst_bstat->cputime.stime -= src_bstat->cputime.stime;
  	dst_bstat->cputime.sum_exec_runtime -= src_bstat->cputime.sum_exec_runtime;
  }
d4ff749b5   Tejun Heo   cgroup: Distingui...
296
  static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu)
041cd640b   Tejun Heo   cgroup: Implement...
297
298
  {
  	struct cgroup *parent = cgroup_parent(cgrp);
c58632b36   Tejun Heo   cgroup: Rename st...
299
  	struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
1bb5ec2ee   Tejun Heo   cgroup: use cgrou...
300
  	struct cgroup_base_stat cur, delta;
041cd640b   Tejun Heo   cgroup: Implement...
301
  	unsigned seq;
041cd640b   Tejun Heo   cgroup: Implement...
302
303
  	/* fetch the current per-cpu values */
  	do {
d4ff749b5   Tejun Heo   cgroup: Distingui...
304
  		seq = __u64_stats_fetch_begin(&rstatc->bsync);
1bb5ec2ee   Tejun Heo   cgroup: use cgrou...
305
  		cur.cputime = rstatc->bstat.cputime;
d4ff749b5   Tejun Heo   cgroup: Distingui...
306
  	} while (__u64_stats_fetch_retry(&rstatc->bsync, seq));
041cd640b   Tejun Heo   cgroup: Implement...
307

1bb5ec2ee   Tejun Heo   cgroup: use cgrou...
308
309
310
311
312
313
314
315
316
317
318
319
320
  	/* propagate percpu delta to global */
  	delta = cur;
  	cgroup_base_stat_sub(&delta, &rstatc->last_bstat);
  	cgroup_base_stat_add(&cgrp->bstat, &delta);
  	cgroup_base_stat_add(&rstatc->last_bstat, &delta);
  
  	/* propagate global delta to parent */
  	if (parent) {
  		delta = cgrp->bstat;
  		cgroup_base_stat_sub(&delta, &cgrp->last_bstat);
  		cgroup_base_stat_add(&parent->bstat, &delta);
  		cgroup_base_stat_add(&cgrp->last_bstat, &delta);
  	}
041cd640b   Tejun Heo   cgroup: Implement...
321
  }
c58632b36   Tejun Heo   cgroup: Rename st...
322
  static struct cgroup_rstat_cpu *
d4ff749b5   Tejun Heo   cgroup: Distingui...
323
  cgroup_base_stat_cputime_account_begin(struct cgroup *cgrp)
041cd640b   Tejun Heo   cgroup: Implement...
324
  {
c58632b36   Tejun Heo   cgroup: Rename st...
325
  	struct cgroup_rstat_cpu *rstatc;
041cd640b   Tejun Heo   cgroup: Implement...
326

c58632b36   Tejun Heo   cgroup: Rename st...
327
  	rstatc = get_cpu_ptr(cgrp->rstat_cpu);
d4ff749b5   Tejun Heo   cgroup: Distingui...
328
  	u64_stats_update_begin(&rstatc->bsync);
c58632b36   Tejun Heo   cgroup: Rename st...
329
  	return rstatc;
041cd640b   Tejun Heo   cgroup: Implement...
330
  }
d4ff749b5   Tejun Heo   cgroup: Distingui...
331
332
  static void cgroup_base_stat_cputime_account_end(struct cgroup *cgrp,
  						 struct cgroup_rstat_cpu *rstatc)
041cd640b   Tejun Heo   cgroup: Implement...
333
  {
d4ff749b5   Tejun Heo   cgroup: Distingui...
334
  	u64_stats_update_end(&rstatc->bsync);
6162cef0f   Tejun Heo   cgroup: Factor ou...
335
  	cgroup_rstat_updated(cgrp, smp_processor_id());
c58632b36   Tejun Heo   cgroup: Rename st...
336
  	put_cpu_ptr(rstatc);
041cd640b   Tejun Heo   cgroup: Implement...
337
338
339
340
  }
  
  void __cgroup_account_cputime(struct cgroup *cgrp, u64 delta_exec)
  {
c58632b36   Tejun Heo   cgroup: Rename st...
341
  	struct cgroup_rstat_cpu *rstatc;
041cd640b   Tejun Heo   cgroup: Implement...
342

d4ff749b5   Tejun Heo   cgroup: Distingui...
343
344
345
  	rstatc = cgroup_base_stat_cputime_account_begin(cgrp);
  	rstatc->bstat.cputime.sum_exec_runtime += delta_exec;
  	cgroup_base_stat_cputime_account_end(cgrp, rstatc);
041cd640b   Tejun Heo   cgroup: Implement...
346
347
348
349
350
  }
  
  void __cgroup_account_cputime_field(struct cgroup *cgrp,
  				    enum cpu_usage_stat index, u64 delta_exec)
  {
c58632b36   Tejun Heo   cgroup: Rename st...
351
  	struct cgroup_rstat_cpu *rstatc;
041cd640b   Tejun Heo   cgroup: Implement...
352

d4ff749b5   Tejun Heo   cgroup: Distingui...
353
  	rstatc = cgroup_base_stat_cputime_account_begin(cgrp);
041cd640b   Tejun Heo   cgroup: Implement...
354
355
356
357
  
  	switch (index) {
  	case CPUTIME_USER:
  	case CPUTIME_NICE:
d4ff749b5   Tejun Heo   cgroup: Distingui...
358
  		rstatc->bstat.cputime.utime += delta_exec;
041cd640b   Tejun Heo   cgroup: Implement...
359
360
361
362
  		break;
  	case CPUTIME_SYSTEM:
  	case CPUTIME_IRQ:
  	case CPUTIME_SOFTIRQ:
d4ff749b5   Tejun Heo   cgroup: Distingui...
363
  		rstatc->bstat.cputime.stime += delta_exec;
041cd640b   Tejun Heo   cgroup: Implement...
364
365
366
367
  		break;
  	default:
  		break;
  	}
d4ff749b5   Tejun Heo   cgroup: Distingui...
368
  	cgroup_base_stat_cputime_account_end(cgrp, rstatc);
041cd640b   Tejun Heo   cgroup: Implement...
369
  }
936f2a70f   Boris Burkov   cgroup: add cpu.s...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  /*
   * compute the cputime for the root cgroup by getting the per cpu data
   * at a global level, then categorizing the fields in a manner consistent
   * with how it is done by __cgroup_account_cputime_field for each bit of
   * cpu time attributed to a cgroup.
   */
  static void root_cgroup_cputime(struct task_cputime *cputime)
  {
  	int i;
  
  	cputime->stime = 0;
  	cputime->utime = 0;
  	cputime->sum_exec_runtime = 0;
  	for_each_possible_cpu(i) {
  		struct kernel_cpustat kcpustat;
  		u64 *cpustat = kcpustat.cpustat;
  		u64 user = 0;
  		u64 sys = 0;
  
  		kcpustat_cpu_fetch(&kcpustat, i);
  
  		user += cpustat[CPUTIME_USER];
  		user += cpustat[CPUTIME_NICE];
  		cputime->utime += user;
  
  		sys += cpustat[CPUTIME_SYSTEM];
  		sys += cpustat[CPUTIME_IRQ];
  		sys += cpustat[CPUTIME_SOFTIRQ];
  		cputime->stime += sys;
  
  		cputime->sum_exec_runtime += user;
  		cputime->sum_exec_runtime += sys;
  		cputime->sum_exec_runtime += cpustat[CPUTIME_STEAL];
  		cputime->sum_exec_runtime += cpustat[CPUTIME_GUEST];
  		cputime->sum_exec_runtime += cpustat[CPUTIME_GUEST_NICE];
  	}
  }
d4ff749b5   Tejun Heo   cgroup: Distingui...
407
  void cgroup_base_stat_cputime_show(struct seq_file *seq)
041cd640b   Tejun Heo   cgroup: Implement...
408
409
410
  {
  	struct cgroup *cgrp = seq_css(seq)->cgroup;
  	u64 usage, utime, stime;
936f2a70f   Boris Burkov   cgroup: add cpu.s...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  	struct task_cputime cputime;
  
  	if (cgroup_parent(cgrp)) {
  		cgroup_rstat_flush_hold(cgrp);
  		usage = cgrp->bstat.cputime.sum_exec_runtime;
  		cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime,
  			       &utime, &stime);
  		cgroup_rstat_flush_release();
  	} else {
  		root_cgroup_cputime(&cputime);
  		usage = cputime.sum_exec_runtime;
  		utime = cputime.utime;
  		stime = cputime.stime;
  	}
041cd640b   Tejun Heo   cgroup: Implement...
425
426
427
428
  
  	do_div(usage, NSEC_PER_USEC);
  	do_div(utime, NSEC_PER_USEC);
  	do_div(stime, NSEC_PER_USEC);
d41bf8c9d   Tejun Heo   cgroup, sched: Mo...
429
430
431
432
433
434
435
  	seq_printf(seq, "usage_usec %llu
  "
  		   "user_usec %llu
  "
  		   "system_usec %llu
  ",
  		   usage, utime, stime);
041cd640b   Tejun Heo   cgroup: Implement...
436
  }