cgtop.c revision b5efdb8af40ea759a1ea584c1bc44ecc81dd00ce
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/***
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering This file is part of systemd.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright 2012 Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering***/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <alloca.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <errno.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <getopt.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <signal.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <stdint.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <stdlib.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <string.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <unistd.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "sd-bus.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "alloc-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "bus-error.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "bus-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "cgroup-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "fd-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "fileio.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "hashmap.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "parse-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "path-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "process-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "terminal-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "unit-name.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringtypedef struct Group {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *path;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bool n_tasks_valid:1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bool cpu_valid:1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bool memory_valid:1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bool io_valid:1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint64_t n_tasks;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned cpu_iteration;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering nsec_t cpu_usage;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering nsec_t cpu_timestamp;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering double cpu_fraction;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint64_t memory;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned io_iteration;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint64_t io_input, io_output;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering nsec_t io_timestamp;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint64_t io_input_bps, io_output_bps;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} Group;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic unsigned arg_depth = 3;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic unsigned arg_iterations = (unsigned) -1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic bool arg_batch = false;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic bool arg_raw = false;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic usec_t arg_delay = 1*USEC_PER_SEC;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic char* arg_machine = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringenum {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering COUNT_PIDS,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering COUNT_USERSPACE_PROCESSES,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering COUNT_ALL_PROCESSES,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} arg_count = COUNT_PIDS;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic bool arg_recursive = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic enum {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ORDER_PATH,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ORDER_TASKS,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ORDER_CPU,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ORDER_MEMORY,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ORDER_IO,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} arg_order = ORDER_CPU;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic enum {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering CPU_PERCENT,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering CPU_TIME,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} arg_cpu_type = CPU_PERCENT;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void group_free(Group *g) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(g);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(g->path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(g);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void group_hashmap_clear(Hashmap *h) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Group *g;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while ((g = hashmap_steal_first(h)))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering group_free(g);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void group_hashmap_free(Hashmap *h) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering group_hashmap_clear(h);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering hashmap_free(h);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!is_valid)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return "-";
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (arg_raw) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering snprintf(buf, l, "%jd", t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return buf;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return format_bytes(buf, l, t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int process(
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *controller,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *path,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Hashmap *a,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Hashmap *b,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned iteration,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Group **ret) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Group *g;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(controller);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(a);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g = hashmap_get(a, path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!g) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g = hashmap_get(b, path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!g) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g = new0(Group, 1);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!g)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->path = strdup(path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!g->path) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering group_free(g);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = hashmap_put(a, g->path, g);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering group_free(g);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = hashmap_move_one(a, b, path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering pid_t pid;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = cg_enumerate_processes(controller, path, &f);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r == -ENOENT)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->n_tasks = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (cg_read_pid(f, &pid) > 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->n_tasks++;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (g->n_tasks > 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->n_tasks_valid = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else if (streq(controller, "pids") && arg_count == COUNT_PIDS) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char *p = NULL, *v = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = cg_get_path(controller, path, "pids.current", &p);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = read_one_line_file(p, &v);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r == -ENOENT)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = safe_atou64(v, &g->n_tasks);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (g->n_tasks > 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->n_tasks_valid = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else if (streq(controller, "cpuacct") && cg_unified() <= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char *p = NULL, *v = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint64_t new_usage;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering nsec_t timestamp;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = cg_get_path(controller, path, "cpuacct.usage", &p);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = read_one_line_file(p, &v);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r == -ENOENT)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = safe_atou64(v, &new_usage);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering timestamp = now_nsec(CLOCK_MONOTONIC);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (g->cpu_iteration == iteration - 1 &&
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering (nsec_t) new_usage > g->cpu_usage) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering nsec_t x, y;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering x = timestamp - g->cpu_timestamp;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (x < 1)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering x = 1;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering y = (nsec_t) new_usage - g->cpu_usage;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering g->cpu_fraction = (double) y / (double) x;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering g->cpu_valid = true;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering g->cpu_usage = (nsec_t) new_usage;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering g->cpu_timestamp = timestamp;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering g->cpu_iteration = iteration;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (streq(controller, "memory")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_free_ char *p = NULL, *v = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (cg_unified() <= 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering else
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = cg_get_path(controller, path, "memory.current", &p);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = read_one_line_file(p, &v);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r == -ENOENT)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = safe_atou64(v, &g->memory);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (g->memory > 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering g->memory_valid = true;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (streq(controller, "blkio") && cg_unified() <= 0) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_free_ char *p = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uint64_t wr = 0, rd = 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering nsec_t timestamp;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = cg_get_path(controller, path, "blkio.io_service_bytes", &p);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering f = fopen(p, "re");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!f) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (errno == ENOENT)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -errno;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering for (;;) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char line[LINE_MAX], *l;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uint64_t k, *q;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!fgets(line, sizeof(line), f))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering break;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l = strstrip(line);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l += strcspn(l, WHITESPACE);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l += strspn(l, WHITESPACE);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (first_word(l, "Read")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l += 4;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering q = &rd;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (first_word(l, "Write")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l += 5;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering q = &wr;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering continue;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l += strspn(l, WHITESPACE);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = safe_atou64(l, &k);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering continue;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering *q += k;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering timestamp = now_nsec(CLOCK_MONOTONIC);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (g->io_iteration == iteration - 1) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uint64_t x, yr, yw;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering x = (uint64_t) (timestamp - g->io_timestamp);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (x < 1)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering x = 1;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (rd > g->io_input)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering yr = rd - g->io_input;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering else
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering yr = 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (wr > g->io_output)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering yw = wr - g->io_output;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering yw = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (yr > 0 || yw > 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_input_bps = (yr * 1000000000ULL) / x;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_output_bps = (yw * 1000000000ULL) / x;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_valid = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_input = rd;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_output = wr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_timestamp = timestamp;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering g->io_iteration = iteration;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ret)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering *ret = g;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int refresh_one(
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *controller,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *path,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering Hashmap *a,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Hashmap *b,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned iteration,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned depth,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Group **ret) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_closedir_ DIR *d = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Group *ours;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(controller);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(path);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(a);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (depth > arg_depth)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = process(controller, path, a, b, iteration, &ours);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = cg_enumerate_subgroups(controller, path, &d);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r == -ENOENT)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (;;) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char *fn = NULL, *p = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Group *child = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = cg_read_subgroup(d, &fn);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r == 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering break;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering p = strjoin(path, "/", fn, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!p)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering path_kill_slashes(p);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = refresh_one(controller, p, a, b, iteration, depth + 1, &child);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (arg_recursive &&
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES) &&
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering child &&
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering child->n_tasks_valid &&
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Recursively sum up processes */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ours->n_tasks_valid)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ours->n_tasks += child->n_tasks;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ours->n_tasks = child->n_tasks;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ours->n_tasks_valid = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ret)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering *ret = ours;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(a);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, root, a, b, iteration, 0, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = refresh_one("cpuacct", root, a, b, iteration, 0, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = refresh_one("memory", root, a, b, iteration, 0, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = refresh_one("pids", root, a, b, iteration, 0, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int group_compare(const void*a, const void *b) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const Group *x = *(Group**)a, *y = *(Group**)b;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (arg_order != ORDER_TASKS || arg_recursive) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Let's make sure that the parent is always before
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * the child. Except when ordering by tasks and
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * recursive summing is off, since that is actually
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * not accumulative for all children. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (path_startswith(y->path, x->path))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (path_startswith(x->path, y->path))
return 1;
}
switch (arg_order) {
case ORDER_PATH:
break;
case ORDER_CPU:
if (arg_cpu_type == CPU_PERCENT) {
if (x->cpu_valid && y->cpu_valid) {
if (x->cpu_fraction > y->cpu_fraction)
return -1;
else if (x->cpu_fraction < y->cpu_fraction)
return 1;
} else if (x->cpu_valid)
return -1;
else if (y->cpu_valid)
return 1;
} else {
if (x->cpu_usage > y->cpu_usage)
return -1;
else if (x->cpu_usage < y->cpu_usage)
return 1;
}
break;
case ORDER_TASKS:
if (x->n_tasks_valid && y->n_tasks_valid) {
if (x->n_tasks > y->n_tasks)
return -1;
else if (x->n_tasks < y->n_tasks)
return 1;
} else if (x->n_tasks_valid)
return -1;
else if (y->n_tasks_valid)
return 1;
break;
case ORDER_MEMORY:
if (x->memory_valid && y->memory_valid) {
if (x->memory > y->memory)
return -1;
else if (x->memory < y->memory)
return 1;
} else if (x->memory_valid)
return -1;
else if (y->memory_valid)
return 1;
break;
case ORDER_IO:
if (x->io_valid && y->io_valid) {
if (x->io_input_bps + x->io_output_bps > y->io_input_bps + y->io_output_bps)
return -1;
else if (x->io_input_bps + x->io_output_bps < y->io_input_bps + y->io_output_bps)
return 1;
} else if (x->io_valid)
return -1;
else if (y->io_valid)
return 1;
}
return path_compare(x->path, y->path);
}
static void display(Hashmap *a) {
Iterator i;
Group *g;
Group **array;
signed path_columns;
unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)];
assert(a);
if (on_tty())
fputs(ANSI_HOME_CLEAR, stdout);
array = alloca(sizeof(Group*) * hashmap_size(a));
HASHMAP_FOREACH(g, a, i)
if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid)
array[n++] = g;
qsort_safe(array, n, sizeof(Group*), group_compare);
/* Find the longest names in one run */
for (j = 0; j < n; j++) {
unsigned cputlen, pathtlen;
format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
cputlen = strlen(buffer);
maxtcpu = MAX(maxtcpu, cputlen);
pathtlen = strlen(array[j]->path);
maxtpath = MAX(maxtpath, pathtlen);
}
if (arg_cpu_type == CPU_PERCENT)
snprintf(buffer, sizeof(buffer), "%6s", "%CPU");
else
snprintf(buffer, sizeof(buffer), "%*s", maxtcpu, "CPU Time");
rows = lines();
if (rows <= 10)
rows = 10;
if (on_tty()) {
const char *on, *off;
path_columns = columns() - 36 - strlen(buffer);
if (path_columns < 10)
path_columns = 10;
on = ansi_highlight_underline();
off = ansi_underline();
printf("%s%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
ansi_underline(),
arg_order == ORDER_PATH ? on : "", path_columns, "Control Group",
arg_order == ORDER_PATH ? off : "",
arg_order == ORDER_TASKS ? on : "", arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
arg_order == ORDER_TASKS ? off : "",
arg_order == ORDER_CPU ? on : "", buffer,
arg_order == ORDER_CPU ? off : "",
arg_order == ORDER_MEMORY ? on : "", "Memory",
arg_order == ORDER_MEMORY ? off : "",
arg_order == ORDER_IO ? on : "", "Input/s",
arg_order == ORDER_IO ? off : "",
arg_order == ORDER_IO ? on : "", "Output/s",
arg_order == ORDER_IO ? off : "",
ansi_normal());
} else
path_columns = maxtpath;
for (j = 0; j < n; j++) {
_cleanup_free_ char *ellipsized = NULL;
const char *path;
if (on_tty() && j + 6 > rows)
break;
g = array[j];
path = isempty(g->path) ? "/" : g->path;
ellipsized = ellipsize(path, path_columns, 33);
printf("%-*s", path_columns, ellipsized ?: path);
if (g->n_tasks_valid)
printf(" %7" PRIu64, g->n_tasks);
else
fputs(" -", stdout);
if (arg_cpu_type == CPU_PERCENT) {
if (g->cpu_valid)
printf(" %6.1f", g->cpu_fraction*100);
else
fputs(" -", stdout);
} else
printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_output_bps));
putchar('\n');
}
}
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Show top control groups by their resource usage.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -p --order=path Order by path\n"
" -t --order=tasks Order by number of tasks/processes\n"
" -c --order=cpu Order by CPU load (default)\n"
" -m --order=memory Order by memory load\n"
" -i --order=io Order by IO load\n"
" -r --raw Provide raw (not human-readable) numbers\n"
" --cpu=percentage Show CPU usage as percentage (default)\n"
" --cpu=time Show CPU usage as time\n"
" -P Count userspace processes instead of tasks (excl. kernel)\n"
" -k Count all processes instead of tasks (incl. kernel)\n"
" --recursive=BOOL Sum up process count recursively\n"
" -d --delay=DELAY Delay between updates\n"
" -n --iterations=N Run for N iterations before exiting\n"
" -b --batch Run in batch mode, accepting no input\n"
" --depth=DEPTH Maximum traversal depth (default: %u)\n"
" -M --machine= Show container\n"
, program_invocation_short_name, arg_depth);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_DEPTH,
ARG_CPU_TYPE,
ARG_ORDER,
ARG_RECURSIVE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "delay", required_argument, NULL, 'd' },
{ "iterations", required_argument, NULL, 'n' },
{ "batch", no_argument, NULL, 'b' },
{ "raw", no_argument, NULL, 'r' },
{ "depth", required_argument, NULL, ARG_DEPTH },
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE },
{ "order", required_argument, NULL, ARG_ORDER },
{ "recursive", required_argument, NULL, ARG_RECURSIVE },
{ "machine", required_argument, NULL, 'M' },
{}
};
bool recursive_unset = false;
int c, r;
assert(argc >= 1);
assert(argv);
while ((c = getopt_long(argc, argv, "hptcmin:brd:kPM:", options, NULL)) >= 0)
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
return version();
case ARG_CPU_TYPE:
if (optarg) {
if (streq(optarg, "time"))
arg_cpu_type = CPU_TIME;
else if (streq(optarg, "percentage"))
arg_cpu_type = CPU_PERCENT;
else {
log_error("Unknown argument to --cpu=: %s", optarg);
return -EINVAL;
}
} else
arg_cpu_type = CPU_TIME;
break;
case ARG_DEPTH:
r = safe_atou(optarg, &arg_depth);
if (r < 0) {
log_error("Failed to parse depth parameter.");
return -EINVAL;
}
break;
case 'd':
r = parse_sec(optarg, &arg_delay);
if (r < 0 || arg_delay <= 0) {
log_error("Failed to parse delay parameter.");
return -EINVAL;
}
break;
case 'n':
r = safe_atou(optarg, &arg_iterations);
if (r < 0) {
log_error("Failed to parse iterations parameter.");
return -EINVAL;
}
break;
case 'b':
arg_batch = true;
break;
case 'r':
arg_raw = true;
break;
case 'p':
arg_order = ORDER_PATH;
break;
case 't':
arg_order = ORDER_TASKS;
break;
case 'c':
arg_order = ORDER_CPU;
break;
case 'm':
arg_order = ORDER_MEMORY;
break;
case 'i':
arg_order = ORDER_IO;
break;
case ARG_ORDER:
if (streq(optarg, "path"))
arg_order = ORDER_PATH;
else if (streq(optarg, "tasks"))
arg_order = ORDER_TASKS;
else if (streq(optarg, "cpu"))
arg_order = ORDER_CPU;
else if (streq(optarg, "memory"))
arg_order = ORDER_MEMORY;
else if (streq(optarg, "io"))
arg_order = ORDER_IO;
else {
log_error("Invalid argument to --order=: %s", optarg);
return -EINVAL;
}
break;
case 'k':
arg_count = COUNT_ALL_PROCESSES;
break;
case 'P':
arg_count = COUNT_USERSPACE_PROCESSES;
break;
case ARG_RECURSIVE:
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --recursive= argument: %s", optarg);
return r;
}
arg_recursive = r;
recursive_unset = r == 0;
break;
case 'M':
arg_machine = optarg;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
if (optind < argc) {
log_error("Too many arguments.");
return -EINVAL;
}
if (recursive_unset && arg_count == COUNT_PIDS) {
log_error("Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
return -EINVAL;
}
return 1;
}
static const char* counting_what(void) {
if (arg_count == COUNT_PIDS)
return "tasks";
else if (arg_count == COUNT_ALL_PROCESSES)
return "all processes (incl. kernel)";
else
return "userspace processes (excl. kernel)";
}
static int get_cgroup_root(char **ret) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
_cleanup_free_ char *unit = NULL, *path = NULL;
const char *m;
int r;
if (!arg_machine) {
r = cg_get_root_path(ret);
if (r < 0)
return log_error_errno(r, "Failed to get root control group path: %m");
return 0;
}
m = strjoina("/run/systemd/machines/", arg_machine);
r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load machine data: %m");
path = unit_dbus_path_from_name(unit);
if (!path)
return log_oom();
r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
path,
unit_dbus_interface_from_name(unit),
"ControlGroup",
&error,
ret);
if (r < 0)
return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
return 0;
}
int main(int argc, char *argv[]) {
int r;
Hashmap *a = NULL, *b = NULL;
unsigned iteration = 0;
usec_t last_refresh = 0;
bool quit = false, immediate_refresh = false;
_cleanup_free_ char *root = NULL;
CGroupMask mask;
log_parse_environment();
log_open();
r = cg_mask_supported(&mask);
if (r < 0) {
log_error_errno(r, "Failed to determine supported controllers: %m");
goto finish;
}
arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES;
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = get_cgroup_root(&root);
if (r < 0) {
log_error_errno(r, "Failed to get root control group path: %m");
goto finish;
}
a = hashmap_new(&string_hash_ops);
b = hashmap_new(&string_hash_ops);
if (!a || !b) {
r = log_oom();
goto finish;
}
signal(SIGWINCH, columns_lines_cache_reset);
if (arg_iterations == (unsigned) -1)
arg_iterations = on_tty() ? 0 : 1;
while (!quit) {
Hashmap *c;
usec_t t;
char key;
char h[FORMAT_TIMESPAN_MAX];
t = now(CLOCK_MONOTONIC);
if (t >= last_refresh + arg_delay || immediate_refresh) {
r = refresh(root, a, b, iteration++);
if (r < 0) {
log_error_errno(r, "Failed to refresh: %m");
goto finish;
}
group_hashmap_clear(b);
c = a;
a = b;
b = c;
last_refresh = t;
immediate_refresh = false;
}
display(b);
if (arg_iterations && iteration >= arg_iterations)
break;
if (!on_tty()) /* non-TTY: Empty newline as delimiter between polls */
fputs("\n", stdout);
fflush(stdout);
if (arg_batch)
(void) usleep(last_refresh + arg_delay - t);
else {
r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL);
if (r == -ETIMEDOUT)
continue;
if (r < 0) {
log_error_errno(r, "Couldn't read key: %m");
goto finish;
}
}
if (on_tty()) { /* TTY: Clear any user keystroke */
fputs("\r \r", stdout);
fflush(stdout);
}
if (arg_batch)
continue;
switch (key) {
case ' ':
immediate_refresh = true;
break;
case 'q':
quit = true;
break;
case 'p':
arg_order = ORDER_PATH;
break;
case 't':
arg_order = ORDER_TASKS;
break;
case 'c':
arg_order = ORDER_CPU;
break;
case 'm':
arg_order = ORDER_MEMORY;
break;
case 'i':
arg_order = ORDER_IO;
break;
case '%':
arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME;
break;
case 'k':
arg_count = arg_count != COUNT_ALL_PROCESSES ? COUNT_ALL_PROCESSES : COUNT_PIDS;
fprintf(stdout, "\nCounting: %s.", counting_what());
fflush(stdout);
sleep(1);
break;
case 'P':
arg_count = arg_count != COUNT_USERSPACE_PROCESSES ? COUNT_USERSPACE_PROCESSES : COUNT_PIDS;
fprintf(stdout, "\nCounting: %s.", counting_what());
fflush(stdout);
sleep(1);
break;
case 'r':
if (arg_count == COUNT_PIDS)
fprintf(stdout, "\n\aCannot toggle recursive counting, not available in task counting mode.");
else {
arg_recursive = !arg_recursive;
fprintf(stdout, "\nRecursive process counting: %s", yes_no(arg_recursive));
}
fflush(stdout);
sleep(1);
break;
case '+':
if (arg_delay < USEC_PER_SEC)
arg_delay += USEC_PER_MSEC*250;
else
arg_delay += USEC_PER_SEC;
fprintf(stdout, "\nIncreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0));
fflush(stdout);
sleep(1);
break;
case '-':
if (arg_delay <= USEC_PER_MSEC*500)
arg_delay = USEC_PER_MSEC*250;
else if (arg_delay < USEC_PER_MSEC*1250)
arg_delay -= USEC_PER_MSEC*250;
else
arg_delay -= USEC_PER_SEC;
fprintf(stdout, "\nDecreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0));
fflush(stdout);
sleep(1);
break;
case '?':
case 'h':
#define ON ANSI_HIGHLIGHT
#define OFF ANSI_NORMAL
fprintf(stdout,
"\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"
"\t<" ON "P" OFF "> Toggle count userspace processes; <" ON "k" OFF "> Toggle count all processes\n"
"\t<" ON "r" OFF "> Count processes recursively; <" ON "q" OFF "> Quit");
fflush(stdout);
sleep(3);
break;
default:
if (key < ' ')
fprintf(stdout, "\nUnknown key '\\x%x'. Ignoring.", key);
else
fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key);
fflush(stdout);
sleep(1);
break;
}
}
r = 0;
finish:
group_hashmap_free(a);
group_hashmap_free(b);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}