1#!/bin/sh
2
3################################################################################
4#                                                                              #
5# Copyright (c) 2009 FUJITSU LIMITED                                           #
6#                                                                              #
7# This program is free software;  you can redistribute it and#or modify        #
8# it under the terms of the GNU General Public License as published by         #
9# the Free Software Foundation; either version 2 of the License, or            #
10# (at your option) any later version.                                          #
11#                                                                              #
12# This program is distributed in the hope that it will be useful, but          #
13# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY   #
14# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License     #
15# for more details.                                                            #
16#                                                                              #
17# You should have received a copy of the GNU General Public License            #
18# along with this program;  if not, write to the Free Software                 #
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA      #
20#                                                                              #
21# Author: Miao Xie <[email protected]>                                      #
22#                                                                              #
23################################################################################
24
25export TCID="cpuset_memory_spread"
26export TST_TOTAL=6
27export TST_COUNT=1
28
29. cpuset_funcs.sh
30
31check
32
33exit_status=0
34nr_cpus=$NR_CPUS
35nr_mems=$N_NODES
36
37# In general, the cache hog will use more than 10000 kb slab space on the nodes
38# on which it is running. The other nodes' slab space has littler change.(less
39# than 1000 kb).
40upperlimit=10000
41
42# set lowerlimit according to pagesize
43# pagesize(bytes)  | lowerlimit(kb)
44# ------------------------------------
45#  4096            | 2048
46#  16384           | 8192
47
48PAGE_SIZE=`tst_getconf PAGESIZE`
49lowerlimit=$((PAGE_SIZE * 512 / 1024))
50
51cpus_all="$(seq -s, 0 $((nr_cpus-1)))"
52mems_all="$(seq -s, 0 $((nr_mems-1)))"
53
54nodedir="/sys/devices/system/node"
55
56FIFO="./myfifo"
57
58# memsinfo is an array implementation of the form of a multi-line string
59# _0: value0
60# _1: value1
61# _2: value2
62#
63memsinfo=""
64
65# set value to memsinfo ($1 - index, $2 - value)
66set_memsinfo_val()
67{
68	local nl='
69'
70	# clearing existent value (if present)
71	memsinfo=`echo "$memsinfo" | sed -r "/^\_$1\: /d"`
72
73	if [ -z "$memsinfo" ]; then
74		memsinfo="_$1: $2"
75	else
76		memsinfo="$memsinfo${nl}_$1: $2"
77	fi
78}
79
80# get value from memsinfo ($1 - index)
81get_memsinfo_val()
82{
83	local value=
84	value=`echo "$memsinfo" | grep -e "^\_$1\: "`
85	value=`echo "$value" | sed -r "s/^.*\: (.*)$/\1/"`
86	echo "$value"
87}
88
89
90init_memsinfo_array()
91{
92	local i=
93
94	for i in `seq 0 $((nr_mems-1))`
95	do
96		set_memsinfo_val $i 0
97	done
98}
99
100# get_meminfo <nodeid> <item>
101get_meminfo()
102{
103	local nodeid="$1"
104	local nodepath="$nodedir/node$nodeid"
105	local nodememinfo="$nodepath/meminfo"
106	local item="$2"
107	local info=`cat $nodememinfo | grep $item | awk '{print $4}'`
108	set_memsinfo_val $nodeid $info
109}
110
111# freemem_check
112# We need enough memory space on every node to run this test, so we must check
113# whether every node has enough free memory or not.
114# return value: 1 - Some node doesn't have enough free memory
115#               0 - Every node has enough free memory, We can do this test
116freemem_check()
117{
118	local i=
119
120	for i in `seq 0 $((nr_mems-1))`
121	do
122		get_meminfo $i "MemFree"
123	done
124
125	for i in `seq 0 $((nr_mems-1))`
126	do
127		# I think we need 100MB free memory to run test
128		if [ $(get_memsinfo_val $i) -lt 100000 ]; then
129			return 1
130		fi
131	done
132}
133
134# get_memsinfo
135get_memsinfo()
136{
137	local i=
138
139	for i in `seq 0 $((nr_mems-1))`
140	do
141		get_meminfo $i "FilePages"
142	done
143}
144
145# account_meminfo <nodeId>
146account_meminfo()
147{
148	local nodeId="$1"
149	local tmp="$(get_memsinfo_val $nodeId)"
150	get_meminfo $@ "FilePages"
151	set_memsinfo_val $nodeId $(($(get_memsinfo_val $nodeId)-$tmp))
152}
153
154# account_memsinfo
155account_memsinfo()
156{
157	local i=
158
159	for i in `seq 0 $((nr_mems-1))`
160	do
161		account_meminfo $i
162	done
163}
164
165
166# result_check <nodelist>
167# return 0: success
168#	 1: fail
169result_check()
170{
171	local nodelist="`echo $1 | sed -e 's/,/ /g'`"
172	local i=
173
174	for i in $nodelist
175	do
176		if [ $(get_memsinfo_val $i) -le $upperlimit ]; then
177			return 1
178		fi
179	done
180
181	local allnodelist="`echo $mems_all | sed -e 's/,/ /g'`"
182	allnodelist=" "$allnodelist" "
183	nodelist=" "$nodelist" "
184
185	local othernodelist="$allnodelist"
186	for i in $nodelist
187	do
188		othernodelist=`echo "$othernodelist" | sed -e "s/ $i / /g"`
189	done
190
191	for i in $othernodelist
192	do
193		if [ $(get_memsinfo_val $i) -gt $lowerlimit ]; then
194			return 1
195		fi
196	done
197}
198
199# general_memory_spread_test <cpusetpath> <is_spread> <cpu_list> <node_list> \
200# <expect_nodes> <test_pid>
201# expect_nodes: we expect to use the slab or cache on which node
202general_memory_spread_test()
203{
204	local cpusetpath="$CPUSET/1"
205	local is_spread="$1"
206	local cpu_list="$2"
207	local node_list="$3"
208	local expect_nodes="$4"
209	local test_pid="$5"
210
211	cpuset_set "$cpusetpath" "$cpu_list" "$node_list" "0" 2> $CPUSET_TMP/stderr
212	if [ $? -ne 0 ]; then
213		cpuset_log_error $CPUSET_TMP/stderr
214		tst_resm TFAIL "set general group parameter failed."
215		return 1
216	fi
217
218	/bin/echo "$is_spread" > "$cpusetpath/cpuset.memory_spread_page" 2> $CPUSET_TMP/stderr
219	if [ $? -ne 0 ]; then
220		cpuset_log_error $CPUSET_TMP/stderr
221		tst_resm TFAIL "set spread value failed."
222		return 1
223	fi
224
225	/bin/echo "$test_pid" > "$cpusetpath/tasks" 2> $CPUSET_TMP/stderr
226	if [ $? -ne 0 ]; then
227		cpuset_log_error $CPUSET_TMP/stderr
228		tst_resm TFAIL "attach task failed."
229		return 1
230	fi
231
232	# we'd better drop the caches before we test page cache.
233	sync
234	/bin/echo 3 > /proc/sys/vm/drop_caches 2> $CPUSET_TMP/stderr
235	if [ $? -ne 0 ]; then
236		cpuset_log_error $CPUSET_TMP/stderr
237		tst_resm TFAIL "drop caches failed."
238		return 1
239	fi
240
241	get_memsinfo
242	/bin/kill -s SIGUSR1 $test_pid
243	read exit_num < $FIFO
244	if [ $exit_num -eq 0 ]; then
245		tst_resm TFAIL "hot mem task failed."
246		return 1
247	fi
248
249	account_memsinfo
250	result_check $expect_nodes
251	if [ $? -ne 0 ]; then
252		tst_resm TFAIL "hog the memory on the unexpected node(FilePages_For_Nodes(KB): ${memsinfo}, Expect Nodes: $expect_nodes)."
253		return 1
254	fi
255}
256
257base_test()
258{
259	local pid=
260	local result_num=
261
262	setup
263	if [ $? -ne 0 ]; then
264		exit_status=1
265	else
266		cpuset_mem_hog &
267		pid=$!
268		general_memory_spread_test "$@" "$pid"
269		result_num=$?
270		if [ $result_num -ne 0 ]; then
271			exit_status=1
272		fi
273
274		/bin/kill -s SIGUSR2 $pid
275		wait $pid
276
277		cleanup
278		if [ $? -ne 0 ]; then
279			exit_status=1
280		elif [ $result_num -eq 0 ]; then
281			tst_resm TPASS "Cpuset memory spread page test succeeded."
282		fi
283	fi
284	TST_COUNT=$(($TST_COUNT + 1))
285}
286
287# test general spread page cache in a cpuset
288test_spread_page1()
289{
290	while read spread cpus nodes exp_nodes
291	do
292		base_test "$spread" "$cpus" "$nodes" "$exp_nodes"
293	done <<- EOF
294		0	0	0	0
295		1	0	0	0
296		0	0	1	1
297		1	0	1	1
298		0	0	0,1	0
299		1	0	0,1	0,1
300	EOF
301	# while read spread cpus nodes exp_nodes
302}
303
304test_spread_page2()
305{
306	local pid=
307	local result_num=
308
309	setup
310	if [ $? -ne 0 ]; then
311		exit_status=1
312	else
313		cpuset_mem_hog &
314		pid=$!
315		general_memory_spread_test "1" "$cpus_all" "0" "0" "$pid"
316		result_num=$?
317		if [ $result_num -ne 0 ]; then
318			exit_status=1
319		else
320			general_memory_spread_test "1" "$cpus_all" "1" "1" "$pid"
321			result_num=$?
322			if [ $result_num -ne 0 ]; then
323				exit_status=1
324			fi
325		fi
326
327		/bin/kill -s SIGUSR2 $pid
328		wait $pid
329
330		cleanup
331		if [ $? -ne 0 ]; then
332			exit_status=1
333		elif [ $result_num -eq 0 ]; then
334			tst_resm TPASS "Cpuset memory spread page test succeeded."
335		fi
336	fi
337}
338
339init_memsinfo_array
340freemem_check
341if [ $? -ne 0 ]; then
342	tst_brkm TCONF "Some node doesn't has enough free memory(100MB) to do test(MemFree_For_Nodes(KB): ${memsinfo[*]})."
343fi
344
345dd if=/dev/zero of=./DATAFILE bs=1M count=100
346if [ $? -ne 0 ]; then
347	tst_brkm TFAIL "Creating DATAFILE failed."
348fi
349
350mkfifo $FIFO
351if [ $? -ne 0 ]; then
352	rm -f DATAFILE
353	tst_brkm TFAIL "failed to mkfifo $FIFO"
354fi
355
356test_spread_page1
357test_spread_page2
358
359rm -f DATAFILE $FIFO
360
361exit $exit_status
362