X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbootchart%2Fbootchart.c;h=71dffc9ae8b3a497ee2fc43cf8ca5b1add8958e2;hb=b53a2485a43a59f3a8e45baabac6fc84a53cb3e6;hp=813e38deeb0afc34f1827aa8a2092692bf8c34b0;hpb=1c92ff85b786c423f4436ec26007e79369c9ac05;p=elogind.git diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 813e38dee..71dffc9ae 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -33,10 +33,7 @@ ***/ -#include -#include #include -#include #include #include #include @@ -76,7 +73,7 @@ int sysfd=-1; #define DEFAULT_HZ 25.0 #define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */ #define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */ -#define DEFAULT_INIT "/sbin/init" +#define DEFAULT_INIT ROOTLIBEXECDIR "/systemd" #define DEFAULT_OUTPUT "/run/log" /* graph defaults */ @@ -87,6 +84,7 @@ bool arg_filter = true; bool arg_show_cmdline = false; bool arg_show_cgroup = false; bool arg_pss = false; +bool arg_percpu = false; int samples; int arg_samples_len = DEFAULT_SAMPLES_LEN; /* we record len+1 (1 start sample) */ double arg_hz = DEFAULT_HZ; @@ -122,13 +120,13 @@ static void parse_conf(void) { { "Bootchart", "ScaleX", config_parse_double, 0, &arg_scale_x }, { "Bootchart", "ScaleY", config_parse_double, 0, &arg_scale_y }, { "Bootchart", "ControlGroup", config_parse_bool, 0, &arg_show_cgroup }, + { "Bootchart", "PerCPU", config_parse_bool, 0, &arg_percpu }, { NULL, NULL, NULL, 0, NULL } }; - config_parse(NULL, BOOTCHART_CONF, NULL, - NULL, - config_item_table_lookup, items, - true, false, true, NULL); + config_parse_many(BOOTCHART_CONF, + CONF_DIRS_NULSTR("systemd/bootchart.conf"), + NULL, config_item_table_lookup, items, true, NULL); if (init != NULL) strscpy(arg_init_path, sizeof(arg_init_path), init); @@ -152,6 +150,7 @@ static void help(void) { " -F, --no-filter Disable filtering of unimportant or ephemeral processes\n" " -C, --cmdline Display full command lines with arguments\n" " -c, --control-group Display process control group\n" + " --per-cpu Draw each CPU utilization and wait bar also\n" " -h, --help Display this message\n\n" "See bootchart.conf for more information.\n", program_invocation_short_name, @@ -164,20 +163,26 @@ static void help(void) { } static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_PERCPU = 0x100, + }; + static const struct option options[] = { - {"rel", no_argument, NULL, 'r'}, - {"freq", required_argument, NULL, 'f'}, - {"samples", required_argument, NULL, 'n'}, - {"pss", no_argument, NULL, 'p'}, - {"output", required_argument, NULL, 'o'}, - {"init", required_argument, NULL, 'i'}, - {"no-filter", no_argument, NULL, 'F'}, - {"cmdline", no_argument, NULL, 'C'}, - {"control-group", no_argument, NULL, 'c'}, - {"help", no_argument, NULL, 'h'}, - {"scale-x", required_argument, NULL, 'x'}, - {"scale-y", required_argument, NULL, 'y'}, - {"entropy", no_argument, NULL, 'e'}, + {"rel", no_argument, NULL, 'r' }, + {"freq", required_argument, NULL, 'f' }, + {"samples", required_argument, NULL, 'n' }, + {"pss", no_argument, NULL, 'p' }, + {"output", required_argument, NULL, 'o' }, + {"init", required_argument, NULL, 'i' }, + {"no-filter", no_argument, NULL, 'F' }, + {"cmdline", no_argument, NULL, 'C' }, + {"control-group", no_argument, NULL, 'c' }, + {"help", no_argument, NULL, 'h' }, + {"scale-x", required_argument, NULL, 'x' }, + {"scale-y", required_argument, NULL, 'y' }, + {"entropy", no_argument, NULL, 'e' }, + {"per-cpu", no_argument, NULL, ARG_PERCPU}, {} }; int c, r; @@ -194,8 +199,8 @@ static int parse_argv(int argc, char *argv[]) { case 'f': r = safe_atod(optarg, &arg_hz); if (r < 0) - log_warning("failed to parse --freq/-f argument '%s': %s", - optarg, strerror(-r)); + log_warning_errno(r, "failed to parse --freq/-f argument '%s': %m", + optarg); break; case 'F': arg_filter = false; @@ -209,8 +214,8 @@ static int parse_argv(int argc, char *argv[]) { case 'n': r = safe_atoi(optarg, &arg_samples_len); if (r < 0) - log_warning("failed to parse --samples/-n argument '%s': %s", - optarg, strerror(-r)); + log_warning_errno(r, "failed to parse --samples/-n argument '%s': %m", + optarg); break; case 'o': path_kill_slashes(optarg); @@ -226,18 +231,21 @@ static int parse_argv(int argc, char *argv[]) { case 'x': r = safe_atod(optarg, &arg_scale_x); if (r < 0) - log_warning("failed to parse --scale-x/-x argument '%s': %s", - optarg, strerror(-r)); + log_warning_errno(r, "failed to parse --scale-x/-x argument '%s': %m", + optarg); break; case 'y': r = safe_atod(optarg, &arg_scale_y); if (r < 0) - log_warning("failed to parse --scale-y/-y argument '%s': %s", - optarg, strerror(-r)); + log_warning_errno(r, "failed to parse --scale-y/-y argument '%s': %m", + optarg); break; case 'e': arg_entropy = true; break; + case ARG_PERCPU: + arg_percpu = true; + break; case 'h': help(); return 0; @@ -260,10 +268,11 @@ static int parse_argv(int argc, char *argv[]) { static void do_journal_append(char *file) { struct iovec iovec[5]; - int r, f, j = 0; + int r, j = 0; ssize_t n; _cleanup_free_ char *bootchart_file = NULL, *bootchart_message = NULL, *p = NULL; + _cleanup_close_ int fd = -1; bootchart_file = strappend("BOOTCHART_FILE=", file); if (bootchart_file) @@ -283,18 +292,17 @@ static void do_journal_append(char *file) { memcpy(p, "BOOTCHART=", 10); - f = open(file, O_RDONLY|O_CLOEXEC); - if (f < 0) { - log_error("Failed to read bootchart data: %m"); + fd = open(file, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file); return; } - n = loop_read(f, p + 10, BOOTCHART_MAX, false); + + n = loop_read(fd, p + 10, BOOTCHART_MAX, false); if (n < 0) { - log_error("Failed to read bootchart data: %s", strerror(-n)); - close(f); + log_error_errno(n, "Failed to read bootchart data: %m"); return; } - close(f); iovec[j].iov_base = p; iovec[j].iov_len = 10 + n; @@ -302,7 +310,7 @@ static void do_journal_append(char *file) { r = sd_journal_sendv(iovec, j); if (r < 0) - log_error("Failed to send bootchart: %s", strerror(-r)); + log_error_errno(r, "Failed to send bootchart: %m"); } int main(int argc, char *argv[]) { @@ -327,7 +335,7 @@ int main(int argc, char *argv[]) { /* * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then * fork: - * - parent execs executable specified via init_path[] (/sbin/init by default) as pid=1 + * - parent execs executable specified via init_path[] (/usr/lib/systemd/systemd by default) as pid=1 * - child logs data */ if (getpid() == 1) { @@ -387,15 +395,6 @@ int main(int argc, char *argv[]) { sampledata->sampletime = gettime_ns(); sampledata->counter = samples; - if (!of && (access(arg_output_path, R_OK|W_OK|X_OK) == 0)) { - t = time(NULL); - r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); - assert_se(r > 0); - - snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); - of = fopen(output_file, "we"); - } - if (sysfd < 0) sysfd = open("/sys", O_RDONLY|O_CLOEXEC); @@ -434,7 +433,7 @@ int main(int argc, char *argv[]) { /* caught signal, probably HUP! */ break; } - log_error("nanosleep() failed: %m"); + log_error_errno(errno, "nanosleep() failed: %m"); exit(EXIT_FAILURE); } } else {