Skip to content

Commit 1ad945a

Browse files
Richard Palethorpewangli5665
authored andcommitted
madvise06: Increase reliability and diagnostic info
When memcg.limit_in_bytes is set to PASS_THRESHOLD it's unlikely swapcached will increase by more than PASS_THRESHOLD unless processes in other memcgs are also increasing it. Additionally MADV_WILLNEED must remove pages from memory as it adds more so that the first page may not be in memory by the time the last page is faulted if the amount exceeds the memory limit (which it does because CHUNK_SZ > PASS_THRESSHOLD). Worse if pages are faulted in a non-linear way, or the process must access some other pages, then there is no guarantee which parts of the range will be resident in memory. This results in spurious test failures. To solve this we can set PASS_THRESHOLD to 1/4 of CHUNK_SZ and memcg.limit_in_bytes to 1/2 of CHUNK_SZ (MEM_LIMIT), then mark MEM_LIMIT bytes as needed. That way the amount in the SwapCache will easily be more than the threshold. Secondly we can run madvise again on PASS_THRESHOLD bytes and check that dirtying all of these does not result in too many page faults. We also run the second test on every occasion to ensure the test code itself is still valid. If the original bug is present then both tests fail. Finally this prints more diagnostic information to help with debugging the test. While debugging the test a kernel bug was found in 5.9 which effects CGroupV1 when use_hierarchy=0. This is unlikely to effect many users, but a fix is pending and will be referenced in the test when available. It is recommended that you set use_hierarchy=1. Signed-off-by: Richard Palethorpe <[email protected]> Reviewed-by: Li Wang <[email protected]>
1 parent f4a9a98 commit 1ad945a

File tree

1 file changed

+84
-23
lines changed

1 file changed

+84
-23
lines changed

testcases/kernel/syscalls/madvise/madvise06.c

Lines changed: 84 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@
1919
* Date: Thu May 22 11:54:17 2014 -0700
2020
*
2121
* mm: madvise: fix MADV_WILLNEED on shmem swapouts
22+
*
23+
* Two checks are performed, the first looks at how SwapCache
24+
* changes during madvise. When the pages are dirtied, about half
25+
* will be accounted for under Cached and the other half will be
26+
* moved into Swap. When madvise is run it will cause the pages
27+
* under Cached to also be moved to Swap while rotating the pages
28+
* already in Swap into SwapCached. So we expect that SwapCached has
29+
* roughly MEM_LIMIT bytes added to it, but for reliability the
30+
* PASS_THRESHOLD is much lower than that.
31+
*
32+
* Secondly we run madvise again, but only on the first
33+
* PASS_THRESHOLD bytes to ensure these are entirely in RAM. Then we
34+
* dirty these pages and check there were (almost) no page
35+
* faults. Two faults are allowed incase some tasklet or something
36+
* else unexpected, but irrelevant procedure, registers a fault to
37+
* our process.
38+
*
2239
*/
2340

2441
#include <errno.h>
@@ -28,21 +45,50 @@
2845
#include "tst_test.h"
2946

3047
#define CHUNK_SZ (400*1024*1024L)
31-
#define CHUNK_PAGES (CHUNK_SZ / pg_sz)
48+
#define MEM_LIMIT (CHUNK_SZ / 2)
49+
#define MEMSW_LIMIT (2 * CHUNK_SZ)
3250
#define PASS_THRESHOLD (CHUNK_SZ / 4)
51+
#define PASS_THRESHOLD_KB (PASS_THRESHOLD / 1024)
3352

3453
#define MNT_NAME "memory"
3554
#define GROUP_NAME "madvise06"
3655

3756
static const char drop_caches_fname[] = "/proc/sys/vm/drop_caches";
3857
static int pg_sz;
3958

59+
static long init_swap, init_swap_cached, init_cached;
60+
4061
static void check_path(const char *path)
4162
{
4263
if (access(path, R_OK | W_OK))
4364
tst_brk(TCONF, "file needed: %s\n", path);
4465
}
4566

67+
#define READ_CGMEM(item) \
68+
({long tst_rval; \
69+
SAFE_FILE_LINES_SCANF(MNT_NAME"/"GROUP_NAME"/memory."item, \
70+
"%ld", \
71+
&tst_rval); \
72+
tst_rval;})
73+
74+
static void meminfo_diag(const char *point)
75+
{
76+
FILE_PRINTF("/proc/sys/vm/stat_refresh", "1");
77+
tst_res(TINFO, "%s", point);
78+
tst_res(TINFO, "\tSwap: %ld Kb",
79+
SAFE_READ_MEMINFO("SwapTotal:") - SAFE_READ_MEMINFO("SwapFree:") - init_swap);
80+
tst_res(TINFO, "\tSwapCached: %ld Kb",
81+
SAFE_READ_MEMINFO("SwapCached:") - init_swap_cached);
82+
tst_res(TINFO, "\tCached: %ld Kb",
83+
SAFE_READ_MEMINFO("Cached:") - init_cached);
84+
tst_res(TINFO, "\tcgmem.usage_in_bytes: %ld Kb",
85+
READ_CGMEM("usage_in_bytes") / 1024);
86+
tst_res(TINFO, "\tcgmem.memsw.usage_in_bytes: %ld Kb",
87+
READ_CGMEM("memsw.usage_in_bytes") / 1024);
88+
tst_res(TINFO, "\tcgmem.kmem.usage_in_bytes: %ld Kb",
89+
READ_CGMEM("kmem.usage_in_bytes") / 1024);
90+
}
91+
4692
static void setup(void)
4793
{
4894
struct sysinfo sys_buf_start;
@@ -77,9 +123,19 @@ static void setup(void)
77123

78124
SAFE_FILE_PRINTF("/proc/self/oom_score_adj", "%d", -1000);
79125
SAFE_FILE_PRINTF(MNT_NAME"/"GROUP_NAME"/memory.limit_in_bytes", "%ld\n",
80-
PASS_THRESHOLD);
126+
MEM_LIMIT);
127+
SAFE_FILE_PRINTF(MNT_NAME"/"GROUP_NAME"/memory.memsw.limit_in_bytes", "%ld\n",
128+
MEMSW_LIMIT);
81129
SAFE_FILE_PRINTF(MNT_NAME"/"GROUP_NAME"/memory.swappiness", "60");
82130
SAFE_FILE_PRINTF(MNT_NAME"/"GROUP_NAME"/tasks", "%d\n", getpid());
131+
132+
meminfo_diag("Initial meminfo, later values are relative to this (except memcg)");
133+
init_swap = SAFE_READ_MEMINFO("SwapTotal:") - SAFE_READ_MEMINFO("SwapFree:");
134+
init_swap_cached = SAFE_READ_MEMINFO("SwapCached:");
135+
init_cached = SAFE_READ_MEMINFO("Cached:");
136+
137+
tst_res(TINFO, "mapping %ld Kb (%ld pages), limit %ld Kb, pass threshold %ld Kb",
138+
CHUNK_SZ / 1024, CHUNK_SZ / pg_sz, MEM_LIMIT / 1024, PASS_THRESHOLD_KB);
83139
}
84140

