v01: core: add MemorySwapLimit= to limit memory+swap#2171
v01: core: add MemorySwapLimit= to limit memory+swap#2171walyong wants to merge 1 commit intosystemd:masterfrom walyong:memcg_v01
Conversation
Similar to MemoryLimit=, MemorySwapLimit= limits memory+swap usage. This controls the "memory.memsw.limit_in_bytes" control group attribute. And when MemorySwapLimit= was set, if MemoryLimit= was not set or bigger than MemorySwapLimit= then set MemoryLimit= as same amount of value with MemorySwapLimit=.
|
Are there any tests? |
|
I wrote local test code memory-swap-limit-test.c: #define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
static int get_memory_cgroup_of_my(char **path) {
char *p = NULL, *proc_cgroup = NULL;
pid_t pid = getpid();
char buf[LINE_MAX];
FILE *f = NULL;
asprintf(&proc_cgroup, "/proc/%d/cgroup", pid);
f = fopen(proc_cgroup, "re");
if (!f)
return -errno;
for (;;) {
char *name = NULL;
int i;
if (!fgets(buf, sizeof(buf), f)) {
if (ferror(f))
return -errno;
break;
}
sscanf(buf, "%d:%m[^:]:%ms", &i, &name, &p);
if (!strcmp(name, "memory")) {
*path = p;
free(proc_cgroup);
fclose(f);
return 0;
}
}
free(proc_cgroup);
fclose(f);
return -ENODATA;
}
static int find_cgroup_path(char **path) {
char *cg_node = NULL;
char *p = NULL;
int r;
r = get_memory_cgroup_of_my(&cg_node);
if (r < 0)
return r;
if (!strcmp(cg_node, "/")) {
fprintf(stderr, "Should be run as systemd service\n");
free(cg_node);
return -ENOTSUP;
}
asprintf(&p, "/sys/fs/cgroup/memory%s", cg_node);
*path = p;
free(cg_node);
return 0;
}
static void display_memcg_info(const char *path) {
char *list[] = {
"memory.usage_in_bytes",
"memory.limit_in_bytes",
"memory.failcnt",
"memory.memsw.usage_in_bytes",
"memory.memsw.limit_in_bytes",
"memory.memsw.failcnt",
NULL
};
char node[PATH_MAX];
char buf[LINE_MAX];
int i;
for (i = 0; list[i] != NULL; i++) {
FILE *f = NULL;
snprintf(node, PATH_MAX, "%s/%s", path, list[i]);
f = fopen(node, "re");
for (;;) {
if (!fgets(buf, sizeof(buf), f))
break;
printf("%s: %s\n",list[i], buf);
}
fclose(f);
}
}
int main(int argc, char *argv[]) {
char *cg_path = NULL;
void *p = NULL;
int i, r;
r = find_cgroup_path(&cg_path);
if (r < 0)
return EXIT_FAILURE;
printf("cgroup path: %s\n", cg_path);
display_memcg_info(cg_path);
for (i = 0;; i++) {
p = malloc(500 << 10);
if (!p) {
fprintf(stderr, "!!! malloc failed: %s\n", strerror(errno));
continue;
}
memset(p, 0x0, 500 << 10);
fprintf(stdout, "!!! malloc successed. Count %d\n", i+1);
display_memcg_info(cg_path);
sleep(1);
}
return 0;
}And also I wrote a service file to test as memory-swap-limit-test.service: [Unit]
Description=Test MemorySwapLimit=
[Service]
ExecStart=/home/walyong/tmp/memory-swap-limit/memory-swap-limit-test
MemoryLimit=5M
MemorySwapLimit=10M
StandardOutput=journal
StandardError=inheritAnd run: [root@laptop system]# systemctl daemon-reload
[root@laptop system]# systemctl start memory-swap-limit.service; systemctl status memory-swap-limit.service
● memory-swap-limit.service - Test MemorySwapLimit=
Loaded: loaded (/usr/lib/systemd/system/memory-swap-limit.service; static; vendor preset: disabled)
Active: active (running) since Wed 2015-12-16 13:37:44 KST; 96ms ago
Main PID: 14870 (memory-swap-lim)
Memory: 596.0K (limit: 5.0M) (with swap limit: 10.0M)
CGroup: /system.slice/memory-swap-limit.service
└─14870 /home/walyong/tmp/memory-swap-limit/memory-swap-limit-test
Dec 16 13:37:44 laptop.walyong.com systemd[1]: Started Test MemorySwapLimit=.Finally, I can get below logs: And I'd also tested with only MemoryLimit= option: [Unit]
Description=Test MemorySwapLimit=
[Service]
ExecStart=/home/walyong/tmp/memory-swap-limit/memory-swap-limit-test
MemoryLimit=5M
StandardOutput=journal
StandardError=inheritThen, the service was not killed well: So I had to stop that. |
|
At this point, I don't think we should support cgroups properties that have no future in the unified hierarchy. Or does this one have a counterpart on the unified hierarchy? |
|
It seems currently being implemented now: I will create new PR after kernel has facility for accounting swap. |
|
Well, basically, I think we shouldn't add new support for something that has no future. I am fine howeve, to add support for something that has a clear future and then adding compat for old setups, if that's possible. Or in other words, as soon as it is clear how the settings will look like in the unified hierarchy, we can add support for this setting, and then also make it work on the legacy hierararchy too. But I am not keen on adding support for the legacy hierarchy before the unified hierarchy support is clear, because the exposed knobs should follow the new design, not the old design. I hope this makes sense? Let's delay this until the swap memory knobs land in the kernel hence! Sorry! |
Similar to MemoryLimit=, MemorySwapLimit= limits memory+swap usage. This
controls the "memory.memsw.limit_in_bytes" control group attribute.
And when MemorySwapLimit= was set, if MemoryLimit= was not set or bigger
than MemorySwapLimit= then set MemoryLimit= as same amount of
value with MemorySwapLimit=.
https://www.kernel.org/doc/Documentation/cgroups/memory.txt: