analyze.c revision b5cfa7408c4cb68e9bb232fc34b07fd03c915617
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering This file is part of systemd.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Copyright 2010-2013 Lennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers Copyright 2013 Simon Peeters
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is free software; you can redistribute it and/or modify it
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering under the terms of the GNU Lesser General Public License as published by
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (at your option) any later version.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is distributed in the hope that it will be useful, but
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Lesser General Public License for more details.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering You should have received a copy of the GNU Lesser General Public License
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#define SCALE_X (0.1 / 1000.0) /* pixels per us */
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <rect class=\"%s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart 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); \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering } while(false)
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic enum dot {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic bool arg_no_pager = false;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sieversstatic bool arg_user = false;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poetteringstatic void pager_open_if_enabled(void) {
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landdenstatic int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek r = sd_bus_get_property_trivial(
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmekstatic int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
b90930c73b1c82a3dc4d4f2603799993f042aaffLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen log_error("Failed to get unit property %s: %s", property, bus_error_message(&error, -r));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic int compare_unit_time(const void *a, const void *b) {
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic int compare_unit_start(const void *a, const void *b) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return compare(((struct unit_times *)a)->activating,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen ((struct unit_times *)b)->activating);
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering r = parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &n, NULL);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic void free_unit_times(struct unit_times *t, unsigned n) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen for (p = t; p < t + n; p++)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int acquire_time_data(sd_bus *bus, struct unit_times **out) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "org.freedesktop.systemd1.Manager",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen log_error("Failed to list units: %s", bus_error_message(&error, -r));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering while ((r = bus_parse_unit_info(reply, &u)) > 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!GREEDY_REALLOC(unit_times, size, c+1)) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen assert_cc(sizeof(usec_t) == sizeof(uint64_t));
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (bus_get_uint64_property(bus, u.unit_path,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "InactiveExitTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus, u.unit_path,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "ActiveEnterTimestampMonotonic",
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering bus_get_uint64_property(bus, u.unit_path,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "ActiveExitTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus, u.unit_path,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "InactiveEnterTimestampMonotonic",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->time = t->activated - t->activating;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen else if (t->deactivated >= t->activating)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->time = t->deactivated - t->activating;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free_unit_times(unit_times, (unsigned) c);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersenstatic int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen static struct boot_times times;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen static bool cached = false;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering assert_cc(sizeof(usec_t) == sizeof(uint64_t));
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (bus_get_uint64_property(bus,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "FirmwareTimestampMonotonic",
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "LoaderTimestampMonotonic",
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering "org.freedesktop.systemd1.Manager",
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt "KernelTimestamp",
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "InitRDTimestampMonotonic",
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering "UserspaceTimestampMonotonic",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "FinishTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Manager",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "SecurityStartTimestampMonotonic",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew JÄ™drzejewski-Szmek ×.security_start_time) < 0 ||
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
3906ab4adf0aa7b952e39100262a11acd55cd79bRonny Chevalier "SecurityFinishTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "GeneratorsStartTimestampMonotonic",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "GeneratorsFinishTimestampMonotonic",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "org.freedesktop.systemd1.Manager",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "UnitsLoadStartTimestampMonotonic",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "org.freedesktop.systemd1.Manager",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "UnitsLoadFinishTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("Bootup is not yet finished. Please try again later.");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering times.kernel_done_time = times.initrd_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering times.kernel_done_time = times.userspace_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int pretty_boot_time(sd_bus *bus, char **_buf) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen char ts[FORMAT_TIMESPAN_MAX];
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = acquire_boot_times(bus, &t);
c978343015c787713651dff571acb5207367f5f2Lennart Poettering size = strpcpyf(&ptr, size, "Startup finished in ");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic void svg_graph_box(double height, double begin, double end) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* outside box, fill */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen svg("<rect class=\"box\" x=\"0\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * (end - begin), SCALE_Y * height);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* lines for each second */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (i % 5000000 == 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering else if (i % 1000000 == 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int n, m = 1, y=0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_free_ char *pretty_times = NULL, *osname = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering n = pretty_boot_time(bus, &pretty_times);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering qsort(times, n, sizeof(struct unit_times), compare_unit_start);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering width = SCALE_X * (boot->firmware_time + boot->finish_time);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (boot->firmware_time > boot->loader_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (u->activating < boot->userspace_time ||
249968612f16a71df909d6e73785c18a9ff36a65Lennart Poettering /* If the text cannot fit on the left side then
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering * increase the svg width so it fits on the right.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * TODO: calculate the text width more accurately */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering text_start = (boot->firmware_time + u->activating) * SCALE_X;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (text_width > text_start && text_width + text_start > width)
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering if (u->deactivated > u->activating && u->deactivated <= boot->finish_time
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering && u->activated == 0 && u->deactivating == 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering u->activated = u->deactivating = u->deactivated;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (u->activated < u->activating || u->activated > boot->finish_time)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen u->activated = boot->finish_time;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (u->deactivating < u->activated || u->activated > boot->finish_time)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen u->deactivating = boot->finish_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg("<?xml version=\"1.0\" standalone=\"no\"?>\n"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
"xmlns=\"http://www.w3.org/2000/svg\">\n\n",
" rect.security { fill: rgb(144,238,144); fill-opacity: 0.7; }\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 -ENOMEM;
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 -ENOMEM;
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Unit",
&error,
&reply,
return bus_log_parse_error(r);
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 UnitInfo *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);
UnitInfo u;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&error,
&reply,
return bus_log_parse_error(r);
return bus_log_parse_error(r);
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,
return bus_log_parse_error(r);
return -E2BIG;
r = sd_bus_set_property(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&error,
args[0]);
return -EIO;
static int help(void) {
* changes to shell-completion/bash/systemd and
* shell-completion/systemd-zsh-completion.zsh too. */
return help();
case ARG_VERSION:
case ARG_USER:
arg_user = true;
case ARG_SYSTEM:
arg_user = false;
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();