From 5663ddaed7f7d89236cf0ef4a634c3828518108c Mon Sep 17 00:00:00 2001 From: Chris Down Date: Fri, 24 Jul 2026 16:08:16 -0700 Subject: [PATCH 1/2] properties: Skip found set building for nominal case bus_message_print_all_properties() inserts every name it walks into the found-properties set, but the set is only used to report missing requested properties at debug level. Request the set from systemctl only when properties were specified and debug logging is enabled, avoiding the unnecessary work in normal operation. In my tests with `systemctl show` over 160 units this brings the instructions retired from 1167.8M down to 992.6M, a reduction of 15.0%. The output is unchanged. --- src/systemctl/systemctl-show.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c index 82b8568813..464955e160 100644 --- a/src/systemctl/systemctl-show.c +++ b/src/systemctl/systemctl-show.c @@ -2336,6 +2336,7 @@ static int show_one( .io_read_bytes = UINT64_MAX, .io_write_bytes = UINT64_MAX, }; + bool collect_found_properties; int r; assert(path); @@ -2387,13 +2388,18 @@ static int show_one( if (r < 0) return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); - r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_print_flags, &found_properties); + /* The found properties set is expensive and only used for debug logging, so collect it only when needed. */ + collect_found_properties = DEBUG_LOGGING && !strv_isempty(arg_properties); + + r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_print_flags, + collect_found_properties ? &found_properties : NULL); if (r < 0) return bus_log_parse_error(r); - STRV_FOREACH(pp, arg_properties) - if (!set_contains(found_properties, *pp)) - log_debug("Property %s does not exist.", *pp); + if (collect_found_properties) + STRV_FOREACH(pp, arg_properties) + if (!set_contains(found_properties, *pp)) + log_debug("Property %s does not exist.", *pp); return 0; } From 248d6cf09d26a2daeff20c29fb1660868b9d352b Mon Sep 17 00:00:00 2001 From: Chris Down Date: Fri, 24 Jul 2026 16:18:27 -0700 Subject: [PATCH 2/2] properties: Skip value building for nominal case bus_message_print_all_properties() builds a PROP= string for every property in the reply so that -p PROP=value filters can be matched against it, but most queries never need this. Take the normal `systemctl show` or `systemctl show UNIT` case. In that case there is no filter. Even with `-p PROP` there is no value filter since there is no value. Avoid constructing the string entirely by comparing property names directly against filter entries. In my tests with a `systemctl show` over 160 units this brings the instructions retired from 992.6M down to 960.5M, a reduction of 3.2%. The same goes for property filters with units. When running: systemctl show -p UnitFileState -p ActiveState UNIT ...the instructions retired drops from 9.52M to 9.22M, a reduction of 3.2%. The output in each case is unchanged. --- src/shared/bus-print-properties.c | 38 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/shared/bus-print-properties.c b/src/shared/bus-print-properties.c index d2377ceb60..b8a12bdb8b 100644 --- a/src/shared/bus-print-properties.c +++ b/src/shared/bus-print-properties.c @@ -344,6 +344,34 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b return 0; } +static bool match_filter(char **filter, const char *name, const char **ret_expected_value) { + const char *expected_value = NULL; + + assert(name); + assert(ret_expected_value); + + if (!filter) { + *ret_expected_value = NULL; + return true; + } + + STRV_FOREACH(f, filter) { + const char *p = startswith(*f, name); + + if (!p) + continue; + if (*p == '\0') { + *ret_expected_value = NULL; + return true; + } + if (*p == '=' && !expected_value) + expected_value = p + 1; + } + + *ret_expected_value = expected_value; + return expected_value != NULL; +} + int bus_message_print_all_properties( sd_bus_message *m, bus_message_print_t func, @@ -360,7 +388,6 @@ int bus_message_print_all_properties( return r; while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { - _cleanup_free_ char *name_with_equal = NULL; const char *name, *contents, *expected_value = NULL; r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); @@ -373,14 +400,7 @@ int bus_message_print_all_properties( return log_oom(); } - name_with_equal = strjoin(name, "="); - if (!name_with_equal) - return log_oom(); - - if (!filter || - strv_contains(filter, name) || - (expected_value = strv_find_startswith(filter, name_with_equal))) { - + if (match_filter(filter, name, &expected_value)) { r = sd_bus_message_peek_type(m, NULL, &contents); if (r < 0) return r;