]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
analyze: split out critical chain
authorLennart Poettering <lennart@poettering.net>
Mon, 21 Feb 2022 12:56:59 +0000 (13:56 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 21 Feb 2022 16:22:23 +0000 (17:22 +0100)
src/analyze/analyze-critical-chain.c [new file with mode: 0644]
src/analyze/analyze-critical-chain.h [new file with mode: 0644]
src/analyze/analyze.c
src/analyze/analyze.h
src/analyze/meson.build

diff --git a/src/analyze/analyze-critical-chain.c b/src/analyze/analyze-critical-chain.c
new file mode 100644 (file)
index 0000000..3e2c5e7
--- /dev/null
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "analyze.h"
+#include "analyze-critical-chain.h"
+#include "analyze-time-data.h"
+#include "strv.h"
+#include "copy.h"
+#include "path-util.h"
+#include "terminal-util.h"
+#include "sort-util.h"
+#include "special.h"
+#include "bus-error.h"
+
+static int list_dependencies_print(
+                const char *name,
+                unsigned level,
+                unsigned branches,
+                bool last,
+                UnitTimes *times,
+                BootTimes *boot) {
+
+        for (unsigned i = level; i != 0; i--)
+                printf("%s", special_glyph(branches & (1 << (i-1)) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
+
+        printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
+
+        if (times) {
+                if (times->time > 0)
+                        printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
+                               FORMAT_TIMESPAN(times->activating - boot->userspace_time, USEC_PER_MSEC),
+                               FORMAT_TIMESPAN(times->time, USEC_PER_MSEC), ansi_normal());
+                else if (times->activated > boot->userspace_time)
+                        printf("%s @%s", name, FORMAT_TIMESPAN(times->activated - boot->userspace_time, USEC_PER_MSEC));
+                else
+                        printf("%s", name);
+        } else
+                printf("%s", name);
+        printf("\n");
+
+        return 0;
+}
+
+static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
+        _cleanup_free_ char *path = NULL;
+
+        assert(bus);
+        assert(name);
+        assert(deps);
+
+        path = unit_dbus_path_from_name(name);
+        if (!path)
+                return -ENOMEM;
+
+        return bus_get_unit_property_strv(bus, path, "After", deps);
+}
+
+static Hashmap *unit_times_hashmap;
+
+static int list_dependencies_compare(char *const *a, char *const *b) {
+        usec_t usa = 0, usb = 0;
+        UnitTimes *times;
+
+        times = hashmap_get(unit_times_hashmap, *a);
+        if (times)
+                usa = times->activated;
+        times = hashmap_get(unit_times_hashmap, *b);
+        if (times)
+                usb = times->activated;
+
+        return CMP(usb, usa);
+}
+
+static bool times_in_range(const UnitTimes *times, const BootTimes *boot) {
+        return times && times->activated > 0 && times->activated <= boot->finish_time;
+}
+
+static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units, unsigned branches) {
+        _cleanup_strv_free_ char **deps = NULL;
+        char **c;
+        int r;
+        usec_t service_longest = 0;
+        int to_print = 0;
+        UnitTimes *times;
+        BootTimes *boot;
+
+        if (strv_extend(units, name))
+                return log_oom();
+
+        r = list_dependencies_get_dependencies(bus, name, &deps);
+        if (r < 0)
+                return r;
+
+        typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
+
+        r = acquire_boot_times(bus, &boot);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(c, deps) {
+                times = hashmap_get(unit_times_hashmap, *c); /* lgtm [cpp/inconsistent-null-check] */
+                if (times_in_range(times, boot) && times->activated >= service_longest)
+                        service_longest = times->activated;
+        }
+
+        if (service_longest == 0)
+                return r;
+
+        STRV_FOREACH(c, deps) {
+                times = hashmap_get(unit_times_hashmap, *c); /* lgtm [cpp/inconsistent-null-check] */
+                if (times_in_range(times, boot) && service_longest - times->activated <= arg_fuzz)
+                        to_print++;
+        }
+
+        if (!to_print)
+                return r;
+
+        STRV_FOREACH(c, deps) {
+                times = hashmap_get(unit_times_hashmap, *c); /* lgtm [cpp/inconsistent-null-check] */
+                if (!times_in_range(times, boot) || service_longest - times->activated > arg_fuzz)
+                        continue;
+
+                to_print--;
+
+                r = list_dependencies_print(*c, level, branches, to_print == 0, times, boot);
+                if (r < 0)
+                        return r;
+
+                if (strv_contains(*units, *c)) {
+                        r = list_dependencies_print("...", level + 1, (branches << 1) | (to_print ? 1 : 0),
+                                                    true, NULL, boot);
+                        if (r < 0)
+                                return r;
+                        continue;
+                }
+
+                r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (to_print ? 1 : 0));
+                if (r < 0)
+                        return r;
+
+                if (to_print == 0)
+                        break;
+        }
+        return 0;
+}
+
+static int list_dependencies(sd_bus *bus, const char *name) {
+        _cleanup_strv_free_ char **units = NULL;
+        UnitTimes *times;
+        int r;
+        const char *id;
+        _cleanup_free_ char *path = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        BootTimes *boot;
+
+        assert(bus);
+
+        path = unit_dbus_path_from_name(name);
+        if (!path)
+                return -ENOMEM;
+
+        r = sd_bus_get_property(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Unit",
+                        "Id",
+                        &error,
+                        &reply,
+                        "s");
+        if (r < 0)
+                return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_read(reply, "s", &id);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        times = hashmap_get(unit_times_hashmap, id);
+
+        r = acquire_boot_times(bus, &boot);
+        if (r < 0)
+                return r;
+
+        if (times) {
+                if (times->time)
+                        printf("%s%s +%s%s\n", ansi_highlight_red(), id,
+                               FORMAT_TIMESPAN(times->time, USEC_PER_MSEC), ansi_normal());
+                else if (times->activated > boot->userspace_time)
+                        printf("%s @%s\n", id,
+                               FORMAT_TIMESPAN(times->activated - boot->userspace_time, USEC_PER_MSEC));
+                else
+                        printf("%s\n", id);
+        }
+
+        return list_dependencies_one(bus, name, 0, &units, 0);
+}
+
+int analyze_critical_chain(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL;
+        Hashmap *h;
+        int n, r;
+
+        r = acquire_bus(&bus, NULL);
+        if (r < 0)
+                return bus_log_connect_error(r, arg_transport);
+
+        n = acquire_time_data(bus, &times);
+        if (n <= 0)
+                return n;
+
+        h = hashmap_new(&string_hash_ops);
+        if (!h)
+                return log_oom();
+
+        for (UnitTimes *u = times; u->has_data; u++) {
+                r = hashmap_put(h, u->name, u);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add entry to hashmap: %m");
+        }
+        unit_times_hashmap = h;
+
+        pager_open(arg_pager_flags);
+
+        puts("The time when unit became active or started is printed after the \"@\" character.\n"
+             "The time the unit took to start is printed after the \"+\" character.\n");
+
+        if (argc > 1) {
+                char **name;
+                STRV_FOREACH(name, strv_skip(argv, 1))
+                        list_dependencies(bus, *name);
+        } else
+                list_dependencies(bus, SPECIAL_DEFAULT_TARGET);
+
+        h = hashmap_free(h);
+        return 0;
+}
diff --git a/src/analyze/analyze-critical-chain.h b/src/analyze/analyze-critical-chain.h
new file mode 100644 (file)
index 0000000..a5a8e2d
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int analyze_critical_chain(int argc, char *argv[], void *userdata);
index 5d6ae15038e0ecc5c4dda9916c984770e0c888ec..465f7c7c0927bc8e4a5375660e7989534d5743fb 100644 (file)
@@ -18,6 +18,7 @@
 #include "analyze-capability.h"
 #include "analyze-cat-config.h"
 #include "analyze-condition.h"
