| .. | .. |
|---|
| 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); |
|---|