analyze: correctly draw the plot for user instances

Start-up timestamp of a user instance (userspace_time in struct boot_times)
actually may be arbitrarily big. This, because all timestamps are offset by
that value, leads to creation of arbitrarily wide SVGs which almost completely
consist of blank space.

Fix this by inverse-offsetting all timestamps by that value if user instance
operation is requested.

Fixes #740.
This commit is contained in:
Ivan Shapovalov 2015-07-27 19:40:36 +03:00
parent 29b8b5ce87
commit 06bef033be

View file

@ -88,6 +88,18 @@ struct boot_times {
usec_t generators_finish_time;
usec_t unitsload_start_time;
usec_t unitsload_finish_time;
/*
* If we're analyzing the user instance, all timestamps will be offset
* by its own start-up timestamp, which may be arbitrarily big.
* With "plot", this causes arbitrarily wide output SVG files which almost
* completely consist of empty space. Thus we cancel out this offset.
*
* This offset is subtracted from times above by acquire_boot_times(),
* but it still needs to be subtracted from unit-specific timestamps
* (so it is stored here for reference).
*/
usec_t reverse_offset;
};
struct unit_times {
@ -188,6 +200,15 @@ static void free_unit_times(struct unit_times *t, unsigned n) {
free(t);
}
static void subtract_timestamp(usec_t *a, usec_t b) {
assert(a);
if (*a > 0) {
assert(*a >= b);
*a -= b;
}
}
static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
static struct boot_times times;
static bool cached = false;
@ -264,10 +285,30 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
return -EINPROGRESS;
}
if (times.initrd_time)
times.kernel_done_time = times.initrd_time;
else
times.kernel_done_time = times.userspace_time;
if (arg_user) {
/*
* User-instance-specific timestamps processing
* (see comment to reverse_offset in struct boot_times).
*/
times.reverse_offset = times.userspace_time;
times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time = times.userspace_time = 0;
subtract_timestamp(&times.finish_time, times.reverse_offset);
subtract_timestamp(&times.security_start_time, times.reverse_offset);
subtract_timestamp(&times.security_finish_time, times.reverse_offset);
subtract_timestamp(&times.generators_start_time, times.reverse_offset);
subtract_timestamp(&times.generators_finish_time, times.reverse_offset);
subtract_timestamp(&times.unitsload_start_time, times.reverse_offset);
subtract_timestamp(&times.unitsload_finish_time, times.reverse_offset);
} else {
if (times.initrd_time)
times.kernel_done_time = times.initrd_time;
else
times.kernel_done_time = times.userspace_time;
}
cached = true;
@ -291,10 +332,15 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r, c = 0;
struct boot_times *boot_times = NULL;
struct unit_times *unit_times = NULL;
size_t size = 0;
UnitInfo u;
r = acquire_boot_times(bus, &boot_times);
if (r < 0)
goto fail;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@ -347,6 +393,11 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
goto fail;
}
subtract_timestamp(&t->activating, boot_times->reverse_offset);
subtract_timestamp(&t->activated, boot_times->reverse_offset);
subtract_timestamp(&t->deactivating, boot_times->reverse_offset);
subtract_timestamp(&t->deactivated, boot_times->reverse_offset);
if (t->activated >= t->activating)
t->time = t->activated - t->activating;
else if (t->deactivated >= t->activating)
@ -450,10 +501,7 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
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));
else
strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
ptr = strdup(buf);
if (!ptr)