.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | #include "cgroup-internal.h" |
---|
2 | 3 | |
---|
3 | 4 | #include <linux/sched/cputime.h> |
---|
.. | .. |
---|
63 | 64 | |
---|
64 | 65 | raw_spin_unlock_irqrestore(cpu_lock, flags); |
---|
65 | 66 | } |
---|
66 | | -EXPORT_SYMBOL_GPL(cgroup_rstat_updated); |
---|
67 | 67 | |
---|
68 | 68 | /** |
---|
69 | 69 | * cgroup_rstat_cpu_pop_updated - iterate and dismantle rstat_cpu updated tree |
---|
.. | .. |
---|
293 | 293 | * Functions for cgroup basic resource statistics implemented on top of |
---|
294 | 294 | * rstat. |
---|
295 | 295 | */ |
---|
296 | | -static void cgroup_base_stat_accumulate(struct cgroup_base_stat *dst_bstat, |
---|
297 | | - struct cgroup_base_stat *src_bstat) |
---|
| 296 | +static void cgroup_base_stat_add(struct cgroup_base_stat *dst_bstat, |
---|
| 297 | + struct cgroup_base_stat *src_bstat) |
---|
298 | 298 | { |
---|
299 | 299 | dst_bstat->cputime.utime += src_bstat->cputime.utime; |
---|
300 | 300 | dst_bstat->cputime.stime += src_bstat->cputime.stime; |
---|
301 | 301 | dst_bstat->cputime.sum_exec_runtime += src_bstat->cputime.sum_exec_runtime; |
---|
302 | 302 | } |
---|
303 | 303 | |
---|
| 304 | +static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat, |
---|
| 305 | + struct cgroup_base_stat *src_bstat) |
---|
| 306 | +{ |
---|
| 307 | + dst_bstat->cputime.utime -= src_bstat->cputime.utime; |
---|
| 308 | + dst_bstat->cputime.stime -= src_bstat->cputime.stime; |
---|
| 309 | + dst_bstat->cputime.sum_exec_runtime -= src_bstat->cputime.sum_exec_runtime; |
---|
| 310 | +} |
---|
| 311 | + |
---|
304 | 312 | static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) |
---|
305 | 313 | { |
---|
306 | 314 | struct cgroup *parent = cgroup_parent(cgrp); |
---|
307 | 315 | struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu); |
---|
308 | | - struct task_cputime *last_cputime = &rstatc->last_bstat.cputime; |
---|
309 | | - struct task_cputime cputime; |
---|
310 | | - struct cgroup_base_stat delta; |
---|
| 316 | + struct cgroup_base_stat cur, delta; |
---|
311 | 317 | unsigned seq; |
---|
312 | 318 | |
---|
313 | 319 | /* fetch the current per-cpu values */ |
---|
314 | 320 | do { |
---|
315 | 321 | seq = __u64_stats_fetch_begin(&rstatc->bsync); |
---|
316 | | - cputime = rstatc->bstat.cputime; |
---|
| 322 | + cur.cputime = rstatc->bstat.cputime; |
---|
317 | 323 | } while (__u64_stats_fetch_retry(&rstatc->bsync, seq)); |
---|
318 | 324 | |
---|
319 | | - /* calculate the delta to propgate */ |
---|
320 | | - delta.cputime.utime = cputime.utime - last_cputime->utime; |
---|
321 | | - delta.cputime.stime = cputime.stime - last_cputime->stime; |
---|
322 | | - delta.cputime.sum_exec_runtime = cputime.sum_exec_runtime - |
---|
323 | | - last_cputime->sum_exec_runtime; |
---|
324 | | - *last_cputime = cputime; |
---|
| 325 | + /* propagate percpu delta to global */ |
---|
| 326 | + delta = cur; |
---|
| 327 | + cgroup_base_stat_sub(&delta, &rstatc->last_bstat); |
---|
| 328 | + cgroup_base_stat_add(&cgrp->bstat, &delta); |
---|
| 329 | + cgroup_base_stat_add(&rstatc->last_bstat, &delta); |
---|
325 | 330 | |
---|
326 | | - /* transfer the pending stat into delta */ |
---|
327 | | - cgroup_base_stat_accumulate(&delta, &cgrp->pending_bstat); |
---|
328 | | - memset(&cgrp->pending_bstat, 0, sizeof(cgrp->pending_bstat)); |
---|
329 | | - |
---|
330 | | - /* propagate delta into the global stat and the parent's pending */ |
---|
331 | | - cgroup_base_stat_accumulate(&cgrp->bstat, &delta); |
---|
332 | | - if (parent) |
---|
333 | | - cgroup_base_stat_accumulate(&parent->pending_bstat, &delta); |
---|
| 331 | + /* propagate global delta to parent */ |
---|
| 332 | + if (parent) { |
---|
| 333 | + delta = cgrp->bstat; |
---|
| 334 | + cgroup_base_stat_sub(&delta, &cgrp->last_bstat); |
---|
| 335 | + cgroup_base_stat_add(&parent->bstat, &delta); |
---|
| 336 | + cgroup_base_stat_add(&cgrp->last_bstat, &delta); |
---|
| 337 | + } |
---|
334 | 338 | } |
---|
335 | 339 | |
---|
336 | 340 | static struct cgroup_rstat_cpu * |
---|
.. | .. |
---|
384 | 388 | cgroup_base_stat_cputime_account_end(cgrp, rstatc); |
---|
385 | 389 | } |
---|
386 | 390 | |
---|
| 391 | +/* |
---|
| 392 | + * compute the cputime for the root cgroup by getting the per cpu data |
---|
| 393 | + * at a global level, then categorizing the fields in a manner consistent |
---|
| 394 | + * with how it is done by __cgroup_account_cputime_field for each bit of |
---|
| 395 | + * cpu time attributed to a cgroup. |
---|
| 396 | + */ |
---|
| 397 | +static void root_cgroup_cputime(struct task_cputime *cputime) |
---|
| 398 | +{ |
---|
| 399 | + int i; |
---|
| 400 | + |
---|
| 401 | + cputime->stime = 0; |
---|
| 402 | + cputime->utime = 0; |
---|
| 403 | + cputime->sum_exec_runtime = 0; |
---|
| 404 | + for_each_possible_cpu(i) { |
---|
| 405 | + struct kernel_cpustat kcpustat; |
---|
| 406 | + u64 *cpustat = kcpustat.cpustat; |
---|
| 407 | + u64 user = 0; |
---|
| 408 | + u64 sys = 0; |
---|
| 409 | + |
---|
| 410 | + kcpustat_cpu_fetch(&kcpustat, i); |
---|
| 411 | + |
---|
| 412 | + user += cpustat[CPUTIME_USER]; |
---|
| 413 | + user += cpustat[CPUTIME_NICE]; |
---|
| 414 | + cputime->utime += user; |
---|
| 415 | + |
---|
| 416 | + sys += cpustat[CPUTIME_SYSTEM]; |
---|
| 417 | + sys += cpustat[CPUTIME_IRQ]; |
---|
| 418 | + sys += cpustat[CPUTIME_SOFTIRQ]; |
---|
| 419 | + cputime->stime += sys; |
---|
| 420 | + |
---|
| 421 | + cputime->sum_exec_runtime += user; |
---|
| 422 | + cputime->sum_exec_runtime += sys; |
---|
| 423 | + cputime->sum_exec_runtime += cpustat[CPUTIME_STEAL]; |
---|
| 424 | + } |
---|
| 425 | +} |
---|
| 426 | + |
---|
387 | 427 | void cgroup_base_stat_cputime_show(struct seq_file *seq) |
---|
388 | 428 | { |
---|
389 | 429 | struct cgroup *cgrp = seq_css(seq)->cgroup; |
---|
390 | 430 | u64 usage, utime, stime; |
---|
| 431 | + struct task_cputime cputime; |
---|
391 | 432 | |
---|
392 | | - if (!cgroup_parent(cgrp)) |
---|
393 | | - return; |
---|
394 | | - |
---|
395 | | - cgroup_rstat_flush_hold(cgrp); |
---|
396 | | - usage = cgrp->bstat.cputime.sum_exec_runtime; |
---|
397 | | - cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime, &utime, &stime); |
---|
398 | | - cgroup_rstat_flush_release(); |
---|
| 433 | + if (cgroup_parent(cgrp)) { |
---|
| 434 | + cgroup_rstat_flush_hold(cgrp); |
---|
| 435 | + usage = cgrp->bstat.cputime.sum_exec_runtime; |
---|
| 436 | + cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime, |
---|
| 437 | + &utime, &stime); |
---|
| 438 | + cgroup_rstat_flush_release(); |
---|
| 439 | + } else { |
---|
| 440 | + root_cgroup_cputime(&cputime); |
---|
| 441 | + usage = cputime.sum_exec_runtime; |
---|
| 442 | + utime = cputime.utime; |
---|
| 443 | + stime = cputime.stime; |
---|
| 444 | + } |
---|
399 | 445 | |
---|
400 | 446 | do_div(usage, NSEC_PER_USEC); |
---|
401 | 447 | do_div(utime, NSEC_PER_USEC); |
---|