mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 18:23:32 +08:00
Merge pull request #29391 from lf-/jade/analyze-plot-tooltips
analyze: add tooltips with dependency information to "plot"
This commit is contained in:
commit
723ce80602
6
NEWS
6
NEWS
@ -60,6 +60,12 @@ CHANGES WITH 255 in spe:
|
||||
is now dropped, as it never worked, hence it should not be used by
|
||||
anyone.
|
||||
|
||||
Changes in systemd-analyze:
|
||||
|
||||
* "systemd-analyze plot" has gained tooltips on each unit name with
|
||||
related-unit information in its svg output, such as Before=,
|
||||
Requires=, and similar properties.
|
||||
|
||||
CHANGES WITH 254:
|
||||
|
||||
Announcements of Future Feature Removals and Incompatible Changes:
|
||||
|
@ -1,13 +1,15 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "analyze.h"
|
||||
#include "analyze-plot.h"
|
||||
#include "analyze-time-data.h"
|
||||
#include "analyze.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-map-properties.h"
|
||||
#include "format-table.h"
|
||||
#include "os-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "strv.h"
|
||||
#include "unit-def.h"
|
||||
#include "version.h"
|
||||
|
||||
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
|
||||
@ -158,12 +160,32 @@ static void svg_graph_box(double height, double begin, double end) {
|
||||
SCALE_Y * height);
|
||||
}
|
||||
}
|
||||
|
||||
static void plot_tooltip(const UnitTimes *ut) {
|
||||
assert(ut);
|
||||
assert(ut->name);
|
||||
|
||||
svg("%s:\n", ut->name);
|
||||
|
||||
UnitDependency i;
|
||||
VA_ARGS_FOREACH(i, UNIT_AFTER, UNIT_BEFORE, UNIT_REQUIRES, UNIT_REQUISITE, UNIT_WANTS, UNIT_CONFLICTS, UNIT_UPHOLDS)
|
||||
if (!strv_isempty(ut->deps[i])) {
|
||||
svg("\n%s:\n", unit_dependency_to_string(i));
|
||||
STRV_FOREACH(s, ut->deps[i])
|
||||
svg(" %s\n", *s);
|
||||
}
|
||||
}
|
||||
|
||||
static int plot_unit_times(UnitTimes *u, double width, int y) {
|
||||
bool b;
|
||||
|
||||
if (!u->name)
|
||||
return 0;
|
||||
|
||||
svg("<g>\n");
|
||||
svg("<title>");
|
||||
plot_tooltip(u);
|
||||
svg("</title>\n");
|
||||
svg_bar("activating", u->activating, u->activated, y);
|
||||
svg_bar("active", u->activated, u->deactivating, y);
|
||||
svg_bar("deactivating", u->deactivating, u->deactivated, y);
|
||||
@ -175,6 +197,7 @@ static int plot_unit_times(UnitTimes *u, double width, int y) {
|
||||
u->name, FORMAT_TIMESPAN(u->time, USEC_PER_MSEC));
|
||||
else
|
||||
svg_text(b, u->activating, y, "%s", u->name);
|
||||
svg("</g>\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -220,7 +243,7 @@ static int produce_plot_as_svg(
|
||||
double text_start, text_width;
|
||||
|
||||
if (u->activating > boot->finish_time) {
|
||||
u->name = mfree(u->name);
|
||||
unit_times_clear(u);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "analyze.h"
|
||||
#include "analyze-time-data.h"
|
||||
#include "analyze.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "bus-map-properties.h"
|
||||
#include "bus-unit-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "special.h"
|
||||
#include "strv.h"
|
||||
|
||||
static void subtract_timestamp(usec_t *a, usec_t b) {
|
||||
assert(a);
|
||||
@ -215,22 +217,41 @@ int pretty_boot_time(sd_bus *bus, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unit_times_clear(UnitTimes *t) {
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
FOREACH_ARRAY(d, t->deps, ELEMENTSOF(t->deps))
|
||||
*d = strv_free(*d);
|
||||
|
||||
t->name = mfree(t->name);
|
||||
}
|
||||
|
||||
UnitTimes* unit_times_free_array(UnitTimes *t) {
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
for (UnitTimes *p = t; p->has_data; p++)
|
||||
free(p->name);
|
||||
unit_times_clear(p);
|
||||
|
||||
return mfree(t);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UnitTimes*, unit_times_clear, NULL);
|
||||
|
||||
int acquire_time_data(sd_bus *bus, bool require_finished, UnitTimes **out) {
|
||||
static const struct bus_properties_map property_map[] = {
|
||||
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activating) },
|
||||
{ "ActiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activated) },
|
||||
{ "ActiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, deactivating) },
|
||||
{ "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, deactivated) },
|
||||
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activating) },
|
||||
{ "ActiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activated) },
|
||||
{ "ActiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, deactivating) },
|
||||
{ "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, deactivated) },
|
||||
{ "After", "as", NULL, offsetof(UnitTimes, deps[UNIT_AFTER]) },
|
||||
{ "Before", "as", NULL, offsetof(UnitTimes, deps[UNIT_BEFORE]) },
|
||||
{ "Requires", "as", NULL, offsetof(UnitTimes, deps[UNIT_REQUIRES]) },
|
||||
{ "Requisite", "as", NULL, offsetof(UnitTimes, deps[UNIT_REQUISITE]) },
|
||||
{ "Wants", "as", NULL, offsetof(UnitTimes, deps[UNIT_WANTS]) },
|
||||
{ "Conflicts", "as", NULL, offsetof(UnitTimes, deps[UNIT_CONFLICTS]) },
|
||||
{ "Upholds", "as", NULL, offsetof(UnitTimes, deps[UNIT_UPHOLDS]) },
|
||||
{},
|
||||
};
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
@ -254,14 +275,14 @@ int acquire_time_data(sd_bus *bus, bool require_finished, UnitTimes **out) {
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
|
||||
UnitTimes *t;
|
||||
_cleanup_(unit_times_clearp) UnitTimes *t = NULL;
|
||||
|
||||
if (!GREEDY_REALLOC(unit_times, c + 2))
|
||||
if (!GREEDY_REALLOC0(unit_times, c + 2))
|
||||
return log_oom();
|
||||
|
||||
unit_times[c + 1].has_data = false;
|
||||
/* t initially has pointers zeroed by the allocation, and unit_times_clearp will have zeroed
|
||||
* them if the entry is being reused. */
|
||||
t = &unit_times[c];
|
||||
t->name = NULL;
|
||||
|
||||
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
|
||||
|
||||
@ -298,6 +319,8 @@ int acquire_time_data(sd_bus *bus, bool require_finished, UnitTimes **out) {
|
||||
return log_oom();
|
||||
|
||||
t->has_data = true;
|
||||
/* Prevent destructor from running on t reference. */
|
||||
TAKE_PTR(t);
|
||||
c++;
|
||||
}
|
||||
if (r < 0)
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <sd-bus.h>
|
||||
|
||||
#include "time-util.h"
|
||||
#include "unit-def.h"
|
||||
|
||||
typedef struct BootTimes {
|
||||
usec_t firmware_time;
|
||||
@ -45,11 +46,13 @@ typedef struct UnitTimes {
|
||||
usec_t deactivated;
|
||||
usec_t deactivating;
|
||||
usec_t time;
|
||||
char **deps[_UNIT_DEPENDENCY_MAX];
|
||||
} UnitTimes;
|
||||
|
||||
int acquire_boot_times(sd_bus *bus, bool require_finished, BootTimes **ret);
|
||||
int pretty_boot_time(sd_bus *bus, char **ret);
|
||||
|
||||
void unit_times_clear(UnitTimes *t);
|
||||
UnitTimes* unit_times_free_array(UnitTimes *t);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UnitTimes*, unit_times_free_array);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user