All of lore.kernel.org
 help / color / mirror / Atom feed
From: Shuah Khan <shuah@kernel.org>
To: jgkamat@fb.com
Cc: linux-kselftest@vger.kernel.org, Roman Gushchin <guro@fb.com>,
	Tejun Heo <tj@kernel.org>,
	kernel-team@fb.com, linux-kernel@vger.kernel.org,
	jaygkamat@gmail.com, Shuah Khan <shuah@kernel.org>
Subject: Re: [PATCH 2/2] Add tests for memory.oom.group
Date: Wed, 5 Sep 2018 09:21:46 -0600	[thread overview]
Message-ID: <2f5ffeaf-3161-37e2-73a3-ae449aecca40@kernel.org> (raw)
In-Reply-To: <20180905010827.27743-3-jgkamat@fb.com>

Hi Jay,

Thanks for the patch. Comments below:

On 09/04/2018 07:08 PM, jgkamat@fb.com wrote:
> From: Jay Kamat <jgkamat@fb.com>
> 
> Add tests for memory.oom.group for the following cases:
> - Killing all processes in a leaf cgroup, but leaving the
>   parent untouched
> - Killing all processes in a parent and leaf cgroup
> - Keeping processes marked by OOM_SCORE_ADJ_MIN alive when considered
>   for being killed by the group oom killer.
> 
> Signed-off-by: Jay Kamat <jgkamat@fb.com>
> ---
>  tools/testing/selftests/cgroup/cgroup_util.c  |  21 ++
>  tools/testing/selftests/cgroup/cgroup_util.h  |   1 +
>  .../selftests/cgroup/test_memcontrol.c        | 205 ++++++++++++++++++
>  3 files changed, 227 insertions(+)
> 
> diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c
> index 4aadf38bcd5d..6799c69d7f03 100644
> --- a/tools/testing/selftests/cgroup/cgroup_util.c
> +++ b/tools/testing/selftests/cgroup/cgroup_util.c
> @@ -338,3 +338,24 @@ int is_swap_enabled(void)
>  
>  	return cnt > 1;
>  }
> +
> +int set_oom_adj_score(int pid, int score)
> +{
> +	char path[PATH_MAX];
> +	int fd, len;
> +
> +	sprintf(path, "/proc/%d/oom_score_adj", pid);
> +
> +	fd = open(path, O_WRONLY | O_APPEND);
> +	if (fd < 0)
> +		return fd;
> +
> +	len = dprintf(fd, "%d", score);
> +	if (len < 0) {
> +		close(fd);
> +		return len;
> +	}
> +
> +	close(fd);
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/cgroup/cgroup_util.h b/tools/testing/selftests/cgroup/cgroup_util.h
> index fe82a297d4e0..cabd43fd137a 100644
> --- a/tools/testing/selftests/cgroup/cgroup_util.h
> +++ b/tools/testing/selftests/cgroup/cgroup_util.h
> @@ -39,3 +39,4 @@ extern int get_temp_fd(void);
>  extern int alloc_pagecache(int fd, size_t size);
>  extern int alloc_anon(const char *cgroup, void *arg);
>  extern int is_swap_enabled(void);
> +extern int set_oom_adj_score(int pid, int score);
> diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c
> index cf0bddc9d271..017c15a7a935 100644
> --- a/tools/testing/selftests/cgroup/test_memcontrol.c
> +++ b/tools/testing/selftests/cgroup/test_memcontrol.c
> @@ -2,6 +2,7 @@
>  #define _GNU_SOURCE
>  
>  #include <linux/limits.h>
> +#include <linux/oom.h>
>  #include <fcntl.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -202,6 +203,36 @@ static int alloc_pagecache_50M_noexit(const char *cgroup, void *arg)
>  	return 0;
>  }
>  
> +static int alloc_anon_noexit(const char *cgroup, void *arg)
> +{
> +	int ppid = getppid();
> +
> +	if (alloc_anon(cgroup, arg))
> +		return -1;
> +
> +	while (getppid() == ppid)
> +		sleep(1);
> +
> +	return 0;
> +}
> +
> +/*
> + * Wait until processes are killed asynchronously by the OOM killer
> + * If we exceed a timeout, fail.
> + */
> +static int cg_test_proc_killed(const char *cgroup)
> +{
> +	int limit;
> +
> +	for (limit = 10; limit > 0; limit--) {
> +		if (cg_read_strcmp(cgroup, "cgroup.procs", "") == 0)
> +			return 0;
> +
> +		usleep(100000);
> +	}
> +	return -1;
> +}
> +
>  /*
>   * First, this test creates the following hierarchy:
>   * A       memory.min = 50M,  memory.max = 200M
> @@ -964,6 +995,177 @@ static int test_memcg_sock(const char *root)
>  	return ret;
>  }
>  
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes in the leaf (but not the parent) were killed.
> + */
> +static int test_memcg_oom_group_leaf_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *parent, *child;
> +
> +	parent = cg_name(root, "memcg_test_0");
> +	child = cg_name(root, "memcg_test_0/memcg_test_1");
> +
> +	if (!parent || !child)
> +		goto cleanup;
> +
> +	if (cg_create(parent))
> +		goto cleanup;
> +
> +	if (cg_create(child))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "cgroup.subtree_control", "+memory"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.max", "50M"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	if (!cg_run(child, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_test_proc_killed(child))
> +		goto cleanup;
> +
> +	if (cg_read_key_long(child, "memory.events", "oom_kill ") <= 0)
> +		goto cleanup;
> +
> +	if (cg_read_key_long(parent, "memory.events", "oom_kill ") != 0)
> +		goto cleanup;
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (child)
> +		cg_destroy(child);
> +	if (parent)
> +		cg_destroy(parent);
> +	free(child);
> +	free(parent);
> +
> +	return ret;
> +}
> +
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes in the parent and leaf were killed.
> + */
> +static int test_memcg_oom_group_parent_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *parent, *child;
> +
> +	parent = cg_name(root, "memcg_test_0");
> +	child = cg_name(root, "memcg_test_0/memcg_test_1");
> +
> +	if (!parent || !child)
> +		goto cleanup;
> +
> +	if (cg_create(parent))
> +		goto cleanup;
> +
> +	if (cg_create(child))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.max", "80M"))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +
> +	if (!cg_run(child, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_test_proc_killed(child))
> +		goto cleanup;
> +	if (cg_test_proc_killed(parent))
> +		goto cleanup;
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (child)
> +		cg_destroy(child);
> +	if (parent)
> +		cg_destroy(parent);
> +	free(child);
> +	free(parent);
> +
> +	return ret;
> +}
> +
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes were killed except those set with OOM_SCORE_ADJ_MIN
> + */
> +static int test_memcg_oom_group_score_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *memcg;
> +	int safe_pid;
> +
> +	memcg = cg_name(root, "memcg_test_0");
> +
> +	if (!memcg)
> +		goto cleanup;
> +
> +	if (cg_create(memcg))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.max", "50M"))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	safe_pid = cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
> +	if (set_oom_adj_score(safe_pid, OOM_SCORE_ADJ_MIN))
> +		goto cleanup;
> +
> +	cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
> +	if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_read_key_long(memcg, "memory.events", "oom_kill ") != 3)
> +		goto cleanup;
> +
> +	if (kill(safe_pid, SIGKILL))
> +		return -1;

