X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fanalyze%2Fsystemd-analyze.c;h=e648a4449f04cb03622b5c4cf0728034dc4a6680;hb=d3b6d0c21ea5a0d15ec6dbd8b8d179138b7463bc;hp=762016d61686e4eace30a415dc6f6b2fedde5439;hpb=c170f3a41bc69ad1eab2dba40cede865f2532bbc;p=elogind.git diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c index 762016d61..e648a4449 100644 --- a/src/analyze/systemd-analyze.c +++ b/src/analyze/systemd-analyze.c @@ -3,7 +3,8 @@ /*** This file is part of systemd. - Copyright 2010 Lennart Poettering + Copyright 2010-2013 Lennart Poettering + Copyright 2013 Simon Peeters systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -24,6 +25,7 @@ #include #include #include +#include #include "install.h" #include "log.h" @@ -32,6 +34,10 @@ #include "util.h" #include "strxcpyx.h" #include "fileio.h" +#include "strv.h" + +#define SCALE_X (0.1 / 1000.0) /* pixels per us */ +#define SCALE_Y 20.0 #define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0)) @@ -40,12 +46,12 @@ #define svg_bar(class, x1, x2, y) \ svg(" \n", \ (class), \ - scale_x * (x1), scale_y * (y), \ - scale_x * ((x2) - (x1)), scale_y - 1.0) + SCALE_X * (x1), SCALE_Y * (y), \ + SCALE_X * ((x2) - (x1)), SCALE_Y - 1.0) #define svg_text(b, x, y, format, ...) \ do { \ - svg(" ", (b) ? "left" : "right", scale_x * (x) + (b ? 5.0 : -5.0), scale_y * (y) + 14.0); \ + svg(" ", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \ svg(format, ## __VA_ARGS__); \ svg("\n"); \ } while(false) @@ -56,9 +62,8 @@ static enum dot { DEP_ORDER, DEP_REQUIRE } arg_dot = DEP_ALL; - -static double scale_x = 0.1 / 1000.0; /* pixels per us */ -static double scale_y = 20.0; +static char** arg_dot_from_patterns = NULL; +static char** arg_dot_to_patterns = NULL; struct boot_times { usec_t firmware_time; @@ -330,19 +335,19 @@ static int pretty_boot_time(DBusConnection *bus, char **_buf) { size = strpcpyf(&ptr, size, "Startup finished in "); if (t->firmware_time) - size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time)); + size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC)); if (t->loader_time) - size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time)); + size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC)); if (t->kernel_time) - size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time)); + size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC)); if (t->initrd_time > 0) - size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time)); + size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC)); - size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time)); + size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC)); if (t->kernel_time > 0) - size = strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time)); + size = strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC)); else - size = strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time)); + size = strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC)); ptr = strdup(buf); if (!ptr) @@ -357,21 +362,21 @@ static void svg_graph_box(double height, double begin, double end) { /* outside box, fill */ svg("\n", - scale_x * (end - begin), scale_y * height); + SCALE_X * (end - begin), SCALE_Y * height); for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) { /* lines for each second */ if (i % 5000000 == 0) svg(" \n" " %.01fs\n", - scale_x * i, scale_x * i, scale_y * height, scale_x * i, -5.0, 0.000001 * i); + SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i); else if (i % 1000000 == 0) svg(" \n" " %.01fs\n", - scale_x * i, scale_x * i, scale_y * height, scale_x * i, -5.0, 0.000001 * i); + SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i); else svg(" \n", - scale_x * i, scale_x * i, scale_y * height); + SCALE_X * i, SCALE_X * i, SCALE_Y * height); } } @@ -401,7 +406,7 @@ static int analyze_plot(DBusConnection *bus) { qsort(times, n, sizeof(struct unit_times), compare_unit_start); - width = scale_x * (boot->firmware_time + boot->finish_time); + width = SCALE_X * (boot->firmware_time + boot->finish_time); if (width < 800.0) width = 800.0; @@ -426,7 +431,7 @@ static int analyze_plot(DBusConnection *bus) { u->name = NULL; continue; } - len = ((boot->firmware_time + u->ixt) * scale_x) + len = ((boot->firmware_time + u->ixt) * SCALE_X) + (10.0 * strlen(u->name)); if (len > width) width = len; @@ -449,7 +454,7 @@ static int analyze_plot(DBusConnection *bus) { svg("\n\n", - 80.0 + width, 150.0 + (m * scale_y)); + 80.0 + width, 150.0 + (m * SCALE_Y)); /* write some basic info as a comment, including some help */ svg("\n" @@ -486,9 +491,9 @@ static int analyze_plot(DBusConnection *bus) { isempty(osname) ? "Linux" : osname, name.nodename, name.release, name.version, name.machine); svg("Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", - 120.0 + (m *scale_y)); + 120.0 + (m *SCALE_Y)); - svg("\n", 20.0 + (scale_x * boot->firmware_time)); + svg("\n", 20.0 + (SCALE_X * boot->firmware_time)); svg_graph_box(m, -boot->firmware_time, boot->finish_time); if (boot->firmware_time) { @@ -517,6 +522,7 @@ static int analyze_plot(DBusConnection *bus) { for (u = times; u < times + n; u++) { char ts[FORMAT_TIMESPAN_MAX]; + bool b; if (!u->name) continue; @@ -525,10 +531,12 @@ static int analyze_plot(DBusConnection *bus) { svg_bar("active", u->aet, u->axt, y); svg_bar("deactivating", u->axt, u->iet, y); - if (u->ixt * scale_x > width * 2 / 3) - svg_text(false, u->ixt, y, u->time? "%s (%s)" : "%s", u->name, format_timespan(ts, sizeof(ts), u->time)); + b = u->ixt * SCALE_X > width * 2 / 3; + if (u->time) + svg_text(b, u->ixt, y, "%s (%s)", + u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC)); else - svg_text(true, u->ixt, y, u->time? "%s (%s)" : "%s", u->name, format_timespan(ts, sizeof(ts), u->time)); + svg_text(b, u->ixt, y, "%s", u->name); y++; } svg("\n\n"); @@ -555,7 +563,7 @@ static int analyze_blame(DBusConnection *bus) { char ts[FORMAT_TIMESPAN_MAX]; if (times[i].time > 0) - printf("%16s %s\n", format_timespan(ts, sizeof(ts), times[i].time), times[i].name); + printf("%16s %s\n", format_timespan(ts, sizeof(ts), times[i].time, USEC_PER_MSEC), times[i].name); } free_unit_times(times, (unsigned) n); @@ -574,7 +582,7 @@ static int analyze_time(DBusConnection *bus) { return 0; } -static int graph_one_property(const char *name, const char *prop, DBusMessageIter *iter) { +static int graph_one_property(const char *name, const char *prop, DBusMessageIter *iter, char* patterns[]) { static const char * const colors[] = { "Requires", "[color=\"black\"]", @@ -617,9 +625,50 @@ static int graph_one_property(const char *name, const char *prop, DBusMessageIte dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID; dbus_message_iter_next(&sub)) { const char *s; + char **p; + bool match_found; assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); dbus_message_iter_get_basic(&sub, &s); + + if (!strv_isempty(arg_dot_from_patterns)) { + match_found = false; + + STRV_FOREACH(p, arg_dot_from_patterns) + if (fnmatch(*p, name, 0) == 0) { + match_found = true; + break; + } + + if (!match_found) + continue; + } + + if (!strv_isempty(arg_dot_to_patterns)) { + match_found = false; + + STRV_FOREACH(p, arg_dot_to_patterns) + if (fnmatch(*p, s, 0) == 0) { + match_found = true; + break; + } + + if (!match_found) + continue; + } + + if (!strv_isempty(patterns)) { + match_found = false; + + STRV_FOREACH(p, patterns) + if (fnmatch(*p, name, 0) == 0 || fnmatch(*p, s, 0) == 0) { + match_found = true; + break; + } + if (!match_found) + continue; + } + printf("\t\"%s\"->\"%s\" %s;\n", name, s, c); } } @@ -627,7 +676,7 @@ static int graph_one_property(const char *name, const char *prop, DBusMessageIte return 0; } -static int graph_one(DBusConnection *bus, const struct unit_info *u) { +static int graph_one(DBusConnection *bus, const struct unit_info *u, char *patterns[]) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; const char *interface = "org.freedesktop.systemd1.Unit"; int r; @@ -671,7 +720,7 @@ static int graph_one(DBusConnection *bus, const struct unit_info *u) { } dbus_message_iter_recurse(&sub2, &sub3); - r = graph_one_property(u->id, prop, &sub3); + r = graph_one_property(u->id, prop, &sub3, patterns); if (r < 0) return r; } @@ -679,7 +728,7 @@ static int graph_one(DBusConnection *bus, const struct unit_info *u) { return 0; } -static int dot(DBusConnection *bus) { +static int dot(DBusConnection *bus, char* patterns[]) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub; int r; @@ -714,7 +763,7 @@ static int dot(DBusConnection *bus) { if (r < 0) return -EIO; - r = graph_one(bus, &u); + r = graph_one(bus, &u, patterns); if (r < 0) return r; } @@ -743,7 +792,10 @@ static void analyze_help(void) " --system Connect to system manager\n" " --user Connect to user service manager\n" " --order When generating a dependency graph, show only order\n" - " --require When generating a dependency graph, show only requirement\n\n" + " --require When generating a dependency graph, show only requirement\n" + " --from-pattern=GLOB, --to-pattern=GLOB\n" + " When generating a dependency graph, filter only origins\n" + " or destinations, respectively\n\n" "Commands:\n" " time Print time spent in the kernel before reaching userspace\n" " blame Print list of running units ordered by time to init\n" @@ -759,7 +811,9 @@ static int parse_argv(int argc, char *argv[]) ARG_ORDER, ARG_REQUIRE, ARG_USER, - ARG_SYSTEM + ARG_SYSTEM, + ARG_DOT_FROM_PATTERN, + ARG_DOT_TO_PATTERN }; static const struct option options[] = { @@ -769,6 +823,8 @@ static int parse_argv(int argc, char *argv[]) { "require", no_argument, NULL, ARG_REQUIRE }, { "user", no_argument, NULL, ARG_USER }, { "system", no_argument, NULL, ARG_SYSTEM }, + { "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN}, + { "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN }, { NULL, 0, NULL, 0 } }; @@ -802,6 +858,18 @@ static int parse_argv(int argc, char *argv[]) arg_dot = DEP_REQUIRE; break; + case ARG_DOT_FROM_PATTERN: + if (strv_extend(&arg_dot_from_patterns, optarg) < 0) + return log_oom(); + + break; + + case ARG_DOT_TO_PATTERN: + if (strv_extend(&arg_dot_to_patterns, optarg) < 0) + return log_oom(); + + break; + case -1: return 1; @@ -840,10 +908,12 @@ int main(int argc, char *argv[]) { else if (streq(argv[optind], "plot")) r = analyze_plot(bus); else if (streq(argv[optind], "dot")) - r = dot(bus); + r = dot(bus, argv+optind+1); else log_error("Unknown operation '%s'.", argv[optind]); + strv_free(arg_dot_from_patterns); + strv_free(arg_dot_to_patterns); dbus_connection_unref(bus); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;