diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index ac5c05dd87..b723ebf9bd 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -88,6 +88,12 @@ struct boot_times {
usec_t generators_finish_time;
usec_t unitsload_start_time;
usec_t unitsload_finish_time;
+ usec_t initrd_security_start_time;
+ usec_t initrd_security_finish_time;
+ usec_t initrd_generators_start_time;
+ usec_t initrd_generators_finish_time;
+ usec_t initrd_unitsload_start_time;
+ usec_t initrd_unitsload_finish_time;
/*
* If we're analyzing the user instance, all timestamps will be offset
@@ -289,6 +295,37 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
×.unitsload_finish_time) < 0)
return -EIO;
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDSecurityStartTimestampMonotonic",
+ ×.initrd_security_start_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDSecurityFinishTimestampMonotonic",
+ ×.initrd_security_finish_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDGeneratorsStartTimestampMonotonic",
+ ×.initrd_generators_start_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDGeneratorsFinishTimestampMonotonic",
+ ×.initrd_generators_finish_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDUnitsLoadStartTimestampMonotonic",
+ ×.initrd_unitsload_start_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDUnitsLoadFinishTimestampMonotonic",
+ ×.initrd_unitsload_finish_time);
+
if (times.finish_time <= 0) {
log_error("Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
"Please try again later.\n"
@@ -453,6 +490,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL;
_cleanup_(free_host_infop) struct host_info *host;
int r;
@@ -460,7 +498,15 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
if (!host)
return log_oom();
- r = bus_map_all_properties(bus,
+ if (arg_scope != UNIT_FILE_SYSTEM) {
+ r = bus_connect_transport(arg_transport, arg_host, false, &system_bus);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to connect to system bus, ignoring: %m");
+ goto manager;
+ }
+ }
+
+ r = bus_map_all_properties(system_bus ?: bus,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
hostname_map,
@@ -468,9 +514,12 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
&error,
NULL,
host);
- if (r < 0)
- log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s", bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+manager:
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
@@ -543,14 +592,14 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
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->firmware_time + t->finish_time, USEC_PER_MSEC));
if (unit_id && activated_time > 0 && activated_time != USEC_INFINITY)
size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id, format_timespan(ts, sizeof(ts), activated_time - t->userspace_time, USEC_PER_MSEC));
else if (unit_id && activated_time == 0)
size = strpcpyf(&ptr, size, "\n%s was never reached", unit_id);
else if (unit_id && activated_time == USEC_INFINITY)
- size = strpcpyf(&ptr, size, "\nCould not get time to reach %s.",unit_id);
+ size = strpcpyf(&ptr, size, "\nCould not get time to reach %s.", unit_id);
else if (!unit_id)
size = strpcpyf(&ptr, size, "\ncould not find default.target");
@@ -585,16 +634,38 @@ static void svg_graph_box(double height, double begin, double end) {
}
}
+static int plot_unit_times(struct unit_times *u, double width, int y) {
+ char ts[FORMAT_TIMESPAN_MAX];
+ bool b;
+
+ if (!u->name)
+ return 0;
+
+ svg_bar("activating", u->activating, u->activated, y);
+ svg_bar("active", u->activated, u->deactivating, y);
+ svg_bar("deactivating", u->deactivating, u->deactivated, y);
+
+ /* place the text on the left if we have passed the half of the svg width */
+ b = u->activating * SCALE_X < width / 2;
+ if (u->time)
+ svg_text(b, u->activating, y, "%s (%s)",
+ u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
+ else
+ svg_text(b, u->activating, y, "%s", u->name);
+
+ return 1;
+}
+
static int analyze_plot(int argc, char *argv[], void *userdata) {
_cleanup_(free_host_infop) struct host_info *host = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(unit_times_freep) struct unit_times *times = NULL;
- struct boot_times *boot;
- int n, m = 1, y = 0, r;
- bool use_full_bus = true;
- double width;
_cleanup_free_ char *pretty_times = NULL;
+ bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM;
+ struct boot_times *boot;
struct unit_times *u;
+ int n, m = 1, y = 0, r;
+ double width;
r = acquire_bus(&bus, &use_full_bus);
if (r < 0)
@@ -608,7 +679,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
if (n < 0)
return n;
- if (use_full_bus) {
+ if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) {
n = acquire_host_info(bus, &host);
if (n < 0)
return n;
@@ -639,8 +710,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
for (u = times; u->has_data; u++) {
double text_start, text_width;
- if (u->activating < boot->userspace_time ||
- u->activating > boot->finish_time) {
+ if (u->activating > boot->finish_time) {
u->name = mfree(u->name);
continue;
}
@@ -711,7 +781,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
svg("\n");
svg("%s", pretty_times);
- if (use_full_bus)
+ if (host)
svg("%s %s (%s %s %s) %s %s",
isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
strempty(host->hostname),
@@ -741,9 +811,23 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
}
if (boot->initrd_time > 0) {
svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
+ if (boot->initrd_security_start_time < boot->initrd_security_finish_time)
+ svg_bar("security", boot->initrd_security_start_time, boot->initrd_security_finish_time, y);
+ if (boot->initrd_generators_start_time < boot->initrd_generators_finish_time)
+ svg_bar("generators", boot->initrd_generators_start_time, boot->initrd_generators_finish_time, y);
+ if (boot->initrd_unitsload_start_time < boot->initrd_unitsload_finish_time)
+ svg_bar("unitsload", boot->initrd_unitsload_start_time, boot->initrd_unitsload_finish_time, y);
svg_text(true, boot->initrd_time, y, "initrd");
y++;
}
+
+ for (u = times; u->has_data; u++) {
+ if (u->activating >= boot->userspace_time)
+ break;
+
+ y += plot_unit_times(u, width, y);
+ }
+
svg_bar("active", boot->userspace_time, boot->finish_time, y);
svg_bar("security", boot->security_start_time, boot->security_finish_time, y);
svg_bar("generators", boot->generators_start_time, boot->generators_finish_time, y);
@@ -751,26 +835,8 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
svg_text(true, boot->userspace_time, y, "systemd");
y++;
- for (u = times; u->has_data; u++) {
- char ts[FORMAT_TIMESPAN_MAX];
- bool b;
-
- if (!u->name)
- continue;
-
- svg_bar("activating", u->activating, u->activated, y);
- svg_bar("active", u->activated, u->deactivating, y);
- svg_bar("deactivating", u->deactivating, u->deactivated, y);
-
- /* place the text on the left if we have passed the half of the svg width */
- b = u->activating * SCALE_X < width / 2;
- if (u->time)
- svg_text(b, u->activating, y, "%s (%s)",
- u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
- else
- svg_text(b, u->activating, y, "%s", u->name);
- y++;
- }
+ for (; u->has_data; u++)
+ y += plot_unit_times(u, width, y);
svg("\n");
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 4c0f79b983..c2f82e19de 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2418,6 +2418,12 @@ const sd_bus_vtable bus_manager_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_GENERATORS_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_START]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDSecurityStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_SECURITY_START]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDSecurityFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDGeneratorsStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_START]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDGeneratorsFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDUnitsLoadStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDUnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
SD_BUS_PROPERTY("NNames", "u", property_get_hashmap_size, offsetof(Manager, units), 0),
diff --git a/src/core/main.c b/src/core/main.c
index b7e98502eb..0e92f70a24 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2373,8 +2373,8 @@ int main(int argc, char *argv[]) {
m->timestamps[MANAGER_TIMESTAMP_KERNEL] = kernel_timestamp;
m->timestamps[MANAGER_TIMESTAMP_INITRD] = initrd_timestamp;
m->timestamps[MANAGER_TIMESTAMP_USERSPACE] = userspace_timestamp;
- m->timestamps[MANAGER_TIMESTAMP_SECURITY_START] = security_start_timestamp;
- m->timestamps[MANAGER_TIMESTAMP_SECURITY_FINISH] = security_finish_timestamp;
+ m->timestamps[manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_SECURITY_START)] = security_start_timestamp;
+ m->timestamps[manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_SECURITY_FINISH)] = security_finish_timestamp;
set_manager_defaults(m);
set_manager_settings(m);
diff --git a/src/core/manager.c b/src/core/manager.c
index 1d177008e5..8dc3f5e55f 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1555,9 +1555,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_GENERATORS_START);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START));
r = manager_run_generators(m);
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_GENERATORS_FINISH);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_FINISH));
if (r < 0)
return r;
@@ -1572,10 +1572,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->n_reloading++;
/* First, enumerate what we can from all config files */
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_UNITS_LOAD_START));
manager_enumerate_perpetual(m);
manager_enumerate(m);
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_UNITS_LOAD_FINISH));
/* Second, deserialize if there is something to deserialize */
if (serialization) {
@@ -3026,8 +3026,12 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "log-target-override=%s\n", log_target_to_string(log_get_target()));
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
- /* The userspace and finish timestamps only apply to the host system, hence only serialize them there */
- if (in_initrd() && IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH))
+ /* The following timestamps only apply to the host system, hence only serialize them there */
+ if (in_initrd() &&
+ IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
+ MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
+ MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
+ MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH))
continue;
t = manager_timestamp_to_string(q);
@@ -4527,6 +4531,14 @@ void manager_restore_original_log_target(Manager *m) {
m->log_target_overridden = false;
}
+ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s) {
+ if (in_initrd() &&
+ s >= MANAGER_TIMESTAMP_SECURITY_START &&
+ s <= MANAGER_TIMESTAMP_UNITS_LOAD_FINISH)
+ return s - MANAGER_TIMESTAMP_SECURITY_START + MANAGER_TIMESTAMP_INITRD_SECURITY_START;
+ return s;
+}
+
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
@@ -4551,6 +4563,12 @@ static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
[MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
[MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
+ [MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start",
+ [MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish",
+ [MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start",
+ [MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH] = "initrd-generators-finish",
+ [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start",
+ [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH] = "initrd-units-load-finish",
};
DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp);
diff --git a/src/core/manager.h b/src/core/manager.h
index ea5d425030..342258fcf9 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -67,6 +67,13 @@ typedef enum ManagerTimestamp {
MANAGER_TIMESTAMP_GENERATORS_FINISH,
MANAGER_TIMESTAMP_UNITS_LOAD_START,
MANAGER_TIMESTAMP_UNITS_LOAD_FINISH,
+
+ MANAGER_TIMESTAMP_INITRD_SECURITY_START,
+ MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH,
+ MANAGER_TIMESTAMP_INITRD_GENERATORS_START,
+ MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH,
+ MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START,
+ MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH,
_MANAGER_TIMESTAMP_MAX,
_MANAGER_TIMESTAMP_INVALID = -1,
} ManagerTimestamp;
@@ -479,3 +486,4 @@ void manager_disable_confirm_spawn(void);
const char *manager_timestamp_to_string(ManagerTimestamp m) _const_;
ManagerTimestamp manager_timestamp_from_string(const char *s) _pure_;
+ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);