[LTP] [PATCH v9 1/1] cpuset_memory_spread: rewrite as a C test using the LTP cgroup library
Changwei Zou
changwei.zou@canonical.com
Thu Nov 5 01:55:05 CET 2026
The cpuset_memory_spread test, written in 2009, was split between a shell
script (cpuset_memory_spread_testset.sh) that mounted /dev/cpuset by hand
and a C helper (cpuset_mem_hog) driven over a FIFO and SIGUSR1/SIGUSR2.
It checked the cpuset.memory_spread_page policy by comparing the global
per-node FilePages counters in /sys/devices/system/node/nodeX/meminfo,
which also account for unrelated page-cache activity, so on large or busy
NUMA machines the empirical thresholds became unreliable and the test
failed spuriously.
Rewrite the whole thing as a single C test built on the new LTP test API,
the LTP cgroup library (tst_cgroup.h) and the NUMA helpers from
tse_numa.h, dropping the shell script, the FIFO/signal handshake and the
manual /dev/cpuset management.
For each case the test pins itself to the local node, sets cpuset.mems
and cpuset.memory_spread_page, faults a file-backed shared mapping and
uses tse_nodemap_count_pages() (get_mempolicy(2)) to learn the NUMA node
of each of the mapping's pages. Only the test mapping's own pages are
counted, so unrelated page-cache activity can no longer perturb the
result. The distribution is then verified: the pages must land on the
expected node(s), the other nodes may hold at most UNEXPECTED_TOLERANCE
(5%) of them, and when several expected nodes are given each must hold at
least (100 - BALANCE_TOLERANCE, 80%) of its even share.
cpuset.memory_spread_page only exists in the cgroup v1 cpuset controller,
so the test requires a v1 cpuset hierarchy (.needs_cgroup_ver = TST_CG_V1)
and is skipped with TCONF when cpuset is mounted on the unified (v2)
hierarchy. Register cpuset.memory_spread_page in the LTP cgroup library's
cpuset file table so it can be driven through the SAFE_CG_* helpers.
Signed-off-by: Changwei Zou <changwei.zou@canonical.com>
Assisted-By: opencode (claude-opus-4.8)
---
lib/tst_cgroup.c | 1 +
runtest/controllers | 2 +-
.../kernel/controllers/cpuset/.gitignore | 2 +-
.../cpuset/cpuset_memory_spread_test/Makefile | 7 +-
.../cpuset_mem_hog.c | 126 ------
.../cpuset_memory_spread01.c | 214 +++++++++++
.../cpuset_memory_spread_testset.sh | 362 ------------------
7 files changed, 223 insertions(+), 491 deletions(-)
delete mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_mem_hog.c
create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread01.c
delete mode 100755 testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh
diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c
index 7c6ecd4d2..74459138f 100644
--- a/lib/tst_cgroup.c
+++ b/lib/tst_cgroup.c
@@ -206,6 +206,7 @@ static const struct cgroup_file cpuset_ctrl_files[] = {
{ "cpuset.cpus", "cpuset.cpus", CTRL_CPUSET },
{ "cpuset.mems", "cpuset.mems", CTRL_CPUSET },
{ "cpuset.memory_migrate", "cpuset.memory_migrate", CTRL_CPUSET },
+ { "cpuset.memory_spread_page", "cpuset.memory_spread_page", CTRL_CPUSET },
{ }
};
diff --git a/runtest/controllers b/runtest/controllers
index 93c52c439..0af338369 100644
--- a/runtest/controllers
+++ b/runtest/controllers
@@ -357,7 +357,7 @@ cpuset_load_balance cpuset_load_balance_test.sh
cpuset_hotplug cpuset_hotplug_test.sh
cpuset_memory cpuset_memory_testset.sh
cpuset_memory_pressure cpuset_memory_pressure_testset.sh
-cpuset_memory_spread cpuset_memory_spread_testset.sh
+cpuset_memory_spread01 cpuset_memory_spread01
cpuset_regression_test cpuset_regression_test.sh
diff --git a/testcases/kernel/controllers/cpuset/.gitignore b/testcases/kernel/controllers/cpuset/.gitignore
index c65f2fb61..6a8d713c2 100644
--- a/testcases/kernel/controllers/cpuset/.gitignore
+++ b/testcases/kernel/controllers/cpuset/.gitignore
@@ -2,6 +2,6 @@
/cpuset_load_balance_test/cpuset_cpu_hog
/cpuset_load_balance_test/cpuset_sched_domains_check
/cpuset_memory_pressure_test/cpuset_memory_pressure
-/cpuset_memory_spread_test/cpuset_mem_hog
+/cpuset_memory_spread_test/cpuset_memory_spread01
/cpuset_memory_test/cpuset_memory_test
/cpuset_syscall_test/cpuset_syscall_test
diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/Makefile b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/Makefile
index b3c76f0de..5b681f77c 100644
--- a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/Makefile
+++ b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/Makefile
@@ -22,6 +22,11 @@
top_srcdir ?= ../../../../..
+LTPLIBS = numa
+
include $(top_srcdir)/include/mk/testcases.mk
-include $(abs_srcdir)/../Makefile.inc
+
+cpuset_memory_spread01: LDLIBS += $(NUMA_LIBS)
+cpuset_memory_spread01: LTPLDLIBS = -lltpnuma
+
include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_mem_hog.c b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_mem_hog.c
deleted file mode 100644
index 56e039eee..000000000
--- a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_mem_hog.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************************************/
-/* */
-/* Copyright (c) 2009 FUJITSU LIMITED */
-/* */
-/* 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. */
-/* */
-/* You should have received a copy of the GNU General Public License */
-/* along with this program; if not, write to the Free Software */
-/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
-/* */
-/* Author: Miao Xie <miaox@cn.fujitsu.com> */
-/* */
-/******************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <err.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "../cpuset_lib/common.h"
-
-#define BUFFER_SIZE 100
-
-volatile int end;
-
-void sighandler1(UNUSED int signo)
-{
-}
-
-void sighandler2(UNUSED int signo)
-{
- end = 1;
-}
-
-int page_cache_hog(void)
-{
- int fd = -1;
- char buff[BUFFER_SIZE];
- char path[BUFFER_SIZE];
- int ret = 0;
-
- sprintf(path, "%s", "DATAFILE");
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- warn("open %s failed", path);
- return -1;
- }
-
- while ((ret = read(fd, buff, sizeof(buff))) > 0) ;
- if (ret == -1)
- warn("read %s failed", path);
-
- close(fd);
- return ret;
-}
-
-int mem_hog(void)
-{
- sigset_t signalset;
- int fd;
- int ret = 0;
-
- if (sigemptyset(&signalset) < 0)
- err(1, "sigemptyset()");
- sigsuspend(&signalset);
-
- while (!end) {
- ret = page_cache_hog();
-
- fd = open("./myfifo", O_WRONLY);
- if (fd == -1)
- err(1, "open fifo failed");
-
- if (ret) {
- if (write(fd, "0", 1) == -1)
- warn("write fifo failed.");
- } else {
- if (write(fd, "1", 1) == -1)
- warn("write fifo failed.");
- }
-
- close(fd);
-
- sigsuspend(&signalset);
- }
-
- return ret;
-}
-
-int main(void)
-{
- struct sigaction sa1, sa2;
-
- sa1.sa_handler = sighandler1;
- if (sigemptyset(&sa1.sa_mask) < 0)
- err(1, "sigemptyset()");
-
- sa1.sa_flags = 0;
- if (sigaction(SIGUSR1, &sa1, NULL) < 0)
- err(1, "sigaction()");
-
- sa2.sa_handler = sighandler2;
- if (sigemptyset(&sa2.sa_mask) < 0)
- err(1, "sigemptyset()");
-
- sa2.sa_flags = 0;
- if (sigaction(SIGUSR2, &sa2, NULL) < 0)
- err(1, "sigaction()");
-
- return mem_hog();
-}
diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread01.c b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread01.c
new file mode 100644
index 000000000..0edaaebb0
--- /dev/null
+++ b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread01.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2009 FUJITSU LIMITED
+ * Author: Miao Xie <miaox@cn.fujitsu.com>
+ *
+ * Rewritten into a single C test using the LTP cgroup library.
+ */
+
+/*\
+ * Verify the ``cpuset.memory_spread_page`` control file.
+ *
+ * A task's file-backed page cache is normally allocated on the node the task
+ * runs on (local allocation). When ``cpuset.memory_spread_page`` is enabled,
+ * the page cache of a task in the cpuset is instead spread evenly over all
+ * the memory nodes allowed by ``cpuset.mems``.
+ *
+ * For every case the test pins itself to the local node, sets ``cpuset.mems``
+ * and ``cpuset.memory_spread_page``, then faults a file-backed shared mapping
+ * and uses :manpage:`get_mempolicy(2)` (through the tse_numa helpers) to learn
+ * the NUMA node each of the mapping's pages resides on. Because only the test
+ * mapping's own pages are counted, unrelated page-cache activity on the system
+ * cannot perturb the result. The resulting distribution is verified:
+ *
+ * - with spreading off the pages must land on the expected node (the local
+ * node, or the only node allowed by ``cpuset.mems``);
+ * - with spreading on over several nodes the pages must be spread evenly.
+ *
+ * ``cpuset.memory_spread_page`` exists only in the cgroup v1 cpuset
+ * controller, so the test requires a v1 cpuset hierarchy and is skipped
+ * (TCONF) when cpuset is mounted on the unified (v2) hierarchy.
+ *
+ * The test is skipped on tmpfs/ramfs, where the mapping's pages are the
+ * backing store itself rather than ordinary page cache, so their placement
+ * is not governed by this knob.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifdef HAVE_NUMA_H
+# include <numa.h>
+#endif
+
+#include "tst_test.h"
+#include "tst_cgroup.h"
+#include "tse_numa.h"
+
+#ifdef HAVE_NUMA_V2
+
+/* Path of the file-backed mapping whose page placement we measure. */
+#define DATAFILE "numa_data_file"
+
+/* Size of the mapping. Large enough to measure an even spread reliably. */
+#define SIZE_MB 100
+#define SIZE ((size_t)SIZE_MB * 1024 * 1024)
+
+/* Each node needs enough free memory to hold the whole mapping plus slack. */
+#define MIN_FREE_KB ((SIZE_MB + 50) * 1024)
+
+/*
+ * The pages must land on the expected node(s); the other nodes may hold at
+ * most this fraction (in percent) of them.
+ */
+#define UNEXPECTED_TOLERANCE 5
+
+/*
+ * When the pages are spread across several expected nodes, the kernel spreads
+ * them evenly. Every expected node must hold at least
+ * (100 - BALANCE_TOLERANCE) percent of its even share.
+ */
+#define BALANCE_TOLERANCE 20
+
+static struct tse_nodemap *nodes;
+
+/*
+ * The task's CPUs are pinned to the local node (nodes->map[0]) for every case
+ * (see setup()); only cpuset.mems and cpuset.memory_spread_page change.
+ *
+ * mems/expect are strings of single-digit indices into nodes->map: '0' is the
+ * local node, '1' the remote one.
+ */
+static const struct tcase {
+ int spread;
+ const char *mems;
+ const char *expect;
+ const char *desc;
+} tcases[] = {
+ {0, "0", "0", "spread off, mems on the local node"},
+ {1, "0", "0", "spread on, mems on the local node"},
+ {0, "1", "1", "spread off, mems on the remote node"},
+ {1, "1", "1", "spread on, mems on the remote node"},
+ {0, "01", "0", "spread off, mems on both nodes (local allocation)"},
+ {1, "01", "01", "spread on, mems on both nodes (even spread)"},
+};
+
+static void check_result(const char *expect, const char *desc)
+{
+ unsigned int i, total = 0, expected_sum = 0, n_expect = 0, unexpected;
+
+ for (i = 0; i < nodes->cnt; i++)
+ total += nodes->counters[i];
+
+ if (!total) {
+ tst_res(TFAIL, "%s: no pages were allocated", desc);
+ return;
+ }
+
+ for (i = 0; expect[i]; i++) {
+ expected_sum += nodes->counters[expect[i] - '0'];
+ n_expect++;
+ }
+
+ unexpected = total - expected_sum;
+
+ tst_res(TINFO,
+ "%s: unexpected nodes hold %.2f%% of the pages (tolerance %d%%)",
+ desc, (double)unexpected * 100 / total, UNEXPECTED_TOLERANCE);
+
+ if (unexpected * 100 > total * UNEXPECTED_TOLERANCE) {
+ tst_res(TFAIL, "%s: too many pages on unexpected node(s)", desc);
+ return;
+ }
+
+ /*
+ * Every expected node must hold at least (100 - BALANCE_TOLERANCE)% of
+ * its even share. This enforces an even spread across several expected
+ * nodes and rejects an expected node that received nothing. A single
+ * expected node always passes this check.
+ */
+ for (i = 0; expect[i]; i++) {
+ unsigned int idx = expect[i] - '0';
+
+ if (nodes->counters[idx] * n_expect * 100 <
+ expected_sum * (100 - BALANCE_TOLERANCE)) {
+ tst_res(TFAIL, "%s: node %u holds too few pages",
+ desc, nodes->map[idx]);
+ return;
+ }
+ }
+
+ tst_res(TPASS, "%s", desc);
+}
+
+static void run(unsigned int n)
+{
+ const struct tcase *tc = &tcases[n];
+ char mems[64];
+ size_t len = 0;
+ void *ptr;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; tc->mems[i]; i++) {
+ ret = snprintf(mems + len, sizeof(mems) - len, "%s%u",
+ i ? "," : "", nodes->map[tc->mems[i] - '0']);
+ if (ret < 0 || (size_t)ret >= sizeof(mems) - len)
+ tst_brk(TBROK, "failed to build cpuset.mems string");
+ len += ret;
+ }
+
+ SAFE_CG_PRINT(tst_cg, "cpuset.mems", mems);
+ SAFE_CG_PRINTF(tst_cg, "cpuset.memory_spread_page", "%d", tc->spread);
+
+ ptr = tse_numa_map(DATAFILE, SIZE);
+ tse_numa_fault(ptr, SIZE);
+ tse_nodemap_reset_counters(nodes);
+ tse_nodemap_count_pages(nodes, ptr, SIZE);
+ tse_numa_unmap(ptr, SIZE);
+
+ check_result(tc->expect, tc->desc);
+}
+
+static void setup(void)
+{
+ nodes = tse_get_nodemap(TST_NUMA_MEM, MIN_FREE_KB);
+ if (nodes->cnt < 2)
+ tst_brk(TCONF, "requires at least 2 NUMA memory nodes");
+
+ if (!SAFE_CG_HAS(tst_cg, "cpuset.memory_spread_page"))
+ tst_brk(TCONF, "cpuset.memory_spread_page not available");
+
+ SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid());
+
+ /* Pin the task to the local node for every case. */
+ if (numa_run_on_node(nodes->map[0]))
+ tst_brk(TCONF, "cannot run on node %u (no CPUs?)",
+ nodes->map[0]);
+}
+
+static void cleanup(void)
+{
+ if (nodes)
+ tse_nodemap_free(nodes);
+}
+
+static struct tst_test test = {
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .skip_filesystems = (const char *const []){ "tmpfs", "ramfs", NULL },
+ .setup = setup,
+ .cleanup = cleanup,
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+ .needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL },
+ .needs_cgroup_ver = TST_CG_V1,
+};
+
+#else
+TST_TEST_TCONF("test requires libnuma >= 2");
+#endif
diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh
deleted file mode 100755
index 4c49bb8fd..000000000
--- a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh
+++ /dev/null
@@ -1,362 +0,0 @@
-#!/bin/sh
-
-################################################################################
-# #
-# Copyright (c) 2009 FUJITSU LIMITED #
-# #
-# 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. #
-# #
-# You should have received a copy of the GNU General Public License #
-# along with this program; if not, write to the Free Software #
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #
-# #
-# Author: Miao Xie <miaox@cn.fujitsu.com> #
-# #
-################################################################################
-
-export TCID="cpuset_memory_spread"
-export TST_TOTAL=6
-export TST_COUNT=1
-
-. cpuset_funcs.sh
-
-check
-
-exit_status=0
-nr_cpus=$NR_CPUS
-nr_mems=$N_NODES
-
-# In general, the cache hog will use more than 10000 kb slab space on the nodes
-# on which it is running. The other nodes' slab space has littler change.(less
-# than 1000 kb).
-upperlimit=10000
-
-# set lowerlimit according to pagesize
-# pagesize(bytes) | lowerlimit(kb)
-# ------------------------------------
-# 4096 | 2048
-# 16384 | 8192
-
-PAGE_SIZE=`tst_getconf PAGESIZE`
-lowerlimit=$((PAGE_SIZE * 512 / 1024))
-
-cpus_all="$(seq -s, 0 $((nr_cpus-1)))"
-mems_all="$(seq -s, 0 $((nr_mems-1)))"
-
-nodedir="/sys/devices/system/node"
-
-FIFO="./myfifo"
-
-# memsinfo is an array implementation of the form of a multi-line string
-# _0: value0
-# _1: value1
-# _2: value2
-#
-memsinfo=""
-
-# set value to memsinfo ($1 - index, $2 - value)
-set_memsinfo_val()
-{
- local nl='
-'
- # clearing existent value (if present)
- memsinfo=`echo "$memsinfo" | sed -r "/^\_$1\: /d"`
-
- if [ -z "$memsinfo" ]; then
- memsinfo="_$1: $2"
- else
- memsinfo="$memsinfo${nl}_$1: $2"
- fi
-}
-
-# get value from memsinfo ($1 - index)
-get_memsinfo_val()
-{
- local value=
- value=`echo "$memsinfo" | grep -e "^_$1: "`
- value=`echo "$value" | sed -r "s/^.*\: (.*)$/\1/"`
- echo "$value"
-}
-
-
-init_memsinfo_array()
-{
- local i=
-
- for i in `seq 0 $((nr_mems-1))`
- do
- set_memsinfo_val $i 0
- done
-}
-
-# get_meminfo <nodeid> <item>
-get_meminfo()
-{
- local nodeid="$1"
- local nodepath="$nodedir/node$nodeid"
- local nodememinfo="$nodepath/meminfo"
- local item="$2"
- local info=`cat $nodememinfo | grep $item | awk '{print $4}'`
- set_memsinfo_val $nodeid $info
-}
-
-# freemem_check
-# We need enough memory space on every node to run this test, so we must check
-# whether every node has enough free memory or not.
-# return value: 1 - Some node doesn't have enough free memory
-# 0 - Every node has enough free memory, We can do this test
-freemem_check()
-{
- local i=
-
- for i in `seq 0 $((nr_mems-1))`
- do
- get_meminfo $i "MemFree"
- done
-
- for i in `seq 0 $((nr_mems-1))`
- do
- # I think we need 100MB free memory to run test
- if [ $(get_memsinfo_val $i) -lt 100000 ]; then
- return 1
- fi
- done
-}
-
-# get_memsinfo
-get_memsinfo()
-{
- local i=
-
- for i in `seq 0 $((nr_mems-1))`
- do
- get_meminfo $i "FilePages"
- done
-}
-
-# account_meminfo <nodeId>
-account_meminfo()
-{
- local nodeId="$1"
- local tmp="$(get_memsinfo_val $nodeId)"
- get_meminfo $@ "FilePages"
- set_memsinfo_val $nodeId $(($(get_memsinfo_val $nodeId)-$tmp))
-}
-
-# account_memsinfo
-account_memsinfo()
-{
- local i=
-
- for i in `seq 0 $((nr_mems-1))`
- do
- account_meminfo $i
- done
-}
-
-
-# result_check <nodelist>
-# return 0: success
-# 1: fail
-result_check()
-{
- local nodelist="`echo $1 | sed -e 's/,/ /g'`"
- local i=
-
- for i in $nodelist
- do
- if [ $(get_memsinfo_val $i) -le $upperlimit ]; then
- return 1
- fi
- done
-
- local allnodelist="`echo $mems_all | sed -e 's/,/ /g'`"
- allnodelist=" "$allnodelist" "
- nodelist=" "$nodelist" "
-
- local othernodelist="$allnodelist"
- for i in $nodelist
- do
- othernodelist=`echo "$othernodelist" | sed -e "s/ $i / /g"`
- done
-
- for i in $othernodelist
- do
- if [ $(get_memsinfo_val $i) -gt $lowerlimit ]; then
- return 1
- fi
- done
-}
-
-# general_memory_spread_test <cpusetpath> <is_spread> <cpu_list> <node_list> \
-# <expect_nodes> <test_pid>
-# expect_nodes: we expect to use the slab or cache on which node
-general_memory_spread_test()
-{
- local cpusetpath="$CPUSET/1"
- local is_spread="$1"
- local cpu_list="$2"
- local node_list="$3"
- local expect_nodes="$4"
- local test_pid="$5"
-
- cpuset_set "$cpusetpath" "$cpu_list" "$node_list" "0" 2> $CPUSET_TMP/stderr
- if [ $? -ne 0 ]; then
- cpuset_log_error $CPUSET_TMP/stderr
- tst_resm TFAIL "set general group parameter failed."
- return 1
- fi
-
- /bin/echo "$is_spread" > "$cpusetpath/cpuset.memory_spread_page" 2> $CPUSET_TMP/stderr
- if [ $? -ne 0 ]; then
- cpuset_log_error $CPUSET_TMP/stderr
- tst_resm TFAIL "set spread value failed."
- return 1
- fi
-
- /bin/echo "$test_pid" > "$cpusetpath/tasks" 2> $CPUSET_TMP/stderr
- if [ $? -ne 0 ]; then
- cpuset_log_error $CPUSET_TMP/stderr
- tst_resm TFAIL "attach task failed."
- return 1
- fi
-
- # we'd better drop the caches before we test page cache.
- sync
- /bin/echo 3 > /proc/sys/vm/drop_caches 2> $CPUSET_TMP/stderr
- if [ $? -ne 0 ]; then
- cpuset_log_error $CPUSET_TMP/stderr
- tst_resm TFAIL "drop caches failed."
- return 1
- fi
-
- get_memsinfo
- /bin/kill -s SIGUSR1 $test_pid
- read exit_num < $FIFO
- if [ $exit_num -eq 0 ]; then
- tst_resm TFAIL "hot mem task failed."
- return 1
- fi
-
- account_memsinfo
- result_check $expect_nodes
- if [ $? -ne 0 ]; then
- tst_resm TFAIL "hog the memory on the unexpected node(FilePages_For_Nodes(KB): ${memsinfo}, Expect Nodes: $expect_nodes)."
- return 1
- fi
-}
-
-base_test()
-{
- local pid=
- local result_num=
-
- setup
- if [ $? -ne 0 ]; then
- exit_status=1
- else
- cpuset_mem_hog &
- pid=$!
- general_memory_spread_test "$@" "$pid"
- result_num=$?
- if [ $result_num -ne 0 ]; then
- exit_status=1
- fi
-
- /bin/kill -s SIGUSR2 $pid
- wait $pid
-
- cleanup
- if [ $? -ne 0 ]; then
- exit_status=1
- elif [ $result_num -eq 0 ]; then
- tst_resm TPASS "Cpuset memory spread page test succeeded."
- fi
- fi
- TST_COUNT=$(($TST_COUNT + 1))
-}
-
-# test general spread page cache in a cpuset
-test_spread_page1()
-{
- while read spread cpus nodes exp_nodes
- do
- base_test "$spread" "$cpus" "$nodes" "$exp_nodes"
- done <<- EOF
- 0 0 0 0
- 1 0 0 0
- 0 0 1 1
- 1 0 1 1
- 0 0 0,1 0
- 1 0 0,1 0,1
- EOF
- # while read spread cpus nodes exp_nodes
-}
-
-test_spread_page2()
-{
- local pid=
- local result_num=
-
- setup
- if [ $? -ne 0 ]; then
- exit_status=1
- else
- cpuset_mem_hog &
- pid=$!
- general_memory_spread_test "1" "$cpus_all" "0" "0" "$pid"
- result_num=$?
- if [ $result_num -ne 0 ]; then
- exit_status=1
- else
- general_memory_spread_test "1" "$cpus_all" "1" "1" "$pid"
- result_num=$?
- if [ $result_num -ne 0 ]; then
- exit_status=1
- fi
- fi
-
- /bin/kill -s SIGUSR2 $pid
- wait $pid
-
- cleanup
- if [ $? -ne 0 ]; then
- exit_status=1
- elif [ $result_num -eq 0 ]; then
- tst_resm TPASS "Cpuset memory spread page test succeeded."
- fi
- fi
-}
-
-init_memsinfo_array
-freemem_check
-if [ $? -ne 0 ]; then
- tst_brkm TCONF "Some node doesn't has enough free memory(100MB) to do test(MemFree_For_Nodes(KB): ${memsinfo[*]})."
-fi
-
-dd if=/dev/zero of=./DATAFILE bs=1M count=100
-if [ $? -ne 0 ]; then
- tst_brkm TFAIL "Creating DATAFILE failed."
-fi
-
-rm -f $FIFO
-mkfifo $FIFO
-if [ $? -ne 0 ]; then
- rm -f DATAFILE
- tst_brkm TFAIL "failed to mkfifo $FIFO"
-fi
-
-test_spread_page1
-test_spread_page2
-
-rm -f DATAFILE $FIFO
-
-exit $exit_status
--
2.43.0
More information about the ltp
mailing list