diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-09-10 12:32:16 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-09-10 18:41:06 +0200 |
commit | 03a7b521e3ffb7f5d153d90480ba5d4bc29d1e8f (patch) | |
tree | d18052ac68aae77bcce3813e64bf1f956cc9ad7d /src/cgtop/cgtop.c | |
parent | 15af581253a3f25a71d4fa723bf1fdd22f842728 (diff) |
core: add support for the "pids" cgroup controller
This adds support for the new "pids" cgroup controller of 4.3 kernels.
It allows accounting the number of tasks in a cgroup and enforcing
limits on it.
This adds two new setting TasksAccounting= and TasksMax= to each unit,
as well as a gloabl option DefaultTasksAccounting=.
This also updated "cgtop" to optionally make use of the new
kernel-provided accounting.
systemctl has been updated to show the number of tasks for each service
if it is available.
This patch also adds correct support for undoing memory limits for units
using a MemoryLimit=infinity syntax. We do the same for TasksMax= now
and hence keep things in sync here.
Diffstat (limited to 'src/cgtop/cgtop.c')
-rw-r--r-- | src/cgtop/cgtop.c | 107 |
1 files changed, 89 insertions, 18 deletions
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 1c94bea31a..7a0399d8f2 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -45,7 +45,7 @@ typedef struct Group { bool memory_valid:1; bool io_valid:1; - unsigned n_tasks; + uint64_t n_tasks; unsigned cpu_iteration; nsec_t cpu_usage; @@ -65,7 +65,12 @@ static unsigned arg_iterations = (unsigned) -1; static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; -static bool arg_kernel_threads = false; + +enum { + COUNT_PIDS, + COUNT_USERSPACE_PROCESSES, + COUNT_ALL_PROCESSES, +} arg_count = COUNT_PIDS; static bool arg_recursive = true; static enum { @@ -73,7 +78,7 @@ static enum { ORDER_TASKS, ORDER_CPU, ORDER_MEMORY, - ORDER_IO + ORDER_IO, } arg_order = ORDER_CPU; static enum { @@ -153,7 +158,7 @@ static int process( } } - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { + if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) { _cleanup_fclose_ FILE *f = NULL; pid_t pid; @@ -166,7 +171,7 @@ static int process( g->n_tasks = 0; while (cg_read_pid(f, &pid) > 0) { - if (!arg_kernel_threads && is_kernel_thread(pid) > 0) + if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0) continue; g->n_tasks++; @@ -175,6 +180,26 @@ static int process( if (g->n_tasks > 0) g->n_tasks_valid = true; + } else if (streq(controller, "pids") && arg_count == COUNT_PIDS) { + _cleanup_free_ char *p = NULL, *v = NULL; + + r = cg_get_path(controller, path, "pids.current", &p); + if (r < 0) + return r; + + r = read_one_line_file(p, &v); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + + r = safe_atou64(v, &g->n_tasks); + if (r < 0) + return r; + + if (g->n_tasks > 0) + g->n_tasks_valid = true; + } else if (streq(controller, "cpuacct") && cg_unified() <= 0) { _cleanup_free_ char *p = NULL, *v = NULL; uint64_t new_usage; @@ -371,6 +396,7 @@ static int refresh_one( return r; if (arg_recursive && + IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES) && child && child->n_tasks_valid && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { @@ -409,6 +435,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) r = refresh_one("blkio", root, a, b, iteration, 0, NULL); if (r < 0) return r; + r = refresh_one("pids", root, a, b, iteration, 0, NULL); + if (r < 0) + return r; return 0; } @@ -549,7 +578,7 @@ static void display(Hashmap *a) { printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n", arg_order == ORDER_PATH ? ON : "", path_columns, "Control Group", arg_order == ORDER_PATH ? OFF : "", - arg_order == ORDER_TASKS ? ON : "", "Tasks", + 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 : "", @@ -576,7 +605,7 @@ static void display(Hashmap *a) { printf("%-*s", path_columns, ellipsized ?: path); if (g->n_tasks_valid) - printf(" %7u", g->n_tasks); + printf(" %7" PRIu64, g->n_tasks); else fputs(" -", stdout); @@ -602,15 +631,16 @@ static void help(void) { " -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\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" - " -k Include kernel threads in task count\n" - " --recursive=BOOL Sum up task count recursively\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" @@ -642,12 +672,13 @@ static int parse_argv(int argc, char *argv[]) { {} }; + bool recursive_unset = false; int c, r; assert(argc >= 1); assert(argv); - while ((c = getopt_long(argc, argv, "hptcmin:brd:k", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hptcmin:brd:kP", options, NULL)) >= 0) switch (c) { @@ -748,7 +779,11 @@ static int parse_argv(int argc, char *argv[]) { break; case 'k': - arg_kernel_threads = true; + arg_count = COUNT_ALL_PROCESSES; + break; + + case 'P': + arg_count = COUNT_USERSPACE_PROCESSES; break; case ARG_RECURSIVE: @@ -759,6 +794,7 @@ static int parse_argv(int argc, char *argv[]) { } arg_recursive = r; + recursive_unset = r == 0; break; case '?': @@ -773,9 +809,23 @@ static int parse_argv(int argc, char *argv[]) { 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)"; +} + int main(int argc, char *argv[]) { int r; Hashmap *a = NULL, *b = NULL; @@ -783,10 +833,19 @@ int main(int argc, char *argv[]) { 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; @@ -899,15 +958,26 @@ int main(int argc, char *argv[]) { break; case 'k': - arg_kernel_threads = !arg_kernel_threads; - fprintf(stdout, "\nCounting kernel threads: %s.", yes_no(arg_kernel_threads)); + 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': - arg_recursive = !arg_recursive; - fprintf(stdout, "\nRecursive task counting: %s", yes_no(arg_recursive)); + 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; @@ -939,9 +1009,10 @@ int main(int argc, char *argv[]) { case '?': case 'h': fprintf(stdout, - "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n" + "\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 "k" OFF "> Count kernel threads; <" ON "r" OFF "> Count recursively; <" ON "q" OFF "> Quit"); + "\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; |