Home | History | Annotate | Download | only in ksm
      1 /*
      2  * Copyright (C) 2013-2017  Red Hat, Inc.
      3  *
      4  * This program is free software;  you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  * the GNU General Public License for more details.
     13  */
     14 
     15 /*
     16  * The case is designed to test new sysfs boolean knob
     17  * /sys/kernel/mm/ksm/merge_across_nodes, which was introduced by
     18  * commit 90bd6fd31c8097ee (ksm: allow trees per NUMA node).
     19  * when merge_across_nodes is set to zero only pages from the same
     20  * node are merged, otherwise pages from all nodes can be merged
     21  * together.
     22  */
     23 
     24 #include "config.h"
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <sys/mman.h>
     28 #include <limits.h>
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #if HAVE_NUMA_H
     32 #include <numa.h>
     33 #endif
     34 #if HAVE_NUMAIF_H
     35 #include <numaif.h>
     36 #endif
     37 #include <signal.h>
     38 #include <stdio.h>
     39 #include <unistd.h>
     40 #include <limits.h>
     41 
     42 #include "mem.h"
     43 #include "numa_helper.h"
     44 
     45 #if defined(HAVE_NUMA_V2) && defined(HAVE_LINUX_MEMPOLICY_H)
     46 
     47 static int run = -1;
     48 static int sleep_millisecs = -1;
     49 static int merge_across_nodes = -1;
     50 static unsigned long nr_pages;
     51 
     52 static char *n_opt;
     53 static struct tst_option ksm_options[] = {
     54 	{"n:", &n_opt,  "-n x    Allocate x pages memory per node"},
     55 	{NULL, NULL, NULL}
     56 };
     57 
     58 static void test_ksm(void)
     59 {
     60 	if (n_opt)
     61 		nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX);
     62 	else
     63 		nr_pages = 100;
     64 
     65 	test_ksm_merge_across_nodes(nr_pages);
     66 }
     67 
     68 static void setup(void)
     69 {
     70 	if (access(PATH_KSM "merge_across_nodes", F_OK) == -1)
     71 		tst_brk(TCONF, "no merge_across_nodes sysfs knob");
     72 
     73 	save_max_page_sharing();
     74 
     75 	if (!is_numa(NULL, NH_MEMS, 2))
     76 		tst_brk(TCONF, "The case needs a NUMA system.");
     77 
     78 	/* save the current value */
     79 	SAFE_FILE_SCANF(PATH_KSM "run", "%d", &run);
     80 	SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes",
     81 			"%d", &merge_across_nodes);
     82 	SAFE_FILE_SCANF(PATH_KSM "sleep_millisecs",
     83 			"%d", &sleep_millisecs);
     84 }
     85 
     86 static void cleanup(void)
     87 {
     88 	if (merge_across_nodes != -1) {
     89 		FILE_PRINTF(PATH_KSM "merge_across_nodes",
     90 			    "%d", merge_across_nodes);
     91 	}
     92 
     93 	if (sleep_millisecs != -1)
     94 		FILE_PRINTF(PATH_KSM "sleep_millisecs", "%d", sleep_millisecs);
     95 
     96 	if (run != -1)
     97 		FILE_PRINTF(PATH_KSM "run", "%d", run);
     98 
     99 	restore_max_page_sharing();
    100 }
    101 
    102 static struct tst_test test = {
    103 	.needs_root = 1,
    104 	.options = ksm_options,
    105 	.setup = setup,
    106 	.cleanup = cleanup,
    107 	.test_all = test_ksm,
    108 };
    109 
    110 #else
    111 	TST_TEST_TCONF("test requires libnuma >= 2 and it's development packages");
    112 #endif
    113