analyze.c revision 07d0eaa0171d6e30b85a4b84b3287509406f9451
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering This file is part of systemd.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Copyright 2010-2013 Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Copyright 2013 Simon Peeters
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering systemd is free software; you can redistribute it and/or modify it
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering under the terms of the GNU Lesser General Public License as published by
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (at your option) any later version.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering systemd is distributed in the hope that it will be useful, but
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Lesser General Public License for more details.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering You should have received a copy of the GNU Lesser General Public License
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering#define SCALE_X (0.1 / 1000.0) /* pixels per us */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering svg(" <rect class=\"%s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", \
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering svg(" <text class=\"%s\" x=\"%.03f\" y=\"%.03f\">", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering } while(false)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic char** arg_dot_from_patterns = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic bool arg_no_pager = false;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic void pager_open_if_enabled(void) {
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poetteringstatic int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int compare_unit_time(const void *a, const void *b) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return compare(((struct unit_times *)b)->time,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int compare_unit_start(const void *a, const void *b) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return compare(((struct unit_times *)a)->activating,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &n, NULL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic void free_unit_times(struct unit_times *t, unsigned n) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering for (p = t; p < t + n; p++)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int bus_parse_unit_info(sd_bus_message *message, struct unit_info *u) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_bus_message_read(message, "(ssssssouso)", &u->id,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_error("Failed to parse message as unit_info.");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int bus_get_unit_property_strv(sd_bus *bus, const char *unit_path, const char *prop, char ***strv) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering const char *s;
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering log_error("Failed to get unit property: %s %s", prop, bus_error_message(&error, -r));
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering while ((r = sd_bus_message_read(reply, "s", &s)) > 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int acquire_time_data(sd_bus *bus, struct unit_times **out) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering int r, c = 0, n_units = 0;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering "org.freedesktop.systemd1.Manager",
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering while ((r = bus_parse_unit_info(reply, &u)) > 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering w = realloc(unit_times, sizeof(struct unit_times) * n_units);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_cc(sizeof(usec_t) == sizeof(uint64_t));
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (bus_get_uint64_property(bus, u.unit_path,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering "InactiveExitTimestampMonotonic",
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering bus_get_uint64_property(bus, u.unit_path,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering "ActiveEnterTimestampMonotonic",
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering bus_get_uint64_property(bus, u.unit_path,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering "ActiveExitTimestampMonotonic",
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering bus_get_uint64_property(bus, u.unit_path,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering "InactiveEnterTimestampMonotonic",
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering else if (t->deactivated >= t->activating)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering t->time = t->deactivated - t->activating;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering free_unit_times(unit_times, (unsigned) c);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
ce30c8dcb41dfe9264f79f30c7f51c0e74576638Lennart Poettering static bool cached = false;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_cc(sizeof(usec_t) == sizeof(uint64_t));
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
return -EIO;
return -EAGAIN;
cached = true;
struct boot_times *t;
char *ptr;
if (t->firmware_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, USEC_PER_MSEC));
if (t->kernel_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, USEC_PER_MSEC));
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)
strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
if (!ptr)
return log_oom();
double width;
struct unit_times *u;
"xmlns=\"http://www.w3.org/2000/svg\">\n\n",
"// line.sec1 { }\n"
" line.sec5 { stroke-width: 2; }\n"
" line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n"
" text.sec { font-size: 10px; }\n"
if (!u->name)
if (u->time)
for (i = level; i != 0; i--)
if (times) {
printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
return -EINVAL;
if (times)
if (times)
unsigned int branches) {
int to_print = 0;
return log_oom();
if (times
|| service_longest == 0)) {
if (service_longest == 0 )
to_print++;
if(!to_print)
if (!times
to_print--;
if (!to_print)
return -EINVAL;
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Unit",
&error,
&reply,
if (times) {
printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
Hashmap *h;
return -ENOMEM;
unit_times_hashmap = h;
char **name;
hashmap_free(h);
static int graph_one_property(sd_bus *bus, const struct unit_info *u, const char* prop, const char *color, char* patterns[]) {
char **unit;
assert(u);
bool match_found;
match_found = false;
match_found = true;
if (!match_found)
match_found = false;
match_found = true;
if (!match_found)
match_found = false;
match_found = true;
if (!match_found)
assert(u);
struct unit_info u;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&error,
&reply,
if (on_tty())
"-- Try a shell pipeline like 'systemd-analyze dot | dot -Tsvg > systemd.svg'!\n");
return -E2BIG;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&error,
&reply,
const char* value;
return -E2BIG;
r = sd_bus_set_property(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&error,
value);
return -EIO;
static void analyze_help(void) {
* changes to shell-completion/bash/systemd and
* shell-completion/systemd-zsh-completion.zsh too. */
analyze_help();
case ARG_VERSION:
case ARG_USER:
case ARG_SYSTEM:
case ARG_ORDER:
case ARG_REQUIRE:
case ARG_DOT_FROM_PATTERN:
return log_oom();
case ARG_DOT_TO_PATTERN:
return log_oom();
case ARG_FUZZ:
case ARG_NO_PAGER:
arg_no_pager = true;
return -EINVAL;
log_open();
goto finish;
goto finish;
pager_close();