1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2013-2017 Red Hat, Inc. 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci/*\ 6f08c3bdfSopenharmony_ci * [Description] 7f08c3bdfSopenharmony_ci * 8f08c3bdfSopenharmony_ci * The case is designed to test sysfs boolean knob 9f08c3bdfSopenharmony_ci * /sys/kernel/mm/ksm/merge_across_nodes. 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * When merge_across_nodes is set to zero only pages from the same 12f08c3bdfSopenharmony_ci * node are merged, otherwise pages from all nodes can be merged 13f08c3bdfSopenharmony_ci * together. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * Introduced in commit: 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * commit 90bd6fd31c8097ee4ddcb74b7e08363134863de5 18f08c3bdfSopenharmony_ci * Author: Petr Holasek <pholasek@redhat.com> 19f08c3bdfSopenharmony_ci * Date: Fri Feb 22 16:35:00 2013 -0800 20f08c3bdfSopenharmony_ci * 21f08c3bdfSopenharmony_ci * ksm: allow trees per NUMA node 22f08c3bdfSopenharmony_ci */ 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#include "config.h" 25f08c3bdfSopenharmony_ci#include <sys/types.h> 26f08c3bdfSopenharmony_ci#include <sys/stat.h> 27f08c3bdfSopenharmony_ci#include <sys/mman.h> 28f08c3bdfSopenharmony_ci#include <limits.h> 29f08c3bdfSopenharmony_ci#include <errno.h> 30f08c3bdfSopenharmony_ci#include <fcntl.h> 31f08c3bdfSopenharmony_ci#include <signal.h> 32f08c3bdfSopenharmony_ci#include <stdio.h> 33f08c3bdfSopenharmony_ci#include <unistd.h> 34f08c3bdfSopenharmony_ci#include <limits.h> 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_ci#include "mem.h" 37f08c3bdfSopenharmony_ci#include "tst_numa.h" 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_ci#ifdef HAVE_NUMA_V2 40f08c3bdfSopenharmony_ci# include <numa.h> 41f08c3bdfSopenharmony_ci# include <numaif.h> 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_cistatic unsigned long nr_pages = 100; 44f08c3bdfSopenharmony_cistatic char *n_opt; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic size_t page_size; 47f08c3bdfSopenharmony_cistatic struct tst_nodemap *nodes; 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_cistatic void test_ksm(void) 50f08c3bdfSopenharmony_ci{ 51f08c3bdfSopenharmony_ci char **memory; 52f08c3bdfSopenharmony_ci unsigned int i; 53f08c3bdfSopenharmony_ci int ret; 54f08c3bdfSopenharmony_ci unsigned long length; 55f08c3bdfSopenharmony_ci struct bitmask *bm = numa_allocate_nodemask(); 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ci length = nr_pages * page_size; 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci memory = SAFE_MALLOC(nodes->cnt * sizeof(char *)); 60f08c3bdfSopenharmony_ci for (i = 0; i < nodes->cnt; i++) { 61f08c3bdfSopenharmony_ci memory[i] = SAFE_MMAP(NULL, length, PROT_READ|PROT_WRITE, 62f08c3bdfSopenharmony_ci MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 63f08c3bdfSopenharmony_ci#ifdef HAVE_DECL_MADV_MERGEABLE 64f08c3bdfSopenharmony_ci if (madvise(memory[i], length, MADV_MERGEABLE) == -1) 65f08c3bdfSopenharmony_ci tst_brk(TBROK|TERRNO, "madvise"); 66f08c3bdfSopenharmony_ci#endif 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci#ifdef HAVE_NUMA_V2 69f08c3bdfSopenharmony_ci numa_bitmask_setbit(bm, nodes->map[i]); 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci ret = mbind(memory[i], length, MPOL_BIND, bm->maskp, bm->size+1, 0); 72f08c3bdfSopenharmony_ci if (ret == -1) 73f08c3bdfSopenharmony_ci tst_brk(TBROK|TERRNO, "mbind"); 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_ci numa_bitmask_clearbit(bm, nodes->map[i]); 76f08c3bdfSopenharmony_ci#endif 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_ci memset(memory[i], 10, length); 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci if (mlock(memory[i], length)) 81f08c3bdfSopenharmony_ci tst_res(TWARN | TERRNO, "mlock() failed"); 82f08c3bdfSopenharmony_ci } 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci numa_free_nodemask(bm); 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0"); 87f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", 88f08c3bdfSopenharmony_ci nr_pages * nodes->cnt); 89f08c3bdfSopenharmony_ci /* 90f08c3bdfSopenharmony_ci * merge_across_nodes and max_page_sharing setting can be changed 91f08c3bdfSopenharmony_ci * only when there are no ksm shared pages in system, so set run 2 92f08c3bdfSopenharmony_ci * to unmerge pages first, then to 1 after changing merge_across_nodes, 93f08c3bdfSopenharmony_ci * to remerge according to the new setting. 94f08c3bdfSopenharmony_ci */ 95f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "run", "2"); 96f08c3bdfSopenharmony_ci if (access(PATH_KSM "max_page_sharing", F_OK) == 0) 97f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", 98f08c3bdfSopenharmony_ci "%ld", nr_pages * nodes->cnt); 99f08c3bdfSopenharmony_ci tst_res(TINFO, "Start to test KSM with merge_across_nodes=1"); 100f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); 101f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "run", "1"); 102f08c3bdfSopenharmony_ci ksm_group_check(1, 1, nr_pages * nodes->cnt - 1, 0, 0, 0, 103f08c3bdfSopenharmony_ci nr_pages * nodes->cnt); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "run", "2"); 106f08c3bdfSopenharmony_ci tst_res(TINFO, "Start to test KSM with merge_across_nodes=0"); 107f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "0"); 108f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "run", "1"); 109f08c3bdfSopenharmony_ci ksm_group_check(1, nodes->cnt, nr_pages * nodes->cnt - nodes->cnt, 110f08c3bdfSopenharmony_ci 0, 0, 0, nr_pages * nodes->cnt); 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(PATH_KSM "run", "2"); 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci for (i = 0; i < nodes->cnt; i++) 115f08c3bdfSopenharmony_ci SAFE_MUNMAP(memory[i], length); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci free(memory); 118f08c3bdfSopenharmony_ci} 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_cistatic void setup(void) 121f08c3bdfSopenharmony_ci{ 122f08c3bdfSopenharmony_ci if (n_opt) 123f08c3bdfSopenharmony_ci nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX); 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci page_size = getpagesize(); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci nodes = tst_get_nodemap(TST_NUMA_MEM, nr_pages * page_size / 1024); 128f08c3bdfSopenharmony_ci if (nodes->cnt <= 1) 129f08c3bdfSopenharmony_ci tst_brk(TCONF, "Test requires at least two NUMA memory nodes"); 130f08c3bdfSopenharmony_ci} 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_cistatic struct tst_test test = { 133f08c3bdfSopenharmony_ci .needs_root = 1, 134f08c3bdfSopenharmony_ci .options = (struct tst_option[]) { 135f08c3bdfSopenharmony_ci {"n:", &n_opt, "Allocate x pages memory per node"}, 136f08c3bdfSopenharmony_ci {} 137f08c3bdfSopenharmony_ci }, 138f08c3bdfSopenharmony_ci .setup = setup, 139f08c3bdfSopenharmony_ci .save_restore = (const struct tst_path_val[]) { 140f08c3bdfSopenharmony_ci {"/sys/kernel/mm/ksm/max_page_sharing", NULL, 141f08c3bdfSopenharmony_ci TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, 142f08c3bdfSopenharmony_ci {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, 143f08c3bdfSopenharmony_ci {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, 144f08c3bdfSopenharmony_ci {"/sys/kernel/mm/ksm/merge_across_nodes", NULL, TST_SR_TCONF}, 145f08c3bdfSopenharmony_ci {} 146f08c3bdfSopenharmony_ci }, 147f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *const[]){ 148f08c3bdfSopenharmony_ci "CONFIG_KSM=y", 149f08c3bdfSopenharmony_ci "CONFIG_NUMA=y", 150f08c3bdfSopenharmony_ci NULL 151f08c3bdfSopenharmony_ci }, 152f08c3bdfSopenharmony_ci .test_all = test_ksm, 153f08c3bdfSopenharmony_ci}; 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci#else 156f08c3bdfSopenharmony_ci TST_TEST_TCONF(NUMA_ERROR_MSG); 157f08c3bdfSopenharmony_ci#endif 158