+#include "analyze-critical-chain.h"
 #include "analyze-dot.h"
 #include "analyze-dump.h"
 #include "analyze-elf.h"
@@ -83,7 +84,7 @@
 
 DotMode arg_dot = DEP_ALL;
 char **arg_dot_from_patterns = NULL, **arg_dot_to_patterns = NULL;
-static usec_t arg_fuzz = 0;
+usec_t arg_fuzz = 0;
 PagerFlags arg_pager_flags = 0;
 BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
 const char *arg_host = NULL;
@@ -196,231 +197,6 @@ static int process_aliases(char *argv[], char *tempdir, char ***ret) {
         return 0;
 }
 
-static int list_dependencies_print(
-                const char *name,
-                unsigned level,
-                unsigned branches,
-                bool last,
-                UnitTimes *times,
-                BootTimes *boot) {
-
-        for (unsigned i = level; i != 0; i--)
-                printf("%s", special_glyph(branches & (1 << (i-1)) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
-
-        printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
-
-        if (times) {
-                if (times->time > 0)
-                        printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
-                               FORMAT_TIMESPAN(times->activating - boot->userspace_time, USEC_PER_MSEC),
-                               FORMAT_TIMESPAN(times->time, USEC_PER_MSEC), ansi_normal());
-                else if (times->activated > boot->userspace_time)
-                        printf("%s @%s", name, FORMAT_TIMESPAN(times->activated - boot->userspace_time, USEC_PER_MSEC));
-                else
-                        printf("%s", name);
-        } else
-                printf("%s", name);
-        printf("\n");
-
-        return 0;
-}
-
-static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
-        _cleanup_free_ char *path = NULL;
-
-        assert(bus);
-        assert(name);
-        assert(deps);
-
-        path = unit_dbus_path_from_name(name);
-        if (!path)
-                return -ENOMEM;
-
-        return bus_get_unit_property_strv(bus, path, "After", deps);
-}
-
-static Hashmap *unit_times_hashmap;
-
-static int list_dependencies_compare(char *const *a, char *const *b) {
-        usec_t usa = 0, usb = 0;
-        UnitTimes *times;
-
-        times = hashmap_get(unit_times_hashmap, *a);
-        if (times)
-                usa = times->activated;
-        times = hashmap_get(unit_times_hashmap, *b);
-        if (times)
-                usb = times->activated;
-
-        return CMP(usb, usa);
-}
-
-static bool times_in_range(const UnitTimes *times, const BootTimes *boot) {
-        return times && times->activated > 0 && times->activated <= boot->finish_time;
-}
-
-static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units, unsigned branches) {
-        _cleanup_strv_free_ char **deps = NULL;
-        char **c;
-        int r;
-        usec_t service_longest = 0;
-        int to_print = 0;
-        UnitTimes *times;
-        BootTimes *boot;
-
-        if (strv_extend(units, name))
-                return log_oom();
-
-        r = list_dependencies_get_dependencies(bus, name, &deps);
-        if (r < 0)
-                return r;
-
-        typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
-
-        r = acquire_boot_times(bus, &boot);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(c, deps) {
-                times = hashmap_get(unit_times_hashmap, *c); /* lgtm [cpp/inconsistent-null-check] */
-                if (times_in_range(times, boot) && times->activated >= service_longest)
-                        service_longest = times->activated;
-        }
-
-        if (service_longest == 0)
-                return r;
-
-        STRV_FOREACH(c, deps) {
-                times = hashmap_get(unit_times_hashmap, *c); /* lgtm [cpp/inconsistent-null-check] */
-                if (times_in_range(times, boot) && service_longest - times->activated <= arg_fuzz)
-                        to_print++;
-        }
-
-        if (!to_print)
-                return r;
-
-        STRV_FOREACH(c, deps) {
-                times = hashmap_get(unit_times_hashmap, *c); /* lgtm [cpp/inconsistent-null-check] */
-                if (!times_in_range(times, boot) || service_longest - times->activated > arg_fuzz)
-                        continue;
-
-                to_print--;
-
-                r = list_dependencies_print(*c, level, branches, to_print == 0, times, boot);
-                if (r < 0)
-                        return r;
-
-                if (strv_contains(*units, *c)) {
-                        r = list_dependencies_print("...", level + 1, (branches << 1) | (to_print ? 1 : 0),
-                                                    true, NULL, boot);
-                        if (r < 0)
-                                return r;
-                        continue;
-                }
-
-                r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (to_print ? 1 : 0));
-                if (r < 0)
-                        return r;
-
-                if (to_print == 0)
-                        break;
-        }
-        return 0;
-}
-
-static int list_dependencies(sd_bus *bus, const char *name) {
-        _cleanup_strv_free_ char **units = NULL;
-        UnitTimes *times;
-        int r;
-        const char *id;
-        _cleanup_free_ char *path = NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        BootTimes *boot;
-
-        assert(bus);
-
-        path = unit_dbus_path_from_name(name);
-        if (!path)
-                return -ENOMEM;
-
-        r = sd_bus_get_property(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Unit",
-                        "Id",
-                        &error,
-                        &reply,
-                        "s");
-        if (r < 0)
-                return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
-
-        r = sd_bus_message_read(reply, "s", &id);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        times = hashmap_get(unit_times_hashmap, id);
-
-        r = acquire_boot_times(bus, &boot);
-        if (r < 0)
-                return r;
-
-        if (times) {
-                if (times->time)
-                        printf("%s%s +%s%s\n", ansi_highlight_red(), id,
-                               FORMAT_TIMESPAN(times->time, USEC_PER_MSEC), ansi_normal());
-                else if (times->activated > boot->userspace_time)
-                        printf("%s @%s\n", id,
-                               FORMAT_TIMESPAN(times->activated - boot->userspace_time, USEC_PER_MSEC));
-                else
-                        printf("%s\n", id);
-        }
-
-        return list_dependencies_one(bus, name, 0, &units, 0);
-}
-
-static int analyze_critical_chain(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL;
-        Hashmap *h;
-        int n, r;
-
-        r = acquire_bus(&bus, NULL);
-        if (r < 0)
-                return bus_log_connect_error(r, arg_transport);
-
-        n = acquire_time_data(bus, &times);
-        if (n <= 0)
-                return n;
-
-        h = hashmap_new(&string_hash_ops);
-        if (!h)
-                return log_oom();
-
-        for (UnitTimes *u = times; u->has_data; u++) {
-                r = hashmap_put(h, u->name, u);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to add entry to hashmap: %m");
-        }
-        unit_times_hashmap = h;
-
-        pager_open(arg_pager_flags);
-
-        puts("The time when unit became active or started is printed after the \"@\" character.\n"
-             "The time the unit took to start is printed after the \"+\" character.\n");
-
-        if (argc > 1) {
-                char **name;
-                STRV_FOREACH(name, strv_skip(argv, 1))
-                        list_dependencies(bus, *name);
-        } else
-                list_dependencies(bus, SPECIAL_DEFAULT_TARGET);
-
-        h = hashmap_free(h);
-        return 0;
-}
-
 static int analyze_time(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_free_ char *buf = NULL;
index 7d4b0d408f7ef17bbe6b25a5765528c4df104af1..57740acc8c32945378a048259f26f7f445e393a0 100644 (file)
@@ -16,6 +16,7 @@ typedef enum DotMode {
 
 extern DotMode arg_dot;
 extern char **arg_dot_from_patterns, **arg_dot_to_patterns;
+extern usec_t arg_fuzz;
 extern PagerFlags arg_pager_flags;
 extern BusTransport arg_transport;
 extern const char *arg_host;
index 383437eb277f1fc8fb26e67cb3653a4a6270108e..71a4f2da4c8d9db00fa07134a8d6606d8ddf9f4a 100644 (file)
@@ -11,6 +11,8 @@ systemd_analyze_sources = files('''
         analyze-cat-config.h
         analyze-condition.c
         analyze-condition.h
+        analyze-critical-chain.c
+        analyze-critical-chain.h
         analyze-dot.c
         analyze-dot.h
         analyze-dump.c