Missing cleanup? Should the return be just ret which is KSFT_FAIL
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (memcg)
> +		cg_destroy(memcg);
> +	free(memcg);
> +
> +	return ret;
> +}
> +
> +
>  #define T(x) { x, #x }
>  struct memcg_test {
>  	int (*fn)(const char *root);
> @@ -978,6 +1180,9 @@ struct memcg_test {
>  	T(test_memcg_oom_events),
>  	T(test_memcg_swap_max),
>  	T(test_memcg_sock),
> +	T(test_memcg_oom_group_leaf_events),
> +	T(test_memcg_oom_group_parent_events),
> +	T(test_memcg_oom_group_score_events),
>  };
>  #undef T
>  
> 

thanks,
-- Shuah

WARNING: multiple messages have this Message-ID (diff)
From: shuah at kernel.org (Shuah Khan)
Subject: [PATCH 2/2] Add tests for memory.oom.group
Date: Wed, 5 Sep 2018 09:21:46 -0600	[thread overview]
Message-ID: <2f5ffeaf-3161-37e2-73a3-ae449aecca40@kernel.org> (raw)
In-Reply-To: <20180905010827.27743-3-jgkamat@fb.com>

Hi Jay,

Thanks for the patch. Comments below:

On 09/04/2018 07:08 PM, jgkamat at fb.com wrote:
> From: Jay Kamat <jgkamat at fb.com>
> 
> Add tests for memory.oom.group for the following cases:
> - Killing all processes in a leaf cgroup, but leaving the
>   parent untouched
> - Killing all processes in a parent and leaf cgroup
> - Keeping processes marked by OOM_SCORE_ADJ_MIN alive when considered
>   for being killed by the group oom killer.
> 
> Signed-off-by: Jay Kamat <jgkamat at fb.com>
> ---
>  tools/testing/selftests/cgroup/cgroup_util.c  |  21 ++
>  tools/testing/selftests/cgroup/cgroup_util.h  |   1 +
>  .../selftests/cgroup/test_memcontrol.c        | 205 ++++++++++++++++++
>  3 files changed, 227 insertions(+)
> 
> diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c
> index 4aadf38bcd5d..6799c69d7f03 100644
> --- a/tools/testing/selftests/cgroup/cgroup_util.c
> +++ b/tools/testing/selftests/cgroup/cgroup_util.c
> @@ -338,3 +338,24 @@ int is_swap_enabled(void)
>  
>  	return cnt > 1;
>  }
> +
> +int set_oom_adj_score(int pid, int score)
> +{
> +	char path[PATH_MAX];
> +	int fd, len;
> +
> +	sprintf(path, "/proc/%d/oom_score_adj", pid);
> +
> +	fd = open(path, O_WRONLY | O_APPEND);
> +	if (fd < 0)
> +		return fd;
> +
> +	len = dprintf(fd, "%d", score);
> +	if (len < 0) {
> +		close(fd);
> +		return len;
> +	}
> +
> +	close(fd);
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/cgroup/cgroup_util.h b/tools/testing/selftests/cgroup/cgroup_util.h
> index fe82a297d4e0..cabd43fd137a 100644
> --- a/tools/testing/selftests/cgroup/cgroup_util.h
> +++ b/tools/testing/selftests/cgroup/cgroup_util.h
> @@ -39,3 +39,4 @@ extern int get_temp_fd(void);
>  extern int alloc_pagecache(int fd, size_t size);
>  extern int alloc_anon(const char *cgroup, void *arg);
>  extern int is_swap_enabled(void);
> +extern int set_oom_adj_score(int pid, int score);
> diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c
> index cf0bddc9d271..017c15a7a935 100644
> --- a/tools/testing/selftests/cgroup/test_memcontrol.c
> +++ b/tools/testing/selftests/cgroup/test_memcontrol.c
> @@ -2,6 +2,7 @@
>  #define _GNU_SOURCE
>  
>  #include <linux/limits.h>
> +#include <linux/oom.h>
>  #include <fcntl.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -202,6 +203,36 @@ static int alloc_pagecache_50M_noexit(const char *cgroup, void *arg)
>  	return 0;
>  }
>  
> +static int alloc_anon_noexit(const char *cgroup, void *arg)
> +{
> +	int ppid = getppid();
> +
> +	if (alloc_anon(cgroup, arg))
> +		return -1;
> +
> +	while (getppid() == ppid)
> +		sleep(1);
> +
> +	return 0;
> +}
> +
> +/*
> + * Wait until processes are killed asynchronously by the OOM killer
> + * If we exceed a timeout, fail.
> + */
> +static int cg_test_proc_killed(const char *cgroup)
> +{
> +	int limit;
> +
> +	for (limit = 10; limit > 0; limit--) {
> +		if (cg_read_strcmp(cgroup, "cgroup.procs", "") == 0)
> +			return 0;
> +
> +		usleep(100000);
> +	}
> +	return -1;
> +}
> +
>  /*
>   * First, this test creates the following hierarchy:
>   * A       memory.min = 50M,  memory.max = 200M
> @@ -964,6 +995,177 @@ static int test_memcg_sock(const char *root)
>  	return ret;
>  }
>  
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes in the leaf (but not the parent) were killed.
> + */
> +static int test_memcg_oom_group_leaf_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *parent, *child;
> +
> +	parent = cg_name(root, "memcg_test_0");
> +	child = cg_name(root, "memcg_test_0/memcg_test_1");
> +
> +	if (!parent || !child)
> +		goto cleanup;
> +
> +	if (cg_create(parent))
> +		goto cleanup;
> +
> +	if (cg_create(child))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "cgroup.subtree_control", "+memory"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.max", "50M"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	if (!cg_run(child, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_test_proc_killed(child))
> +		goto cleanup;
> +
> +	if (cg_read_key_long(child, "memory.events", "oom_kill ") <= 0)
> +		goto cleanup;
> +
> +	if (cg_read_key_long(parent, "memory.events", "oom_kill ") != 0)
> +		goto cleanup;
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (child)
> +		cg_destroy(child);
> +	if (parent)
> +		cg_destroy(parent);
> +	free(child);
> +	free(parent);
> +
> +	return ret;
> +}
> +
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes in the parent and leaf were killed.
> + */
> +static int test_memcg_oom_group_parent_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *parent, *child;
> +
> +	parent = cg_name(root, "memcg_test_0");
> +	child = cg_name(root, "memcg_test_0/memcg_test_1");
> +
> +	if (!parent || !child)
> +		goto cleanup;
> +
> +	if (cg_create(parent))
> +		goto cleanup;
> +
> +	if (cg_create(child))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.max", "80M"))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +
> +	if (!cg_run(child, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_test_proc_killed(child))
> +		goto cleanup;
> +	if (cg_test_proc_killed(parent))
> +		goto cleanup;
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (child)
> +		cg_destroy(child);
> +	if (parent)
> +		cg_destroy(parent);
> +	free(child);
> +	free(parent);
> +
> +	return ret;
> +}
> +
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes were killed except those set with OOM_SCORE_ADJ_MIN
> + */
> +static int test_memcg_oom_group_score_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *memcg;
> +	int safe_pid;
> +
> +	memcg = cg_name(root, "memcg_test_0");
> +
> +	if (!memcg)
> +		goto cleanup;
> +
> +	if (cg_create(memcg))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.max", "50M"))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	safe_pid = cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
> +	if (set_oom_adj_score(safe_pid, OOM_SCORE_ADJ_MIN))
> +		goto cleanup;
> +
> +	cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
> +	if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_read_key_long(memcg, "memory.events", "oom_kill ") != 3)
> +		goto cleanup;
> +
> +	if (kill(safe_pid, SIGKILL))
> +		return -1;

