X Tutup
Skip to content

Commit 93ff34e

Browse files
committed
core: add MemoryAvailable unit property
Try to infer the unused memory that a unit can claim before the memory.max limit is reached, including any limit set on any parent slice above the unit itself.
1 parent d477a09 commit 93ff34e

File tree

6 files changed

+135
-1
lines changed

6 files changed

+135
-1
lines changed

man/org.freedesktop.systemd1.xml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
24012401
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
24022402
readonly t MemoryCurrent = ...;
24032403
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
2404+
readonly t MemoryAvailable = ...;
2405+
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
24042406
readonly t CPUUsageNSec = ...;
24052407
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
24062408
readonly ay EffectiveCPUs = [...];
@@ -3504,6 +3506,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
35043506

35053507
<variablelist class="dbus-property" generated="True" extra-ref="MemoryCurrent"/>
35063508

3509+
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAvailable"/>
3510+
35073511
<variablelist class="dbus-property" generated="True" extra-ref="CPUUsageNSec"/>
35083512

35093513
<variablelist class="dbus-property" generated="True" extra-ref="EffectiveCPUs"/>
@@ -4063,6 +4067,11 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
40634067
<varname>MountImages</varname>
40644068
<varname>ExtensionImages</varname>
40654069
see systemd.exec(5) for their meaning.</para>
4070+
4071+
<para><varname>MemoryAvailable</varname> indicates how much unused memory is available to the unit before
4072+
the <literal>MemoryMax</literal> or <literal>MemoryHigh</literal> (whichever is lower) limit set by the cgroup
4073+
memory controller is reached. It will take into consideration limits on all parent slices, other than the
4074+
limits set on the unit itself.</para>
40664075
</refsect2>
40674076
</refsect1>
40684077

@@ -4196,6 +4205,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
41964205
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
41974206
readonly t MemoryCurrent = ...;
41984207
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
4208+
readonly t MemoryAvailable = ...;
4209+
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
41994210
readonly t CPUUsageNSec = ...;
42004211
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
42014212
readonly ay EffectiveCPUs = [...];
@@ -5321,6 +5332,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
53215332

53225333
<variablelist class="dbus-property" generated="True" extra-ref="MemoryCurrent"/>
53235334

5335+
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAvailable"/>
5336+
53245337
<variablelist class="dbus-property" generated="True" extra-ref="CPUUsageNSec"/>
53255338

53265339
<variablelist class="dbus-property" generated="True" extra-ref="EffectiveCPUs"/>
@@ -5915,6 +5928,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
59155928
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
59165929
readonly t MemoryCurrent = ...;
59175930
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
5931+
readonly t MemoryAvailable = ...;
5932+
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
59185933
readonly t CPUUsageNSec = ...;
59195934
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
59205935
readonly ay EffectiveCPUs = [...];
@@ -6886,6 +6901,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
68866901

68876902
<variablelist class="dbus-property" generated="True" extra-ref="MemoryCurrent"/>
68886903

6904+
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAvailable"/>
6905+
68896906
<variablelist class="dbus-property" generated="True" extra-ref="CPUUsageNSec"/>
68906907

68916908
<variablelist class="dbus-property" generated="True" extra-ref="EffectiveCPUs"/>
@@ -7601,6 +7618,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
76017618
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
76027619
readonly t MemoryCurrent = ...;
76037620
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
7621+
readonly t MemoryAvailable = ...;
7622+
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
76047623
readonly t CPUUsageNSec = ...;
76057624
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
76067625
readonly ay EffectiveCPUs = [...];
@@ -8544,6 +8563,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
85448563

85458564
<variablelist class="dbus-property" generated="True" extra-ref="MemoryCurrent"/>
85468565

8566+
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAvailable"/>
8567+
85478568
<variablelist class="dbus-property" generated="True" extra-ref="CPUUsageNSec"/>
85488569

85498570
<variablelist class="dbus-property" generated="True" extra-ref="EffectiveCPUs"/>
@@ -9112,6 +9133,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
91129133
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
91139134
readonly t MemoryCurrent = ...;
91149135
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
9136+
readonly t MemoryAvailable = ...;
9137+
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
91159138
readonly t CPUUsageNSec = ...;
91169139
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
91179140
readonly ay EffectiveCPUs = [...];
@@ -9403,6 +9426,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
94039426

