mirror of
https://github.com/systemd/systemd.git
synced 2025-03-09 12:58:26 +03:00
Merge pull request #29117 from Werkov/memory_available
Make MemoryAvailable= more useful
This commit is contained in:
commit
66e089af85
@ -4603,10 +4603,11 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
<varname>ExtensionDirectories</varname>
|
||||
see systemd.exec(5) for their meaning.</para>
|
||||
|
||||
<para><varname>MemoryAvailable</varname> indicates how much unused memory is available to the unit before
|
||||
the <literal>MemoryMax</literal> or <literal>MemoryHigh</literal> (whichever is lower) limit set by the cgroup
|
||||
memory controller is reached. It will take into consideration limits on all parent slices, other than the
|
||||
limits set on the unit itself.</para>
|
||||
<para><varname>MemoryAvailable</varname> takes into account unit's and parents' <literal>MemoryMax</literal>
|
||||
or <literal>MemoryHigh</literal> or physically available RAM versus given level's memory consumption
|
||||
and takes minimum. Beware that other units below the tightest parent slice may consume the memory quicker
|
||||
and less than reported value would remain for own allocation.
|
||||
It works better in conjunction with <varname>MemoryAccounting=yes</varname> on involved units.</para>
|
||||
|
||||
<para><varname>DelegateSubgroup</varname> contains the cgroup subgroup to place invoked unit processes
|
||||
in. As configured by the option of the same name in unit files. This is set to the empty string when it
|
||||
|
@ -3751,10 +3751,7 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
|
||||
}
|
||||
|
||||
int unit_get_memory_available(Unit *u, uint64_t *ret) {
|
||||
uint64_t unit_current, available = UINT64_MAX;
|
||||
CGroupContext *unit_context;
|
||||
const char *memory_file;
|
||||
int r;
|
||||
uint64_t available = UINT64_MAX, current = 0;
|
||||
|
||||
assert(u);
|
||||
assert(ret);
|
||||
@ -3763,58 +3760,33 @@ int unit_get_memory_available(Unit *u, uint64_t *ret) {
|
||||
* claim before hitting the configured cgroup limits (if any). Consider both MemoryHigh
|
||||
* and MemoryMax, and also any slice the unit might be nested below. */
|
||||
|
||||
if (!UNIT_CGROUP_BOOL(u, memory_accounting))
|
||||
return -ENODATA;
|
||||
|
||||
if (!u->cgroup_path)
|
||||
return -ENODATA;
|
||||
|
||||
/* The root cgroup doesn't expose this information */
|
||||
if (unit_has_host_root_cgroup(u))
|
||||
return -ENODATA;
|
||||
|
||||
if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
|
||||
return -ENODATA;
|
||||
|
||||
r = cg_all_unified();
|
||||
if (r < 0)
|
||||
return r;
|
||||
memory_file = r > 0 ? "memory.current" : "memory.usage_in_bytes";
|
||||
|
||||
r = cg_get_attribute_as_uint64("memory", u->cgroup_path, memory_file, &unit_current);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert_se(unit_context = unit_get_cgroup_context(u));
|
||||
|
||||
if (unit_context->memory_max != UINT64_MAX || unit_context->memory_high != UINT64_MAX)
|
||||
available = LESS_BY(MIN(unit_context->memory_max, unit_context->memory_high), unit_current);
|
||||
|
||||
for (Unit *slice = UNIT_GET_SLICE(u); slice; slice = UNIT_GET_SLICE(slice)) {
|
||||
uint64_t slice_current, slice_available = UINT64_MAX;
|
||||
CGroupContext *slice_context;
|
||||
do {
|
||||
uint64_t unit_available, unit_limit = UINT64_MAX;
|
||||
CGroupContext *unit_context;
|
||||
|
||||
/* No point in continuing if we can't go any lower */
|
||||
if (available == 0)
|
||||
break;
|
||||
|
||||
if (!slice->cgroup_path)
|
||||
unit_context = unit_get_cgroup_context(u);
|
||||
if (!unit_context)
|
||||
return -ENODATA;
|
||||
|
||||
if (!u->cgroup_path)
|
||||
continue;
|
||||
|
||||
slice_context = unit_get_cgroup_context(slice);
|
||||
if (!slice_context)
|
||||
continue;
|
||||
(void) unit_get_memory_current(u, ¤t);
|
||||
/* in case of error, previous current propagates as lower bound */
|
||||
|
||||
if (slice_context->memory_max == UINT64_MAX && slice_context->memory_high == UINT64_MAX)
|
||||
if (unit_has_name(u, SPECIAL_ROOT_SLICE))
|
||||
unit_limit = physical_memory();
|
||||
else if (unit_context->memory_max == UINT64_MAX && unit_context->memory_high == UINT64_MAX)
|
||||
continue;
|
||||
unit_limit = MIN3(unit_limit, unit_context->memory_max, unit_context->memory_high);
|
||||
|
||||
r = cg_get_attribute_as_uint64("memory", slice->cgroup_path, memory_file, &slice_current);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
slice_available = LESS_BY(MIN(slice_context->memory_max, slice_context->memory_high), slice_current);
|
||||
available = MIN(slice_available, available);
|
||||
}
|
||||
unit_available = LESS_BY(unit_limit, current);
|
||||
available = MIN(unit_available, available);
|
||||
} while ((u = UNIT_GET_SLICE(u)));
|
||||
|
||||
*ret = available;
|
||||
|
||||
|
@ -157,12 +157,12 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
|
||||
else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
|
||||
(STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
|
||||
(STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
|
||||
(STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == UINT64_MAX) ||
|
||||
(STR_IN_SET(name, "MemoryCurrent", "MemoryAvailable", "TasksCurrent") && u == UINT64_MAX) ||
|
||||
(endswith(name, "NSec") && u == UINT64_MAX))
|
||||
|
||||
bus_print_property_value(name, expected_value, flags, "[not set]");
|
||||
|
||||
else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit", "MemoryAvailable") && u == CGROUP_LIMIT_MAX) ||
|
||||
else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
|
||||
(STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == UINT64_MAX) ||
|
||||
(startswith(name, "Limit") && u == UINT64_MAX) ||
|
||||
(startswith(name, "DefaultLimit") && u == UINT64_MAX))
|
||||
|
Loading…
x
Reference in New Issue
Block a user