Missing cleanup? Should the return be just ret which is KSFT_FAIL
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (memcg)
> +		cg_destroy(memcg);
> +	free(memcg);
> +
> +	return ret;
> +}
> +
> +
>  #define T(x) { x, #x }
>  struct memcg_test {
>  	int (*fn)(const char *root);
> @@ -978,6 +1180,9 @@ struct memcg_test {
>  	T(test_memcg_oom_events),
>  	T(test_memcg_swap_max),
>  	T(test_memcg_sock),
> +	T(test_memcg_oom_group_leaf_events),
> +	T(test_memcg_oom_group_parent_events),
> +	T(test_memcg_oom_group_score_events),
>  };
>  #undef T
>  
> 

thanks,
-- Shuah

WARNING: multiple messages have this Message-ID (diff)
From: shuah@kernel.org (Shuah Khan)
Subject: [PATCH 2/2] Add tests for memory.oom.group
Date: Wed, 5 Sep 2018 09:21:46 -0600	[thread overview]
Message-ID: <2f5ffeaf-3161-37e2-73a3-ae449aecca40@kernel.org> (raw)
Message-ID: <20180905152146.GUNXitFdVjRErOmte4OsvwCRCzYD-6_NWW_C_-vfVAg@z> (raw)
In-Reply-To: <20180905010827.27743-3-jgkamat@fb.com>

Hi Jay,

Thanks for the patch. Comments below:

On 09/04/2018 07:08 PM, jgkamat@fb.com wrote:
> From: Jay Kamat <jgkamat at fb.com>
> 
> Add tests for memory.oom.group for the following cases:
> - Killing all processes in a leaf cgroup, but leaving the
>   parent untouched
> - Killing all processes in a parent and leaf cgroup
> - Keeping processes marked by OOM_SCORE_ADJ_MIN alive when considered
>   for being killed by the group oom killer.
> 
> Signed-off-by: Jay Kamat <jgkamat at fb.com>
> ---
>  tools/testing/selftests/cgroup/cgroup_util.c  |  21 ++
>  tools/testing/selftests/cgroup/cgroup_util.h  |   1 +
>  .../selftests/cgroup/test_memcontrol.c        | 205 ++++++++++++++++++
>  3 files changed, 227 insertions(+)
> 
> diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c
> index 4aadf38bcd5d..6799c69d7f03 100644
> --- a/tools/testing/selftests/cgroup/cgroup_util.c
> +++ b/tools/testing/selftests/cgroup/cgroup_util.c
> @@ -338,3 +338,24 @@ int is_swap_enabled(void)
>  
>  	return cnt > 1;
>  }
> +
> +int set_oom_adj_score(int pid, int score)
> +{
> +	char path[PATH_MAX];
> +	int fd, len;
> +
> +	sprintf(path, "/proc/%d/oom_score_adj", pid);
> +
> +	fd = open(path, O_WRONLY | O_APPEND);
> +	if (fd < 0)
> +		return fd;
> +
> +	len = dprintf(fd, "%d", score);
> +	if (len < 0) {
> +		close(fd);
> +		return len;
> +	}
> +
> +	close(fd);
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/cgroup/cgroup_util.h b/tools/testing/selftests/cgroup/cgroup_util.h
> index fe82a297d4e0..cabd43fd137a 100644
> --- a/tools/testing/selftests/cgroup/cgroup_util.h
> +++ b/tools/testing/selftests/cgroup/cgroup_util.h
> @@ -39,3 +39,4 @@ extern int get_temp_fd(void);
>  extern int alloc_pagecache(int fd, size_t size);
>  extern int alloc_anon(const char *cgroup, void *arg);
>  extern int is_swap_enabled(void);
> +extern int set_oom_adj_score(int pid, int score);
> diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c
> index cf0bddc9d271..017c15a7a935 100644
> --- a/tools/testing/selftests/cgroup/test_memcontrol.c
> +++ b/tools/testing/selftests/cgroup/test_memcontrol.c
> @@ -2,6 +2,7 @@
>  #define _GNU_SOURCE
>  
>  #include <linux/limits.h>
> +#include <linux/oom.h>
>  #include <fcntl.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -202,6 +203,36 @@ static int alloc_pagecache_50M_noexit(const char *cgroup, void *arg)
>  	return 0;
>  }
>  
> +static int alloc_anon_noexit(const char *cgroup, void *arg)
> +{
> +	int ppid = getppid();
> +
> +	if (alloc_anon(cgroup, arg))
> +		return -1;
> +
> +	while (getppid() == ppid)
> +		sleep(1);
> +
> +	return 0;
> +}
> +
> +/*
> + * Wait until processes are killed asynchronously by the OOM killer
> + * If we exceed a timeout, fail.
> + */
> +static int cg_test_proc_killed(const char *cgroup)
> +{
> +	int limit;
> +
> +	for (limit = 10; limit > 0; limit--) {
> +		if (cg_read_strcmp(cgroup, "cgroup.procs", "") == 0)
> +			return 0;
> +
> +		usleep(100000);
> +	}
> +	return -1;
> +}
> +
>  /*
>   * First, this test creates the following hierarchy:
>   * A       memory.min = 50M,  memory.max = 200M
> @@ -964,6 +995,177 @@ static int test_memcg_sock(const char *root)
>  	return ret;
>  }
>  
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes in the leaf (but not the parent) were killed.
> + */
> +static int test_memcg_oom_group_leaf_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *parent, *child;
> +
> +	parent = cg_name(root, "memcg_test_0");
> +	child = cg_name(root, "memcg_test_0/memcg_test_1");
> +
> +	if (!parent || !child)
> +		goto cleanup;
> +
> +	if (cg_create(parent))
> +		goto cleanup;
> +
> +	if (cg_create(child))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "cgroup.subtree_control", "+memory"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.max", "50M"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(child, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	if (!cg_run(child, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_test_proc_killed(child))
> +		goto cleanup;
> +
> +	if (cg_read_key_long(child, "memory.events", "oom_kill ") <= 0)
> +		goto cleanup;
> +
> +	if (cg_read_key_long(parent, "memory.events", "oom_kill ") != 0)
> +		goto cleanup;
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (child)
> +		cg_destroy(child);
> +	if (parent)
> +		cg_destroy(parent);
> +	free(child);
> +	free(parent);
> +
> +	return ret;
> +}
> +
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes in the parent and leaf were killed.
> + */
> +static int test_memcg_oom_group_parent_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *parent, *child;
> +
> +	parent = cg_name(root, "memcg_test_0");
> +	child = cg_name(root, "memcg_test_0/memcg_test_1");
> +
> +	if (!parent || !child)
> +		goto cleanup;
> +
> +	if (cg_create(parent))
> +		goto cleanup;
> +
> +	if (cg_create(child))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.max", "80M"))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(parent, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +	cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
> +
> +	if (!cg_run(child, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_test_proc_killed(child))
> +		goto cleanup;
> +	if (cg_test_proc_killed(parent))
> +		goto cleanup;
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (child)
> +		cg_destroy(child);
> +	if (parent)
> +		cg_destroy(parent);
> +	free(child);
> +	free(parent);
> +
> +	return ret;
> +}
> +
> +/*
> + * This test disables swapping and tries to allocate anonymous memory
> + * up to OOM with memory.group.oom set. Then it checks that all
> + * processes were killed except those set with OOM_SCORE_ADJ_MIN
> + */
> +static int test_memcg_oom_group_score_events(const char *root)
> +{
> +	int ret = KSFT_FAIL;
> +	char *memcg;
> +	int safe_pid;
> +
> +	memcg = cg_name(root, "memcg_test_0");
> +
> +	if (!memcg)
> +		goto cleanup;
> +
> +	if (cg_create(memcg))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.max", "50M"))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.swap.max", "0"))
> +		goto cleanup;
> +
> +	if (cg_write(memcg, "memory.oom.group", "1"))
> +		goto cleanup;
> +
> +	safe_pid = cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
> +	if (set_oom_adj_score(safe_pid, OOM_SCORE_ADJ_MIN))
> +		goto cleanup;
> +
> +	cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
> +	if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
> +		goto cleanup;
> +
> +	if (cg_read_key_long(memcg, "memory.events", "oom_kill ") != 3)
> +		goto cleanup;
> +
> +	if (kill(safe_pid, SIGKILL))
> +		return -1;

