From cbd2abbbe736f2fde90408f40b26d0fbccdcbf48 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 13 Nov 2023 21:24:34 +0800 Subject: [PATCH 1/5] core: use FOREACH_ARRAY and RET_GATHER more --- src/core/cgroup.c | 22 +++++++++++----------- src/core/unit.c | 5 +++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 03fdc7388f..73431fa5db 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -4391,19 +4391,19 @@ int unit_reset_cpu_accounting(Unit *u) { } int unit_reset_ip_accounting(Unit *u) { - int r = 0, q = 0; + int r = 0; assert(u); if (u->ip_accounting_ingress_map_fd >= 0) - r = bpf_firewall_reset_accounting(u->ip_accounting_ingress_map_fd); + RET_GATHER(r, bpf_firewall_reset_accounting(u->ip_accounting_ingress_map_fd)); if (u->ip_accounting_egress_map_fd >= 0) - q = bpf_firewall_reset_accounting(u->ip_accounting_egress_map_fd); + RET_GATHER(r, bpf_firewall_reset_accounting(u->ip_accounting_egress_map_fd)); zero(u->ip_accounting_extra); - return r < 0 ? r : q; + return r; } int unit_reset_io_accounting(Unit *u) { @@ -4411,8 +4411,8 @@ int unit_reset_io_accounting(Unit *u) { assert(u); - for (CGroupIOAccountingMetric i = 0; i < _CGROUP_IO_ACCOUNTING_METRIC_MAX; i++) - u->io_accounting_last[i] = UINT64_MAX; + FOREACH_ARRAY(i, u->io_accounting_last, _CGROUP_IO_ACCOUNTING_METRIC_MAX) + *i = UINT64_MAX; r = unit_get_io_accounting_raw(u, u->io_accounting_base); if (r < 0) { @@ -4424,15 +4424,15 @@ int unit_reset_io_accounting(Unit *u) { } int unit_reset_accounting(Unit *u) { - int r, q, v; + int r = 0; assert(u); - r = unit_reset_cpu_accounting(u); - q = unit_reset_io_accounting(u); - v = unit_reset_ip_accounting(u); + RET_GATHER(r, unit_reset_cpu_accounting(u)); + RET_GATHER(r, unit_reset_io_accounting(u)); + RET_GATHER(r, unit_reset_ip_accounting(u)); - return r < 0 ? r : q < 0 ? q : v; + return r; } void unit_invalidate_cgroup(Unit *u, CGroupMask m) { diff --git a/src/core/unit.c b/src/core/unit.c index 66ac9c91ec..381241f02d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -121,8 +121,9 @@ Unit* unit_new(Manager *m, size_t size) { u->ip_accounting_ingress_map_fd = -EBADF; u->ip_accounting_egress_map_fd = -EBADF; - for (CGroupIOAccountingMetric i = 0; i < _CGROUP_IO_ACCOUNTING_METRIC_MAX; i++) - u->io_accounting_last[i] = UINT64_MAX; + + FOREACH_ARRAY(i, u->io_accounting_last, _CGROUP_IO_ACCOUNTING_METRIC_MAX) + *i = UINT64_MAX; u->ipv4_allow_map_fd = -EBADF; u->ipv6_allow_map_fd = -EBADF; From d6d71575dd12efe41edd1070190069fcd7cad652 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 13 Nov 2023 20:53:59 +0800 Subject: [PATCH 2/5] core/unit-serialize: realign table --- src/core/unit-serialize.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c index 3bb63d15d6..75448ab522 100644 --- a/src/core/unit-serialize.c +++ b/src/core/unit-serialize.c @@ -69,24 +69,24 @@ static int deserialize_markers(Unit *u, const char *value) { } } -static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes", +static const char* const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes", [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets", - [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes", - [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets", + [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes", + [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets", }; -static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base", - [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base", - [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base", +static const char* const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base", + [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base", + [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base", [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base", }; -static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last", - [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last", - [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last", +static const char* const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last", + [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last", + [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last", [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last", }; From 94a2937550430c3839c1f86e22478963f2f0313b Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 13 Nov 2023 23:43:54 +0800 Subject: [PATCH 3/5] core/unit-serialize: use private string table --- src/core/unit-serialize.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c index 75448ab522..d5361905b8 100644 --- a/src/core/unit-serialize.c +++ b/src/core/unit-serialize.c @@ -69,27 +69,33 @@ static int deserialize_markers(Unit *u, const char *value) { } } -static const char* const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { +static const char* const ip_accounting_metric_field_table[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes", [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets", [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes", [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets", }; -static const char* const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(ip_accounting_metric_field, CGroupIPAccountingMetric); + +static const char* const io_accounting_metric_field_base_table[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base", [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base", [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base", [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base", }; -static const char* const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(io_accounting_metric_field_base, CGroupIOAccountingMetric); + +static const char* const io_accounting_metric_field_last_table[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last", [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last", [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last", [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last", }; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(io_accounting_metric_field_last, CGroupIOAccountingMetric); + int unit_serialize_state(Unit *u, FILE *f, FDSet *fds, bool switching_root) { int r; @@ -153,10 +159,10 @@ int unit_serialize_state(Unit *u, FILE *f, FDSet *fds, bool switching_root) { (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last); for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) { - (void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]); + (void) serialize_item_format(f, io_accounting_metric_field_base_to_string(im), "%" PRIu64, u->io_accounting_base[im]); if (u->io_accounting_last[im] != UINT64_MAX) - (void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]); + (void) serialize_item_format(f, io_accounting_metric_field_last_to_string(im), "%" PRIu64, u->io_accounting_last[im]); } if (u->cgroup_path) @@ -195,7 +201,7 @@ int unit_serialize_state(Unit *u, FILE *f, FDSet *fds, bool switching_root) { r = unit_get_ip_accounting(u, m, &v); if (r >= 0) - (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v); + (void) serialize_item_format(f, ip_accounting_metric_field_to_string(m), "%" PRIu64, v); } if (!switching_root) { @@ -469,7 +475,7 @@ int unit_deserialize_state(Unit *u, FILE *f, FDSet *fds) { } /* Check if this is an IP accounting metric serialization field */ - m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l); + m = ip_accounting_metric_field_from_string(l); if (m >= 0) { uint64_t c; @@ -481,7 +487,7 @@ int unit_deserialize_state(Unit *u, FILE *f, FDSet *fds) { continue; } - m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l); + m = io_accounting_metric_field_base_from_string(l); if (m >= 0) { uint64_t c; @@ -493,7 +499,7 @@ int unit_deserialize_state(Unit *u, FILE *f, FDSet *fds) { continue; } - m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l); + m = io_accounting_metric_field_last_from_string(l); if (m >= 0) { uint64_t c; From 9824ab1f009e99b0b9d273ace4c98cc687a4c1d7 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 13 Nov 2023 20:23:42 +0800 Subject: [PATCH 4/5] core: generalize memory accounting attribute handling Follow-up for #29941 Also, support for MemoryCurrent in cgroup v1 is removed, as we're going to remove that completely anyway. Fixes #30000 --- src/core/cgroup.c | 84 ++++++++++++-------------- src/core/cgroup.h | 25 ++++++-- src/core/dbus-unit.c | 121 ++++++++------------------------------ src/core/unit-serialize.c | 27 +++++++++ src/core/unit.c | 10 ++-- src/core/unit.h | 7 +-- 6 files changed, 118 insertions(+), 156 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 73431fa5db..4e4b668f62 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -4017,6 +4017,8 @@ int unit_get_memory_available(Unit *u, uint64_t *ret) { int unit_get_memory_current(Unit *u, uint64_t *ret) { int r; + // FIXME: Merge this into unit_get_memory_accounting after support for cgroup v1 is dropped + assert(u); assert(ret); @@ -4040,12 +4042,21 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) { return cg_get_attribute_as_uint64("memory", u->cgroup_path, r > 0 ? "memory.current" : "memory.usage_in_bytes", ret); } -static int unit_get_memory_attr_raw(Unit *u, const char* mem_attribute, uint64_t *ret) { +int unit_get_memory_accounting(Unit *u, CGroupMemoryAccountingMetric metric, uint64_t *ret) { + + static const char* const attributes_table[_CGROUP_MEMORY_ACCOUNTING_METRIC_MAX] = { + [CGROUP_MEMORY_PEAK] = "memory.peak", + [CGROUP_MEMORY_SWAP_CURRENT] = "memory.swap.current", + [CGROUP_MEMORY_SWAP_PEAK] = "memory.swap.peak", + [CGROUP_MEMORY_ZSWAP_CURRENT] = "memory.zswap.current", + }; + + uint64_t bytes; int r; assert(u); - assert(mem_attribute); - assert(ret); + assert(metric >= 0); + assert(metric < _CGROUP_MEMORY_ACCOUNTING_METRIC_MAX); if (!UNIT_CGROUP_BOOL(u, memory_accounting)) return -ENODATA; @@ -4057,64 +4068,36 @@ static int unit_get_memory_attr_raw(Unit *u, const char* mem_attribute, uint64_t if (unit_has_host_root_cgroup(u)) return -ENODATA; - if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0) + if (!FLAGS_SET(u->cgroup_realized_mask, CGROUP_MASK_MEMORY)) return -ENODATA; r = cg_all_unified(); if (r < 0) return r; - if (!r) + if (r == 0) return -ENODATA; - return cg_get_attribute_as_uint64("memory", u->cgroup_path, mem_attribute, ret); -} - -static int unit_get_memory_attr_cached(Unit *u, const char* mem_attribute, uint64_t* last, uint64_t *ret) { - uint64_t bytes; - int r; - - assert(u); - assert(mem_attribute); - assert(last); - - if (!UNIT_CGROUP_BOOL(u, memory_accounting)) - return -ENODATA; - - r = unit_get_memory_attr_raw(u, mem_attribute, &bytes); - if (r == -ENODATA && *last != UINT64_MAX) { - /* If we can't get the memory peak anymore (because the cgroup was already removed, for example), - * use our cached value. */ - - if (ret) - *ret = *last; - return 0; - } - if (r < 0) + r = cg_get_attribute_as_uint64("memory", u->cgroup_path, attributes_table[metric], &bytes); + if (r < 0 && (r != -ENODATA || metric > _CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST)) return r; - *last = bytes; + if (metric <= _CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST) { + uint64_t *last = &u->memory_accounting_last[metric]; + + if (r >= 0) + *last = bytes; + else if (*last != UINT64_MAX) + bytes = *last; + else + return r; + } + if (ret) *ret = bytes; return 0; } -int unit_get_memory_peak(Unit *u, uint64_t *ret) { - return unit_get_memory_attr_cached(u, "memory.peak", &u->memory_peak_last, ret); -} - -int unit_get_memory_swap_current(Unit *u, uint64_t *ret) { - return unit_get_memory_attr_raw(u, "memory.swap.current", ret); -} - -int unit_get_memory_swap_peak(Unit *u, uint64_t *ret) { - return unit_get_memory_attr_cached(u, "memory.swap.peak", &u->memory_swap_peak_last, ret); -} - -int unit_get_memory_zswap_current(Unit *u, uint64_t *ret) { - return unit_get_memory_attr_raw(u, "memory.zswap.current", ret); -} - int unit_get_tasks_current(Unit *u, uint64_t *ret) { assert(u); assert(ret); @@ -4650,3 +4633,12 @@ static const char* const cgroup_io_accounting_metric_table[_CGROUP_IO_ACCOUNTING }; DEFINE_STRING_TABLE_LOOKUP(cgroup_io_accounting_metric, CGroupIOAccountingMetric); + +static const char* const cgroup_memory_accounting_metric_table[_CGROUP_MEMORY_ACCOUNTING_METRIC_MAX] = { + [CGROUP_MEMORY_PEAK] = "MemoryPeak", + [CGROUP_MEMORY_SWAP_CURRENT] = "MemorySwapCurrent", + [CGROUP_MEMORY_SWAP_PEAK] = "MemorySwapPeak", + [CGROUP_MEMORY_ZSWAP_CURRENT] = "MemoryZSwapCurrent", +}; + +DEFINE_STRING_TABLE_LOOKUP(cgroup_memory_accounting_metric, CGroupMemoryAccountingMetric); diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 203575ca34..157ac7271f 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -261,6 +261,21 @@ typedef enum CGroupIOAccountingMetric { _CGROUP_IO_ACCOUNTING_METRIC_INVALID = -EINVAL, } CGroupIOAccountingMetric; +typedef enum CGroupMemoryAccountingMetric { + CGROUP_MEMORY_PEAK, + CGROUP_MEMORY_SWAP_PEAK, + /* We cache the above attributes, so that they can be fetched even after the cgroup is gone, e.g. + * when systemd-run exits. */ + _CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST = CGROUP_MEMORY_SWAP_PEAK, + + /* These attributes are transient, so no need for caching. */ + CGROUP_MEMORY_SWAP_CURRENT, + CGROUP_MEMORY_ZSWAP_CURRENT, + + _CGROUP_MEMORY_ACCOUNTING_METRIC_MAX, + _CGROUP_MEMORY_ACCOUNTING_METRIC_INVALID = -EINVAL, +} CGroupMemoryAccountingMetric; + typedef struct Unit Unit; typedef struct Manager Manager; typedef enum ManagerState ManagerState; @@ -352,12 +367,9 @@ int unit_watch_all_pids(Unit *u); int unit_synthesize_cgroup_empty_event(Unit *u); -int unit_get_memory_current(Unit *u, uint64_t *ret); -int unit_get_memory_peak(Unit *u, uint64_t *ret); -int unit_get_memory_swap_current(Unit *u, uint64_t *ret); -int unit_get_memory_swap_peak(Unit *u, uint64_t *ret); -int unit_get_memory_zswap_current(Unit *u, uint64_t *ret); int unit_get_memory_available(Unit *u, uint64_t *ret); +int unit_get_memory_current(Unit *u, uint64_t *ret); +int unit_get_memory_accounting(Unit *u, CGroupMemoryAccountingMetric metric, uint64_t *ret); int unit_get_tasks_current(Unit *u, uint64_t *ret); int unit_get_cpu_usage(Unit *u, nsec_t *ret); int unit_get_io_accounting(Unit *u, CGroupIOAccountingMetric metric, bool allow_cache, uint64_t *ret); @@ -410,3 +422,6 @@ CGroupIPAccountingMetric cgroup_ip_accounting_metric_from_string(const char *s) const char* cgroup_io_accounting_metric_to_string(CGroupIOAccountingMetric m) _const_; CGroupIOAccountingMetric cgroup_io_accounting_metric_from_string(const char *s) _pure_; + +const char* cgroup_memory_accounting_metric_to_string(CGroupMemoryAccountingMetric m) _const_; +CGroupMemoryAccountingMetric cgroup_memory_accounting_metric_from_string(const char *s) _pure_; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index e5293269e3..36b1bfa066 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1080,98 +1080,6 @@ static int property_get_current_memory( return sd_bus_message_append(reply, "t", sz); } -static int property_get_peak_memory( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - uint64_t sz = UINT64_MAX; - Unit *u = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(reply); - - r = unit_get_memory_peak(u, &sz); - if (r < 0 && r != -ENODATA) - log_unit_warning_errno(u, r, "Failed to get memory.peak attribute: %m"); - - return sd_bus_message_append(reply, "t", sz); -} - -static int property_get_current_swap_memory( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - uint64_t sz = UINT64_MAX; - Unit *u = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(reply); - - r = unit_get_memory_swap_current(u, &sz); - if (r < 0 && r != -ENODATA) - log_unit_warning_errno(u, r, "Failed to get memory.swap.current attribute: %m"); - - return sd_bus_message_append(reply, "t", sz); -} - -static int property_get_peak_swap_memory( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - uint64_t sz = UINT64_MAX; - Unit *u = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(reply); - - r = unit_get_memory_swap_peak(u, &sz); - if (r < 0 && r != -ENODATA) - log_unit_warning_errno(u, r, "Failed to get memory.swap.peak attribute: %m"); - - return sd_bus_message_append(reply, "t", sz); -} - -static int property_get_current_zswap_memory( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - uint64_t sz = UINT64_MAX; - Unit *u = ASSERT_PTR(userdata); - int r; - - assert(bus); - assert(reply); - - r = unit_get_memory_swap_current(u, &sz); - if (r < 0 && r != -ENODATA) - log_unit_warning_errno(u, r, "Failed to get memory.zswap.current attribute: %m"); - - return sd_bus_message_append(reply, "t", sz); -} - static int property_get_available_memory( sd_bus *bus, const char *path, @@ -1195,6 +1103,27 @@ static int property_get_available_memory( return sd_bus_message_append(reply, "t", sz); } +static int property_get_memory_accounting( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = ASSERT_PTR(userdata); + CGroupMemoryAccountingMetric metric; + uint64_t sz = UINT64_MAX; + + assert(bus); + assert(reply); + + assert_se((metric = cgroup_memory_accounting_metric_from_string(property)) >= 0); + (void) unit_get_memory_accounting(u, metric, &sz); + return sd_bus_message_append(reply, "t", sz); +} + static int property_get_current_tasks( sd_bus *bus, const char *path, @@ -1628,10 +1557,10 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = { SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0), SD_BUS_PROPERTY("ControlGroupId", "t", NULL, offsetof(Unit, cgroup_id), 0), SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), - SD_BUS_PROPERTY("MemoryPeak", "t", property_get_peak_memory, 0, 0), - SD_BUS_PROPERTY("MemorySwapCurrent", "t", property_get_current_swap_memory, 0, 0), - SD_BUS_PROPERTY("MemorySwapPeak", "t", property_get_peak_swap_memory, 0, 0), - SD_BUS_PROPERTY("MemoryZSwapCurrent", "t", property_get_current_zswap_memory, 0, 0), + SD_BUS_PROPERTY("MemoryPeak", "t", property_get_memory_accounting, 0, 0), + SD_BUS_PROPERTY("MemorySwapCurrent", "t", property_get_memory_accounting, 0, 0), + SD_BUS_PROPERTY("MemorySwapPeak", "t", property_get_memory_accounting, 0, 0), + SD_BUS_PROPERTY("MemoryZSwapCurrent", "t", property_get_memory_accounting, 0, 0), SD_BUS_PROPERTY("MemoryAvailable", "t", property_get_available_memory, 0, 0), SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0), SD_BUS_PROPERTY("EffectiveCPUs", "ay", property_get_cpuset_cpus, 0, 0), diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c index d5361905b8..af3e1c2089 100644 --- a/src/core/unit-serialize.c +++ b/src/core/unit-serialize.c @@ -96,6 +96,13 @@ static const char* const io_accounting_metric_field_last_table[_CGROUP_IO_ACCOUN DEFINE_PRIVATE_STRING_TABLE_LOOKUP(io_accounting_metric_field_last, CGroupIOAccountingMetric); +static const char* const memory_accounting_metric_field_last_table[_CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST + 1] = { + [CGROUP_MEMORY_PEAK] = "memory-accounting-peak", + [CGROUP_MEMORY_SWAP_PEAK] = "memory-accounting-swap-peak", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(memory_accounting_metric_field_last, CGroupMemoryAccountingMetric); + int unit_serialize_state(Unit *u, FILE *f, FDSet *fds, bool switching_root) { int r; @@ -165,6 +172,14 @@ int unit_serialize_state(Unit *u, FILE *f, FDSet *fds, bool switching_root) { (void) serialize_item_format(f, io_accounting_metric_field_last_to_string(im), "%" PRIu64, u->io_accounting_last[im]); } + for (CGroupMemoryAccountingMetric metric = 0; metric <= _CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST; metric++) { + uint64_t v; + + r = unit_get_memory_accounting(u, metric, &v); + if (r >= 0) + (void) serialize_item_format(f, memory_accounting_metric_field_last_to_string(metric), "%" PRIu64, v); + } + if (u->cgroup_path) (void) serialize_item(f, "cgroup", u->cgroup_path); @@ -474,6 +489,18 @@ int unit_deserialize_state(Unit *u, FILE *f, FDSet *fds) { continue; } + m = memory_accounting_metric_field_last_from_string(l); + if (m >= 0) { + uint64_t c; + + r = safe_atou64(v, &c); + if (r < 0) + log_unit_debug(u, "Failed to parse memory accounting last value %s, ignoring.", v); + else + u->memory_accounting_last[m] = c; + continue; + } + /* Check if this is an IP accounting metric serialization field */ m = ip_accounting_metric_field_from_string(l); if (m >= 0) { diff --git a/src/core/unit.c b/src/core/unit.c index 381241f02d..b88e28d77e 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -114,8 +114,10 @@ Unit* unit_new(Manager *m, size_t size) { u->ref_uid = UID_INVALID; u->ref_gid = GID_INVALID; u->cpu_usage_last = NSEC_INFINITY; - u->memory_peak_last = UINT64_MAX; - u->memory_swap_peak_last = UINT64_MAX; + + FOREACH_ARRAY(i, u->memory_accounting_last, ELEMENTSOF(u->memory_accounting_last)) + *i = UINT64_MAX; + u->cgroup_invalidated_mask |= CGROUP_MASK_BPF_FIREWALL; u->failure_action_exit_status = u->success_action_exit_status = -1; @@ -2372,7 +2374,7 @@ static int unit_log_resources(Unit *u) { nsec > NOTICEWORTHY_CPU_NSEC); } - (void) unit_get_memory_peak(u, &memory_peak); + (void) unit_get_memory_accounting(u, CGROUP_MEMORY_PEAK, &memory_peak); if (memory_peak != UINT64_MAX) { /* Format peak memory for inclusion in the structured log message */ if (asprintf(&t, "MEMORY_PEAK=%" PRIu64, memory_peak) < 0) { @@ -2390,7 +2392,7 @@ static int unit_log_resources(Unit *u) { message_parts[n_message_parts++] = t; } - (void) unit_get_memory_swap_peak(u, &memory_swap_peak); + (void) unit_get_memory_accounting(u, CGROUP_MEMORY_SWAP_PEAK, &memory_swap_peak); if (memory_swap_peak != UINT64_MAX) { /* Format peak swap memory for inclusion in the structured log message */ if (asprintf(&t, "MEMORY_SWAP_PEAK=%" PRIu64, memory_swap_peak) < 0) { diff --git a/src/core/unit.h b/src/core/unit.h index ded2f9d7d5..60bc2e3d35 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -365,11 +365,8 @@ typedef struct Unit { nsec_t cpu_usage_base; nsec_t cpu_usage_last; /* the most recently read value */ - /* Most recently read value of memory.peak */ - uint64_t memory_peak_last; - - /* Most recently read value of memory.swap.peak */ - uint64_t memory_swap_peak_last; + /* Most recently read value of memory accounting metrics */ + uint64_t memory_accounting_last[_CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST + 1]; /* The current counter of OOM kills initiated by systemd-oomd */ uint64_t managed_oom_kill_last; From d4bdc202c37991d01d89b4c38c16f2490f177e89 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 13 Nov 2023 21:27:29 +0800 Subject: [PATCH 5/5] core: add unit_reset_{memory,io}_accounting_last --- src/core/cgroup.c | 18 ++++++++++++++++-- src/core/cgroup.h | 2 ++ src/core/unit.c | 8 +++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 4e4b668f62..5b0cb15c85 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -4373,6 +4373,13 @@ int unit_reset_cpu_accounting(Unit *u) { return 0; } +void unit_reset_memory_accounting_last(Unit *u) { + assert(u); + + FOREACH_ARRAY(i, u->memory_accounting_last, ELEMENTSOF(u->memory_accounting_last)) + *i = UINT64_MAX; +} + int unit_reset_ip_accounting(Unit *u) { int r = 0; @@ -4389,13 +4396,19 @@ int unit_reset_ip_accounting(Unit *u) { return r; } +void unit_reset_io_accounting_last(Unit *u) { + assert(u); + + FOREACH_ARRAY(i, u->io_accounting_last, _CGROUP_IO_ACCOUNTING_METRIC_MAX) + *i = UINT64_MAX; +} + int unit_reset_io_accounting(Unit *u) { int r; assert(u); - FOREACH_ARRAY(i, u->io_accounting_last, _CGROUP_IO_ACCOUNTING_METRIC_MAX) - *i = UINT64_MAX; + unit_reset_io_accounting_last(u); r = unit_get_io_accounting_raw(u, u->io_accounting_base); if (r < 0) { @@ -4414,6 +4427,7 @@ int unit_reset_accounting(Unit *u) { RET_GATHER(r, unit_reset_cpu_accounting(u)); RET_GATHER(r, unit_reset_io_accounting(u)); RET_GATHER(r, unit_reset_ip_accounting(u)); + unit_reset_memory_accounting_last(u); return r; } diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 157ac7271f..f1b674b4b7 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -376,7 +376,9 @@ int unit_get_io_accounting(Unit *u, CGroupIOAccountingMetric metric, bool allow_ int unit_get_ip_accounting(Unit *u, CGroupIPAccountingMetric metric, uint64_t *ret); int unit_reset_cpu_accounting(Unit *u); +void unit_reset_memory_accounting_last(Unit *u); int unit_reset_ip_accounting(Unit *u); +void unit_reset_io_accounting_last(Unit *u); int unit_reset_io_accounting(Unit *u); int unit_reset_accounting(Unit *u); diff --git a/src/core/unit.c b/src/core/unit.c index b88e28d77e..b37b1710f2 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -115,8 +115,9 @@ Unit* unit_new(Manager *m, size_t size) { u->ref_gid = GID_INVALID; u->cpu_usage_last = NSEC_INFINITY; - FOREACH_ARRAY(i, u->memory_accounting_last, ELEMENTSOF(u->memory_accounting_last)) - *i = UINT64_MAX; + unit_reset_memory_accounting_last(u); + + unit_reset_io_accounting_last(u); u->cgroup_invalidated_mask |= CGROUP_MASK_BPF_FIREWALL; u->failure_action_exit_status = u->success_action_exit_status = -1; @@ -124,9 +125,6 @@ Unit* unit_new(Manager *m, size_t size) { u->ip_accounting_ingress_map_fd = -EBADF; u->ip_accounting_egress_map_fd = -EBADF; - FOREACH_ARRAY(i, u->io_accounting_last, _CGROUP_IO_ACCOUNTING_METRIC_MAX) - *i = UINT64_MAX; - u->ipv4_allow_map_fd = -EBADF; u->ipv6_allow_map_fd = -EBADF; u->ipv4_deny_map_fd = -EBADF;