94049427
<variablelist class="dbus-property" generated="True" extra-ref="MemoryCurrent"/>
94059428

9429+
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAvailable"/>
9430+
94069431
<variablelist class="dbus-property" generated="True" extra-ref="CPUUsageNSec"/>
94079432

94089433
<variablelist class="dbus-property" generated="True" extra-ref="EffectiveCPUs"/>
@@ -9571,6 +9596,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
95719596
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
95729597
readonly t MemoryCurrent = ...;
95739598
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
9599+
readonly t MemoryAvailable = ...;
9600+
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
95749601
readonly t CPUUsageNSec = ...;
95759602
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
95769603
readonly ay EffectiveCPUs = [...];
@@ -9904,6 +9931,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
99049931

99059932
<variablelist class="dbus-property" generated="True" extra-ref="MemoryCurrent"/>
99069933

9934+
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAvailable"/>
9935+
99079936
<variablelist class="dbus-property" generated="True" extra-ref="CPUUsageNSec"/>
99089937

99099938
<variablelist class="dbus-property" generated="True" extra-ref="EffectiveCPUs"/>

src/core/cgroup.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,77 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
34023402
return 1;
34033403
}
34043404

3405+
int unit_get_memory_available(Unit *u, uint64_t *ret) {
3406+
uint64_t unit_current, available = UINT64_MAX;
3407+
CGroupContext *unit_context;
3408+
const char *memory_file;
3409+
int r;
3410+
3411+
assert(u);
3412+
assert(ret);
3413+
3414+
/* If data from cgroups can be accessed, try to find out how much more memory a unit can
3415+
* claim before hitting the configured cgroup limits (if any). Consider both MemoryHigh
3416+
* and MemoryMax, and also any slice the unit might be nested below. */
3417+
3418+
if (!UNIT_CGROUP_BOOL(u, memory_accounting))
3419+
return -ENODATA;
3420+
3421+
if (!u->cgroup_path)
3422+
return -ENODATA;
3423+
3424+
/* The root cgroup doesn't expose this information */
3425+
if (unit_has_host_root_cgroup(u))
3426+
return -ENODATA;
3427+
3428+
if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
3429+
return -ENODATA;
3430+
3431+
r = cg_all_unified();
3432+
if (r < 0)
3433+
return r;
3434+
memory_file = r > 0 ? "memory.current" : "memory.usage_in_bytes";
3435+
3436+
r = cg_get_attribute_as_uint64("memory", u->cgroup_path, memory_file, &unit_current);
3437+
if (r < 0)
3438+
return r;
3439+
3440+
assert_se(unit_context = unit_get_cgroup_context(u));
3441+
3442+
if (unit_context->memory_max != UINT64_MAX || unit_context->memory_high != UINT64_MAX)
3443+
available = LESS_BY(MIN(unit_context->memory_max, unit_context->memory_high), unit_current);
3444+
3445+
for (Unit *slice = UNIT_GET_SLICE(u); slice; slice = UNIT_GET_SLICE(slice)) {
3446+
uint64_t slice_current, slice_available = UINT64_MAX;
3447+
CGroupContext *slice_context;
3448+
3449+
/* No point in continuing if we can't go any lower */
3450+
if (available == 0)
3451+
break;
3452+
3453+
if (!slice->cgroup_path)
3454+
continue;
3455+
3456+
slice_context = unit_get_cgroup_context(slice);
3457+
if (!slice_context)
3458+
continue;
3459+
3460+
if (slice_context->memory_max == UINT64_MAX && slice_context->memory_high == UINT64_MAX)
3461+
continue;
3462+
3463+
r = cg_get_attribute_as_uint64("memory", slice->cgroup_path, memory_file, &slice_current);
3464+
if (r < 0)
3465+
continue;
3466+
3467+
slice_available = LESS_BY(MIN(slice_context->memory_max, slice_context->memory_high), slice_current);
3468+
available = MIN(slice_available, available);
3469+
}
3470+
3471+
*ret = available;
3472+
3473+
return 0;
3474+
}
3475+
34053476
int unit_get_memory_current(Unit *u, uint64_t *ret) {
34063477
int r;
34073478

src/core/cgroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ int unit_watch_all_pids(Unit *u);
282282
int unit_synthesize_cgroup_empty_event(Unit *u);
283283

284284
int unit_get_memory_current(Unit *u, uint64_t *ret);
285+
int unit_get_memory_available(Unit *u, uint64_t *ret);
285286
int unit_get_tasks_current(Unit *u, uint64_t *ret);
286287
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
287288
int unit_get_io_accounting(Unit *u, CGroupIOAccountingMetric metric, bool allow_cache, uint64_t *ret);

src/core/dbus-unit.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,30 @@ static int property_get_current_memory(
10971097
return sd_bus_message_append(reply, "t", sz);
10981098
}
10991099

1100+
static int property_get_available_memory(
1101+
sd_bus *bus,
1102+
const char *path,
1103+
const char *interface,
1104+
const char *property,
1105+
sd_bus_message *reply,
1106+
void *userdata,
1107+
sd_bus_error *error) {
1108+
1109+
uint64_t sz = UINT64_MAX;
1110+
Unit *u = userdata;
1111+
int r;
1112+
1113+
assert(bus);
1114+
assert(reply);
1115+
assert(u);
1116+
1117+
r = unit_get_memory_available(u, &sz);
1118+
if (r < 0 && r != -ENODATA)
1119+
log_unit_warning_errno(u, r, "Failed to get total available memory from cgroup: %m");
1120+
1121+
return sd_bus_message_append(reply, "t", sz);
1122+
}
1123+
11001124
static int property_get_current_tasks(
11011125
sd_bus *bus,
11021126
const char *path,
@@ -1541,6 +1565,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
15411565
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
15421566
SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
15431567
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
1568+
SD_BUS_PROPERTY("MemoryAvailable", "t", property_get_available_memory, 0, 0),
15441569
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
15451570
SD_BUS_PROPERTY("EffectiveCPUs", "ay", property_get_cpuset_cpus, 0, 0),
15461571
SD_BUS_PROPERTY("EffectiveMemoryNodes", "ay", property_get_cpuset_mems, 0, 0),

src/shared/bus-print-properties.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
165165

166166
bus_print_property_value(name, expected_value, flags, "[not set]");
167167

168-
else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
168+
else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "MemoryAvailable") && u == CGROUP_LIMIT_MAX) ||
169169
(STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == UINT64_MAX) ||
170170
(startswith(name, "Limit") && u == UINT64_MAX) ||
171171
(startswith(name, "DefaultLimit") && u == UINT64_MAX))