Missing cleanup? Should the return be just ret which is KSFT_FAIL
> +
> +	ret = KSFT_PASS;
> +
> +cleanup:
> +	if (memcg)
> +		cg_destroy(memcg);
> +	free(memcg);
> +
> +	return ret;
> +}
> +
> +
>  #define T(x) { x, #x }
>  struct memcg_test {
>  	int (*fn)(const char *root);
> @@ -978,6 +1180,9 @@ struct memcg_test {
>  	T(test_memcg_oom_events),
>  	T(test_memcg_swap_max),
>  	T(test_memcg_sock),
> +	T(test_memcg_oom_group_leaf_events),
> +	T(test_memcg_oom_group_parent_events),
> +	T(test_memcg_oom_group_score_events),
>  };
>  #undef T
>  
> 

thanks,
-- Shuah

  reply	other threads:[~2018-09-05 15:22 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-05  1:08 kselftests for memory.oom.group jgkamat
2018-09-05  1:08 ` jgkamat
2018-09-05  1:08 ` jgkamat
2018-09-05  1:08 ` [PATCH 1/2] Fix cg_read_strcmp() jgkamat
2018-09-05  1:08   ` jgkamat
2018-09-05  1:08   ` jgkamat
2018-09-05 14:43   ` Shuah Khan
2018-09-05 14:43     ` Shuah Khan
2018-09-05 14:43     ` shuah
2018-09-05  1:08 ` [PATCH 2/2] Add tests for memory.oom.group jgkamat
2018-09-05  1:08   ` jgkamat
2018-09-05  1:08   ` jgkamat
2018-09-05 15:21   ` Shuah Khan [this message]
2018-09-05 15:21     ` Shuah Khan
2018-09-05 15:21     ` shuah
2018-09-07 16:49 ` kselftests " jgkamat
2018-09-07 16:49   ` jgkamat
2018-09-07 16:49   ` jgkamat
2018-09-07 16:49   ` [PATCH 1/2] Fix cg_read_strcmp() jgkamat
2018-09-07 16:49     ` jgkamat
2018-09-07 16:49     ` jgkamat
2018-09-07 16:56     ` Roman Gushchin
2018-09-07 16:56       ` Roman Gushchin
2018-09-07 16:56       ` guro
2018-09-07 17:06     ` Shuah Khan
2018-09-07 17:06       ` Shuah Khan
2018-09-07 17:06       ` shuah
2018-09-07 18:28       ` Jay Kamat
2018-09-07 18:28         ` Jay Kamat
2018-09-07 18:28         ` jgkamat
2018-09-07 18:53         ` Shuah Khan
2018-09-07 18:53           ` Shuah Khan
2018-09-07 18:53           ` shuah
2018-09-07 16:49   ` [PATCH 2/2] Add tests for memory.oom.group jgkamat
2018-09-07 16:49     ` jgkamat
2018-09-07 16:49     ` jgkamat
2018-09-07 16:57     ` Roman Gushchin
2018-09-07 16:57       ` Roman Gushchin
2018-09-07 16:57       ` guro
2018-09-07 21:34   ` kselftests " jgkamat
2018-09-07 21:34     ` jgkamat
2018-09-07 21:34     ` jgkamat
2018-09-07 21:34     ` [PATCH v3 1/2] Fix cg_read_strcmp() jgkamat
2018-09-07 21:34       ` jgkamat
2018-09-07 21:34       ` jgkamat
2018-09-07 21:34     ` [PATCH v3 2/2] Add tests for memory.oom.group jgkamat
2018-09-07 21:34       ` jgkamat
2018-09-07 21:34       ` jgkamat
2018-09-07 22:53     ` kselftests " Shuah Khan
2018-09-07 22:53       ` Shuah Khan
2018-09-07 22:53       ` shuah

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2f5ffeaf-3161-37e2-73a3-ae449aecca40@kernel.org \
    --to=shuah@kernel.org \
    --cc=guro@fb.com \
    --cc=jaygkamat@gmail.com \
    --cc=jgkamat@fb.com \
    --cc=kernel-team@fb.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.