Skip to content

Commit

Permalink
selftests: cgroup: add a selftest for memory.reclaim
Browse files Browse the repository at this point in the history
Add a new test for memory.reclaim that verifies that the interface
correctly reclaims memory as intended, from both anon and file pages.

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Yosry Ahmed <[email protected]>
Acked-by: Roman Gushchin <[email protected]>
Acked-by: David Rientjes <[email protected]>
Cc: Chen Wandun <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Greg Thelen <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: "Michal Koutn" <[email protected]>
Cc: Shakeel Butt <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Tejun Heo <[email protected]>
Cc: Tim Chen <[email protected]>
Cc: Vaibhav Jain <[email protected]>
Cc: Wei Xu <[email protected]>
Cc: Yu Zhao <[email protected]>
Cc: Zefan Li <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
  • Loading branch information
yosrym93 authored and akpm00 committed Apr 29, 2022
1 parent a3622a5 commit eae3cb2
Showing 1 changed file with 106 additions and 0 deletions.
106 changes: 106 additions & 0 deletions tools/testing/selftests/cgroup/test_memcontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,111 @@ static int test_memcg_max(const char *root)
return ret;
}

/*
* This test checks that memory.reclaim reclaims the given
* amount of memory (from both anon and file, if possible).
*/
static int test_memcg_reclaim(const char *root)
{
int ret = KSFT_FAIL, fd, retries;
char *memcg;
long current, expected_usage, to_reclaim;
char buf[64];

memcg = cg_name(root, "memcg_test");
if (!memcg)
goto cleanup;

if (cg_create(memcg))
goto cleanup;

current = cg_read_long(memcg, "memory.current");
if (current != 0)
goto cleanup;

fd = get_temp_fd();
if (fd < 0)
goto cleanup;

cg_run_nowait(memcg, alloc_pagecache_50M_noexit, (void *)(long)fd);

/*
* If swap is enabled, try to reclaim from both anon and file, else try
* to reclaim from file only.
*/
if (is_swap_enabled()) {
cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(50));
expected_usage = MB(100);
} else
expected_usage = MB(50);

/*
* Wait until current usage reaches the expected usage (or we run out of
* retries).
*/
retries = 5;
while (!values_close(cg_read_long(memcg, "memory.current"),
expected_usage, 10)) {
if (retries--) {
sleep(1);
continue;
} else {
fprintf(stderr,
"failed to allocate %ld for memcg reclaim test\n",
expected_usage);
goto cleanup;
}
}

/*
* Reclaim until current reaches 30M, this makes sure we hit both anon
* and file if swap is enabled.
*/
retries = 5;
while (true) {
int err;

current = cg_read_long(memcg, "memory.current");
to_reclaim = current - MB(30);

/*
* We only keep looping if we get EAGAIN, which means we could
* not reclaim the full amount.
*/
if (to_reclaim <= 0)
goto cleanup;


snprintf(buf, sizeof(buf), "%ld", to_reclaim);
err = cg_write(memcg, "memory.reclaim", buf);
if (!err) {
/*
* If writing succeeds, then the written amount should have been
* fully reclaimed (and maybe more).
*/
current = cg_read_long(memcg, "memory.current");
if (!values_close(current, MB(30), 3) && current > MB(30))
goto cleanup;
break;
}

/* The kernel could not reclaim the full amount, try again. */
if (err == -EAGAIN && retries--)
continue;

/* We got an unexpected error or ran out of retries. */
goto cleanup;
}

ret = KSFT_PASS;
cleanup:
cg_destroy(memcg);
free(memcg);
close(fd);

return ret;
}

static int alloc_anon_50M_check_swap(const char *cgroup, void *arg)
{
long mem_max = (long)arg;
Expand Down Expand Up @@ -1264,6 +1369,7 @@ struct memcg_test {
T(test_memcg_high),
T(test_memcg_high_sync),
T(test_memcg_max),
T(test_memcg_reclaim),
T(test_memcg_oom_events),
T(test_memcg_swap_max),
T(test_memcg_sock),
Expand Down

0 comments on commit eae3cb2

Please sign in to comment.