| /* |
| * Copyright (C) 2013-2017 Red Hat, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| */ |
| |
| /* |
| * The case is designed to test new sysfs boolean knob |
| * /sys/kernel/mm/ksm/merge_across_nodes, which was introduced by |
| * commit 90bd6fd31c8097ee (ksm: allow trees per NUMA node). |
| * when merge_across_nodes is set to zero only pages from the same |
| * node are merged, otherwise pages from all nodes can be merged |
| * together. |
| */ |
| |
| #include "config.h" |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/mman.h> |
| #include <limits.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #if HAVE_NUMA_H |
| #include <numa.h> |
| #endif |
| #if HAVE_NUMAIF_H |
| #include <numaif.h> |
| #endif |
| #include <signal.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <limits.h> |
| |
| #include "mem.h" |
| #include "numa_helper.h" |
| |
| #if defined(HAVE_NUMA_V2) && defined(HAVE_LINUX_MEMPOLICY_H) |
| |
| static int run = -1; |
| static int sleep_millisecs = -1; |
| static int merge_across_nodes = -1; |
| static unsigned long nr_pages; |
| |
| static char *n_opt; |
| static struct tst_option ksm_options[] = { |
| {"n:", &n_opt, "-n x Allocate x pages memory per node"}, |
| {NULL, NULL, NULL} |
| }; |
| |
| static void test_ksm(void) |
| { |
| if (n_opt) |
| nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX); |
| else |
| nr_pages = 100; |
| |
| test_ksm_merge_across_nodes(nr_pages); |
| } |
| |
| static void setup(void) |
| { |
| if (access(PATH_KSM "merge_across_nodes", F_OK) == -1) |
| tst_brk(TCONF, "no merge_across_nodes sysfs knob"); |
| |
| save_max_page_sharing(); |
| |
| if (!is_numa(NULL, NH_MEMS, 2)) |
| tst_brk(TCONF, "The case needs a NUMA system."); |
| |
| /* save the current value */ |
| SAFE_FILE_SCANF(PATH_KSM "run", "%d", &run); |
| SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", |
| "%d", &merge_across_nodes); |
| SAFE_FILE_SCANF(PATH_KSM "sleep_millisecs", |
| "%d", &sleep_millisecs); |
| } |
| |
| static void cleanup(void) |
| { |
| if (merge_across_nodes != -1) { |
| FILE_PRINTF(PATH_KSM "merge_across_nodes", |
| "%d", merge_across_nodes); |
| } |
| |
| if (sleep_millisecs != -1) |
| FILE_PRINTF(PATH_KSM "sleep_millisecs", "%d", sleep_millisecs); |
| |
| if (run != -1) |
| FILE_PRINTF(PATH_KSM "run", "%d", run); |
| |
| restore_max_page_sharing(); |
| } |
| |
| static struct tst_test test = { |
| .needs_root = 1, |
| .options = ksm_options, |
| .setup = setup, |
| .cleanup = cleanup, |
| .test_all = test_ksm, |
| }; |
| |
| #else |
| TST_TEST_TCONF("test requires libnuma >= 2 and it's development packages"); |
| #endif |