85141
static void cleanup(void)
@@ -112,55 +168,60 @@ static int get_page_fault_num(void)
112168

113169
static void test_advice_willneed(void)
114170
{
115-
int loops = 50;
171+
int loops = 50, res;
116172
char *target;
117173
long swapcached_start, swapcached;
118174
int page_fault_num_1, page_fault_num_2;
119175

176+
meminfo_diag("Before mmap");
177+
tst_res(TINFO, "PageFault(before mmap): %d", get_page_fault_num());
120178
target = SAFE_MMAP(NULL, CHUNK_SZ, PROT_READ | PROT_WRITE,
121179
MAP_SHARED | MAP_ANONYMOUS,
122180
-1, 0);
181+
meminfo_diag("Before dirty");
182+
tst_res(TINFO, "PageFault(before dirty): %d", get_page_fault_num());
123183
dirty_pages(target, CHUNK_SZ);
184+
tst_res(TINFO, "PageFault(after dirty): %d", get_page_fault_num());
124185

186+
meminfo_diag("Before madvise");
125187
SAFE_FILE_LINES_SCANF("/proc/meminfo", "SwapCached: %ld",
126188
&swapcached_start);
127-
tst_res(TINFO, "SwapCached (before madvise): %ld", swapcached_start);
128189

129-
TEST(madvise(target, CHUNK_SZ, MADV_WILLNEED));
190+
TEST(madvise(target, MEM_LIMIT, MADV_WILLNEED));
130191
if (TST_RET == -1)
131192
tst_brk(TBROK | TERRNO, "madvise failed");
132193

133194
do {
134195
loops--;
135196
usleep(100000);
197+
FILE_PRINTF("/proc/sys/vm/stat_refresh", "1");
136198
SAFE_FILE_LINES_SCANF("/proc/meminfo", "SwapCached: %ld",
137199
&swapcached);
138-
} while (swapcached < swapcached_start + PASS_THRESHOLD / 1024
139-
&& loops > 0);
140-
141-
tst_res(TINFO, "SwapCached (after madvise): %ld", swapcached);
142-
if (swapcached > swapcached_start + PASS_THRESHOLD / 1024) {
143-
tst_res(TPASS, "Regression test pass");
144-
SAFE_MUNMAP(target, CHUNK_SZ);
145-
return;
146-
}
200+
} while (swapcached < swapcached_start + PASS_THRESHOLD_KB && loops > 0);
201+
202+
meminfo_diag("After madvise");
203+
res = swapcached > swapcached_start + PASS_THRESHOLD_KB;
204+
tst_res(res ? TPASS : TFAIL,
205+
"%s than %ld Kb were moved to the swap cache",
206+
res ? "more" : "less", PASS_THRESHOLD_KB);
207+
208+
209+
TEST(madvise(target, PASS_THRESHOLD, MADV_WILLNEED));
210+
if (TST_RET == -1)
211+
tst_brk(TBROK | TERRNO, "madvise failed");
147212

148-
/*
149-
* We may have hit a bug or we just have slow I/O,
150-
* try accessing first page.
151-
*/
152213
page_fault_num_1 = get_page_fault_num();
153214
tst_res(TINFO, "PageFault(madvice / no mem access): %d",
154215
page_fault_num_1);
155-
target[0] = 'a';
216+
dirty_pages(target, PASS_THRESHOLD);
156217
page_fault_num_2 = get_page_fault_num();
157218
tst_res(TINFO, "PageFault(madvice / mem access): %d",
158219
page_fault_num_2);
220+
meminfo_diag("After page access");
159221

160-
if (page_fault_num_1 != page_fault_num_2)
161-
tst_res(TFAIL, "Bug has been reproduced");
162-
else
163-
tst_res(TPASS, "Regression test pass");
222+
res = page_fault_num_2 - page_fault_num_1;
223+
tst_res(res < 3 ? TPASS : TFAIL,
224+
"%d pages were faulted out of 2 max", res);
164225

165226
SAFE_MUNMAP(target, CHUNK_SZ);
166227
}

0 commit comments

Comments
 (0)