Skip to content

Commit 3961998

Browse files
zhans00torvalds
authored andcommitted
selftests: vm: add KSM zero page merging test
Add check_ksm_zero_page_merge() function to test that empty pages are being handled properly. For this, several zero pages are allocated and merged using madvise. If use_zero_pages is enabled, the pages must be shared with the special kernel zero pages; otherwise, they are merged as usual duplicate pages. The test is run as follows: ./ksm_tests -Z Link: https://lkml.kernel.org/r/6d0caab00d4bdccf5e3791cb95cf6dfd5eb85e45.1626252248.git.zhansayabagdaulet@gmail.com Signed-off-by: Zhansaya Bagdauletkyzy <[email protected]> Reviewed-by: Pavel Tatashin <[email protected]> Reviewed-by: Tyler Hicks <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Shuah Khan <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent a40c80e commit 3961998

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed

tools/testing/selftests/vm/ksm_tests.c

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define KSM_SCAN_LIMIT_SEC_DEFAULT 120
1313
#define KSM_PAGE_COUNT_DEFAULT 10l
1414
#define KSM_PROT_STR_DEFAULT "rw"
15+
#define KSM_USE_ZERO_PAGES_DEFAULT false
1516

1617
struct ksm_sysfs {
1718
unsigned long max_page_sharing;
@@ -25,7 +26,8 @@ struct ksm_sysfs {
2526

2627
enum ksm_test_name {
2728
CHECK_KSM_MERGE,
28-
CHECK_KSM_UNMERGE
29+
CHECK_KSM_UNMERGE,
30+
CHECK_KSM_ZERO_PAGE_MERGE
2931
};
3032

3133
static int ksm_write_sysfs(const char *file_path, unsigned long val)
@@ -80,10 +82,12 @@ static int str_to_prot(char *prot_str)
8082

8183
static void print_help(void)
8284
{
83-
printf("usage: ksm_tests [-h] <test type> [-a prot] [-p page_count] [-l timeout]\n");
85+
printf("usage: ksm_tests [-h] <test type> [-a prot] [-p page_count] [-l timeout]\n"
86+
"[-z use_zero_pages]\n");
8487

8588
printf("Supported <test type>:\n"
8689
" -M (page merging)\n"
90+
" -Z (zero pages merging)\n"
8791
" -U (page unmerging)\n\n");
8892

8993
printf(" -a: specify the access protections of pages.\n"
@@ -93,6 +97,8 @@ static void print_help(void)
9397
" Default: %ld\n", KSM_PAGE_COUNT_DEFAULT);
9498
printf(" -l: limit the maximum running time (in seconds) for a test.\n"
9599
" Default: %d seconds\n", KSM_SCAN_LIMIT_SEC_DEFAULT);
100+
printf(" -z: change use_zero_pages tunable\n"
101+
" Default: %d\n", KSM_USE_ZERO_PAGES_DEFAULT);
96102

97103
exit(0);
98104
}
@@ -289,6 +295,50 @@ static int check_ksm_unmerge(int mapping, int prot, int timeout, size_t page_siz
289295
return KSFT_FAIL;
290296
}
291297

298+
static int check_ksm_zero_page_merge(int mapping, int prot, long page_count, int timeout,
299+
bool use_zero_pages, size_t page_size)
300+
{
301+
void *map_ptr;
302+
struct timespec start_time;
303+
304+
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
305+
perror("clock_gettime");
306+
return KSFT_FAIL;
307+
}
308+
309+
if (ksm_write_sysfs(KSM_FP("use_zero_pages"), use_zero_pages))
310+
return KSFT_FAIL;
311+
312+
/* fill pages with zero and try to merge them */
313+
map_ptr = allocate_memory(NULL, prot, mapping, 0, page_size * page_count);
314+
if (!map_ptr)
315+
return KSFT_FAIL;
316+
317+
if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout))
318+
goto err_out;
319+
320+
/*
321+
* verify that the right number of pages are merged:
322+
* 1) if use_zero_pages is set to 1, empty pages are merged
323+
* with the kernel zero page instead of with each other;
324+
* 2) if use_zero_pages is set to 0, empty pages are not treated specially
325+
* and merged as usual.
326+
*/
327+
if (use_zero_pages && !assert_ksm_pages_count(0))
328+
goto err_out;
329+
else if (!use_zero_pages && !assert_ksm_pages_count(page_count))
330+
goto err_out;
331+
332+
printf("OK\n");
333+
munmap(map_ptr, page_size * page_count);
334+
return KSFT_PASS;
335+
336+
err_out:
337+
printf("Not OK\n");
338+
munmap(map_ptr, page_size * page_count);
339+
return KSFT_FAIL;
340+
}
341+
292342
int main(int argc, char *argv[])
293343
{
294344
int ret, opt;
@@ -298,8 +348,9 @@ int main(int argc, char *argv[])
298348
size_t page_size = sysconf(_SC_PAGESIZE);
299349
struct ksm_sysfs ksm_sysfs_old;
300350
int test_name = CHECK_KSM_MERGE;
351+
bool use_zero_pages = KSM_USE_ZERO_PAGES_DEFAULT;
301352

302-
while ((opt = getopt(argc, argv, "ha:p:l:MU")) != -1) {
353+
while ((opt = getopt(argc, argv, "ha:p:l:z:MUZ")) != -1) {
303354
switch (opt) {
304355
case 'a':
305356
prot = str_to_prot(optarg);
@@ -321,11 +372,20 @@ int main(int argc, char *argv[])
321372
case 'h':
322373
print_help();
323374
break;
375+
case 'z':
376+
if (strcmp(optarg, "0") == 0)
377+
use_zero_pages = 0;
378+
else
379+
use_zero_pages = 1;
380+
break;
324381
case 'M':
325382
break;
326383
case 'U':
327384
test_name = CHECK_KSM_UNMERGE;
328385
break;
386+
case 'Z':
387+
test_name = CHECK_KSM_ZERO_PAGE_MERGE;
388+
break;
329389
default:
330390
return KSFT_FAIL;
331391
}
@@ -359,6 +419,10 @@ int main(int argc, char *argv[])
359419
ret = check_ksm_unmerge(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec,
360420
page_size);
361421
break;
422+
case CHECK_KSM_ZERO_PAGE_MERGE:
423+
ret = check_ksm_zero_page_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count,
424+
ksm_scan_limit_sec, use_zero_pages, page_size);
425+
break;
362426
}
363427

364428
if (ksm_restore(&ksm_sysfs_old)) {

tools/testing/selftests/vm/run_vmtests.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,38 @@ else
409409
exitcode=1
410410
fi
411411

412+
echo "----------------------------------------------------------"
413+
echo "running KSM test with 10 zero pages and use_zero_pages = 0"
414+
echo "----------------------------------------------------------"
415+
./ksm_tests -Z -p 10 -z 0
416+
ret_val=$?
417+
418+
if [ $ret_val -eq 0 ]; then
419+
echo "[PASS]"
420+
elif [ $ret_val -eq $ksft_skip ]; then
421+
echo "[SKIP]"
422+
exitcode=$ksft_skip
423+
else
424+
echo "[FAIL]"
425+
exitcode=1
426+
fi
427+
428+
echo "----------------------------------------------------------"
429+
echo "running KSM test with 10 zero pages and use_zero_pages = 1"
430+
echo "----------------------------------------------------------"
431+
./ksm_tests -Z -p 10 -z 1
432+
ret_val=$?
433+
434+
if [ $ret_val -eq 0 ]; then
435+
echo "[PASS]"
436+
elif [ $ret_val -eq $ksft_skip ]; then
437+
echo "[SKIP]"
438+
exitcode=$ksft_skip
439+
else
440+
echo "[FAIL]"
441+
exitcode=1
442+
fi
443+
412444
exit $exitcode
413445

414446
exit $exitcode

0 commit comments

Comments
 (0)