cgtop.c revision 96a6426f30dc9bf3c4dd1f61548c334fa12034df
8a77240a809197c92c0736c431b4b88947a7bac1Christian Maeder/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
adea2e45fa61f1097aadc490a0aeaf4831b729ccChristian Maeder This file is part of systemd.
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder Copyright 2012 Lennart Poettering
98890889ffb2e8f6f722b00e265a211f13b5a861Corneliu-Claudiu Prodescu systemd is free software; you can redistribute it and/or modify it
2eeec5240b424984e3ee26296da1eeab6c6d739eChristian Maeder under the terms of the GNU Lesser General Public License as published by
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowski the Free Software Foundation; either version 2.1 of the License, or
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowski (at your option) any later version.
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder systemd is distributed in the hope that it will be useful, but
0095c7efbddd0ffeed6aaf8ec015346be161d819Till Mossakowski WITHOUT ANY WARRANTY; without even the implied warranty of
adea2e45fa61f1097aadc490a0aeaf4831b729ccChristian Maeder MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowski Lesser General Public License for more details.
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder You should have received a copy of the GNU Lesser General Public License
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder along with systemd; If not, see <http://www.gnu.org/licenses/>.
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowskitypedef struct Group {
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowskistatic unsigned arg_iterations = (unsigned) -1;
adea2e45fa61f1097aadc490a0aeaf4831b729ccChristian Maederstatic bool arg_batch = false;
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowskistatic bool arg_raw = false;
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maederstatic bool arg_recursive = true;
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maederstatic void group_hashmap_clear(Hashmap *h) {
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowskistatic void group_hashmap_free(Hashmap *h) {
df11e5eab86d8247f58e301d8f0a2c6ecf4c9541Till Mossakowskistatic const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) {
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false;
c911a0ec80ca4a178399c68f1e28be4e2bf42fceChristian Maeder if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder r = cg_enumerate_processes(controller, path, &f);
556f473448dfcceee22afaa89ed7a364489cdbbbChristian Maeder if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0)
d3c9318c22fcf44d9135a3b2c64f880b9a785babChristian Maeder } else if (streq(controller, "pids") && arg_count == COUNT_PIDS) {
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder r = cg_get_path(controller, path, "pids.current", &p);
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder } else if (streq(controller, "cpuacct") && cg_unified() <= 0) {
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder r = cg_get_path(controller, path, "cpuacct.usage", &p);
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder g->cpu_fraction = (double) y / (double) x;
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
a98fd29a06e80e447af26d898044c23497adbc73Mihai Codescu r = cg_get_path(controller, path, "memory.current", &p);
09b431a868c79a92ae7c9bd141565f43f9034144Christian Maeder } else if (streq(controller, "blkio") && cg_unified() <= 0) {
c911a0ec80ca4a178399c68f1e28be4e2bf42fceChristian Maeder r = cg_get_path(controller, path, "blkio.io_service_bytes", &p);
556f473448dfcceee22afaa89ed7a364489cdbbbChristian Maeder x = (uint64_t) (timestamp - g->io_timestamp);
556f473448dfcceee22afaa89ed7a364489cdbbbChristian Maeder g->io_input_bps = (yr * 1000000000ULL) / x;
556f473448dfcceee22afaa89ed7a364489cdbbbChristian Maeder g->io_output_bps = (yw * 1000000000ULL) / x;
if (ret)
*ret = g;
static int refresh_one(
const char *controller,
const char *path,
Hashmap *a,
Hashmap *b,
unsigned iteration,
unsigned depth,
assert(a);
if (r == -ENOENT)
return -ENOMEM;
if (arg_recursive &&
child &&
if (ret)
assert(a);
static int group_compare(const void*a, const void *b) {
switch (arg_order) {
case ORDER_PATH:
case ORDER_CPU:
} else if (x->cpu_valid)
else if (y->cpu_valid)
case ORDER_TASKS:
} else if (x->n_tasks_valid)
else if (y->n_tasks_valid)
case ORDER_MEMORY:
} else if (x->memory_valid)
else if (y->memory_valid)
case ORDER_IO:
} else if (x->io_valid)
else if (y->io_valid)
Iterator i;
Group *g;
signed path_columns;
assert(a);
if (on_tty())
HASHMAP_FOREACH(g, a, i)
array[n++] = g;
if (on_tty()) {
arg_order == ORDER_TASKS ? ON : "", arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
const char *path;
g = array[j];
if (g->n_tasks_valid)
if (g->cpu_valid)
printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
static void help(void) {
bool recursive_unset = false;
help();
case ARG_VERSION:
case ARG_CPU_TYPE:
if (optarg) {
return -EINVAL;
case ARG_DEPTH:
return -EINVAL;
if (r < 0 || arg_delay <= 0) {
return -EINVAL;
return -EINVAL;
arg_batch = true;
arg_raw = true;
case ARG_ORDER:
return -EINVAL;
case ARG_RECURSIVE:
arg_recursive = r;
recursive_unset = r == 0;
return -EINVAL;
return -EINVAL;
log_error("Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
return -EINVAL;
static const char* counting_what(void) {
if (!arg_machine) {
if (!path)
return log_oom();
bus,
"org.freedesktop.systemd1",
path,
&error,
ret);
return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
unsigned iteration = 0;
log_open();
goto finish;
goto finish;
goto finish;
r = log_oom();
goto finish;
while (!quit) {
Hashmap *c;
usec_t t;
char key;
char h[FORMAT_TIMESPAN_MAX];
goto finish;
last_refresh = t;
immediate_refresh = false;
display(b);
if (arg_batch)
if (r == -ETIMEDOUT)
goto finish;
if (arg_batch)
switch (key) {
immediate_refresh = true;
quit = true;
"\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks/procs; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
"\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n"