#include "util.h"
#include "hashmap.h"
#include "cgroup-util.h"
+#include "build.h"
+#include "fileio.h"
typedef struct Group {
char *path;
} Group;
static unsigned arg_depth = 3;
+static unsigned arg_iterations = 0;
+static bool arg_batch = false;
static usec_t arg_delay = 1*USEC_PER_SEC;
static enum {
r = cg_enumerate_subgroups(controller, path, &d);
if (r < 0) {
- if (r == ENOENT)
+ if (r == -ENOENT)
return 0;
return r;
Iterator i;
Group *g;
Group **array;
- unsigned rows, n = 0, j;
+ unsigned rows, path_columns, n = 0, j;
assert(a);
qsort(array, n, sizeof(Group*), group_compare);
- rows = fd_lines(STDOUT_FILENO);
- if (rows <= 0)
- rows = 25;
-
- printf("%s%-37s%s %s%7s%s %s%6s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
- arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_ON : "", "Path", arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_OFF : "",
- arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_ON : "", "Tasks", arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_OFF : "",
- arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_ON : "", "%CPU", arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_OFF : "",
- arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_ON : "", "Memory", arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_OFF : "",
- arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Input/s", arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "",
- arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Output/s", arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "");
+ rows = lines();
+ if (rows <= 10)
+ rows = 10;
+
+ path_columns = columns() - 42;
+ if (path_columns < 10)
+ path_columns = 10;
+
+ printf("%s%-*s%s %s%7s%s %s%6s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
+ arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_ON : "", path_columns, "Path",
+ arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_OFF : "",
+ arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_ON : "", "Tasks",
+ arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_OFF : "",
+ arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_ON : "", "%CPU",
+ arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_OFF : "",
+ arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_ON : "", "Memory",
+ arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_OFF : "",
+ arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Input/s",
+ arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "",
+ arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Output/s",
+ arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "");
for (j = 0; j < n; j++) {
char *p;
g = array[j];
- p = ellipsize(g->path, 37, 33);
- printf("%-37s", p ? p : g->path);
+ p = ellipsize(g->path, path_columns, 33);
+ printf("%-*s", path_columns, p ? p : g->path);
free(p);
if (g->n_tasks_valid)
printf("%s [OPTIONS...]\n\n"
"Show top control groups by their resource usage.\n\n"
" -h --help Show this help\n"
+ " --version Print version and exit\n"
" -p Order by path\n"
" -t Order by number of tasks\n"
" -c Order by CPU load\n"
" -m Order by memory load\n"
" -i Order by IO load\n"
" -d --delay=DELAY Specify delay\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: 2)\n",
program_invocation_short_name);
}
+static void version(void) {
+ puts(PACKAGE_STRING " cgtop");
+}
+
static int parse_argv(int argc, char *argv[]) {
enum {
- ARG_DEPTH = 0x100
+ ARG_VERSION = 0x100,
+ ARG_DEPTH,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "delay", required_argument, NULL, 'd' },
- { "depth", required_argument, NULL, ARG_DEPTH },
- { NULL, 0, NULL, 0 }
+ { "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' },
+ { "depth", required_argument, NULL, ARG_DEPTH },
+ { NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "hptcmid:", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "hptcmin:bd:", options, NULL)) >= 0) {
switch (c) {
help();
return 0;
+ case ARG_VERSION:
+ version();
+ return 0;
+
case ARG_DEPTH:
r = safe_atou(optarg, &arg_depth);
if (r < 0) {
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 'p':
arg_order = ORDER_PATH;
break;
goto finish;
}
+ signal(SIGWINCH, columns_lines_cache_reset);
+
while (!quit) {
Hashmap *c;
usec_t t;
if (r < 0)
goto finish;
- r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL);
- if (r == -ETIMEDOUT)
- continue;
- if (r < 0) {
- log_error("Couldn't read key: %s", strerror(-r));
- goto finish;
+ if (arg_iterations && iteration >= arg_iterations)
+ break;
+
+ if (arg_batch) {
+ 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("Couldn't read key: %s", strerror(-r));
+ goto finish;
+ }
}
fputs("\r \r", stdout);
fflush(stdout);
+ if (arg_batch)
+ continue;
+
switch (key) {
case ' ':
group_hashmap_free(a);
group_hashmap_free(b);
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ if (r < 0) {
+ log_error("Exiting with failure: %s", strerror(-r));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
}