src/systemctl/systemctl-show.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ typedef struct UnitStatusInfo {
247247
uint64_t memory_max;
248248
uint64_t memory_swap_max;
249249
uint64_t memory_limit;
250+
uint64_t memory_available;
250251
uint64_t cpu_usage_nsec;
251252
uint64_t tasks_current;
252253
uint64_t tasks_max;
@@ -682,6 +683,7 @@ static void print_status_info(
682683
if (i->memory_min > 0 || i->memory_low > 0 ||
683684
i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
684685
i->memory_swap_max != CGROUP_LIMIT_MAX ||
686+
i->memory_available != CGROUP_LIMIT_MAX ||
685687
i->memory_limit != CGROUP_LIMIT_MAX) {
686688
const char *prefix = "";
687689

@@ -710,6 +712,10 @@ static void print_status_info(
710712
printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
711713
prefix = " ";
712714
}
715+
if (i->memory_available != CGROUP_LIMIT_MAX) {
716+
printf("%savailable: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_available));
717+
prefix = " ";
718+
}
713719
printf(")");
714720
}
715721
printf("\n");
@@ -1827,6 +1833,7 @@ static int show_one(
18271833
{ "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
18281834
{ "What", "s", NULL, offsetof(UnitStatusInfo, what) },
18291835
{ "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
1836+
{ "MemoryAvailable", "t", NULL, offsetof(UnitStatusInfo, memory_available) },
18301837
{ "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
18311838
{ "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
18321839
{ "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
@@ -1869,6 +1876,7 @@ static int show_one(
18691876
.memory_max = CGROUP_LIMIT_MAX,
18701877
.memory_swap_max = CGROUP_LIMIT_MAX,
18711878
.memory_limit = UINT64_MAX,
1879+
.memory_available = CGROUP_LIMIT_MAX,
18721880
.cpu_usage_nsec = UINT64_MAX,
18731881
.tasks_current = UINT64_MAX,
18741882
.tasks_max = UINT64_MAX,

0 commit comments

Comments
 (0)
X Tutup