• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) International Business Machines Corp., 2007
4# Copyright (c) Linux Test Project, 2016
5# Author: Sivakumar Chinnaiah <Sivakumar.C@in.ibm.com>
6#
7# Test Basic functionality of numactl command.
8# Test #1: Verifies cpunodebind and membind
9# Test #2: Verifies preferred node bind for memory allocation
10# Test #3: Verifies memory interleave on all nodes
11# Test #4: Verifies physcpubind
12# Test #5: Verifies localalloc
13# Test #6: Verifies memhog
14# Test #7: Verifies numa_node_size api
15# Test #8:Verifies Migratepages
16# Test #9:Verifies hugepage alloacted on specified node
17# Test #10:Verifies THP memory allocated on preferred node
18
19TST_CNT=10
20TST_SETUP=setup
21TST_TESTFUNC=test
22TST_NEEDS_TMPDIR=1
23TST_NEEDS_ROOT=1
24TST_NEEDS_CMDS="awk bc numactl numastat"
25
26. tst_test.sh
27
28# Extracts the value of given numa node from the `numastat -p` output.
29# $1 - Pid number.
30# $2 - Node number.
31extract_numastat_p()
32{
33	local pid=$1
34	local node=$(($2 + 2))
35
36	echo $(numastat -p $pid |awk '/^Total/ {print $'$node'}')
37}
38
39check_for_support_numa()
40{
41	local pid=$1
42
43	local state=$(awk '{print $3}' /proc/$pid/stat)
44
45	if [ $state = 'T' ]; then
46		return 0
47	fi
48
49	return 1
50}
51
52setup()
53{
54	export MB=$((1024*1024))
55	export PAGE_SIZE=$(tst_getconf PAGESIZE)
56	export HPAGE_SIZE=$(awk '/Hugepagesize:/ {print $2}' /proc/meminfo)
57
58	total_nodes=0
59
60	nodes_list=$(numactl --show | grep nodebind | cut -d ':' -f 2)
61	for node in $nodes_list; do
62		total_nodes=$((total_nodes+1))
63	done
64
65	tst_res TINFO "The system contains $total_nodes nodes: $nodes_list"
66	if [ $total_nodes -le 1 ]; then
67		tst_brk TCONF "your machine does not support numa policy
68		or your machine is not a NUMA machine"
69	fi
70}
71
72# Verification of memory allocated on a node
73test1()
74{
75	Mem_curr=0
76
77	for node in $nodes_list; do
78		numactl --cpunodebind=$node --membind=$node support_numa alloc_1MB &
79		pid=$!
80
81		TST_RETRY_FUNC "check_for_support_numa $pid" 0
82
83		Mem_curr=$(echo "$(extract_numastat_p $pid $node) * $MB" |bc)
84		if [ $(echo "$Mem_curr < $MB" | bc) -eq 1 ]; then
85			tst_res TFAIL \
86				"NUMA memory allocated in node$node is less than expected"
87			kill -CONT $pid >/dev/null 2>&1
88			return
89		fi
90
91		kill -CONT $pid >/dev/null 2>&1
92	done
93
94	tst_res TPASS "NUMA local node and memory affinity"
95}
96
97# Verification of memory allocated on preferred node
98test2()
99{
100	Mem_curr=0
101
102	COUNTER=1
103	for node in $nodes_list; do
104
105		if [ $COUNTER -eq $total_nodes ]; then   #wrap up for last node
106			Preferred_node=$(echo $nodes_list | cut -d ' ' -f 1)
107		else
108			# always next node is preferred node
109			Preferred_node=$(echo $nodes_list | cut -d ' ' -f $((COUNTER+1)))
110		fi
111
112		numactl --cpunodebind=$node --preferred=$Preferred_node support_numa alloc_1MB &
113		pid=$!
114
115		TST_RETRY_FUNC "check_for_support_numa $pid" 0
116
117		Mem_curr=$(echo "$(extract_numastat_p $pid $Preferred_node) * $MB" |bc)
118		if [ $(echo "$Mem_curr < $MB" |bc ) -eq 1 ]; then
119			tst_res TFAIL \
120				"NUMA memory allocated in node$Preferred_node is less than expected"
121			kill -CONT $pid >/dev/null 2>&1
122			return
123		fi
124
125		COUNTER=$((COUNTER+1))
126		kill -CONT $pid >/dev/null 2>&1
127	done
128
129	tst_res TPASS "NUMA preferred node policy"
130}
131
132# Verification of memory interleaved on all nodes
133test3()
134{
135	Mem_curr=0
136	# Memory will be allocated using round robin on nodes.
137	Exp_incr=$(echo "$MB / $total_nodes" |bc)
138
139	numactl --interleave=all support_numa alloc_1MB &
140	pid=$!
141
142	TST_RETRY_FUNC "check_for_support_numa $pid" 0
143
144	for node in $nodes_list; do
145		Mem_curr=$(echo "$(extract_numastat_p $pid $node) * $MB" |bc)
146
147		if [ $(echo "$Mem_curr < $Exp_incr" |bc ) -eq 1 ]; then
148			tst_res TFAIL \
149				"NUMA interleave memory allocated in node$node is less than expected"
150			kill -CONT $pid >/dev/null 2>&1
151			return
152		fi
153	done
154
155	kill -CONT $pid >/dev/null 2>&1
156	tst_res TPASS "NUMA interleave policy"
157}
158
159# Verification of physical cpu bind
160test4()
161{
162	no_of_cpus=0	#no. of cpu's exist
163	run_on_cpu=0
164	running_on_cpu=0
165
166	no_of_cpus=$(tst_ncpus)
167	# not sure whether cpu's can't be in odd number
168	run_on_cpu=$(($((no_of_cpus+1))/2))
169	numactl --physcpubind=$run_on_cpu support_numa pause & #just waits for sigint
170	pid=$!
171	var=`awk '{ print $2 }' /proc/$pid/stat`
172	while [ $var = '(numactl)' ]; do
173		var=`awk '{ print $2 }' /proc/$pid/stat`
174		tst_sleep 100ms
175	done
176	# Warning !! 39 represents cpu number, on which process pid is currently running and
177	# this may change if Some more fields are added in the middle, may be in future
178	running_on_cpu=$(awk '{ print $39; }' /proc/$pid/stat)
179	if [ $running_on_cpu -ne $run_on_cpu ]; then
180		tst_res TFAIL \
181			"Process running on cpu$running_on_cpu but expected to run on cpu$run_on_cpu"
182		ROD kill -INT $pid
183		return
184	fi
185
186	ROD kill -INT $pid
187
188	tst_res TPASS "NUMA phycpubind policy"
189}
190
191# Verification of local node allocation
192test5()
193{
194	Mem_curr=0
195
196	for node in $nodes_list; do
197		numactl --cpunodebind=$node --localalloc support_numa alloc_1MB &
198		pid=$!
199
200		TST_RETRY_FUNC "check_for_support_numa $pid" 0
201
202		Mem_curr=$(echo "$(extract_numastat_p $pid $node) * $MB" |bc)
203		if [ $(echo "$Mem_curr < $MB" |bc ) -eq 1 ]; then
204			tst_res TFAIL \
205				"NUMA localnode memory allocated in node$node is less than expected"
206			kill -CONT $pid >/dev/null 2>&1
207			return
208		fi
209
210		kill -CONT $pid >/dev/null 2>&1
211	done
212
213	tst_res TPASS "NUMA local node allocation"
214}
215
216check_ltp_numa_test8_log()
217{
218	grep -m1 -q '.' ltp_numa_test8.log
219}
220
221# Verification of memhog with interleave policy
222test6()
223{
224	Mem_curr=0
225	# Memory will be allocated using round robin on nodes.
226	Exp_incr=$(echo "$MB / $total_nodes" |bc)
227
228	numactl --interleave=all memhog -r1000000 1MB >ltp_numa_test8.log 2>&1 &
229	pid=$!
230
231	TST_RETRY_FUNC "check_ltp_numa_test8_log" 0
232
233	for node in $nodes_list; do
234		Mem_curr=$(echo "$(extract_numastat_p $pid $node) * $MB" |bc)
235
236		if [ $(echo "$Mem_curr < $Exp_incr" |bc ) -eq 1 ]; then
237			tst_res TFAIL \
238				"NUMA interleave memhog in node$node is less than expected"
239			kill -KILL $pid >/dev/null 2>&1
240			return
241		fi
242	done
243
244	kill -KILL $pid >/dev/null 2>&1
245	tst_res TPASS "NUMA MEMHOG policy"
246}
247
248# Function:     hardware cheking with numa_node_size api
249#
250# Description:  - Returns the size of available nodes if success.
251#
252# Input:        - o/p of numactl --hardware command which is expected in the format
253#                 shown below
254#               available: 2 nodes (0-1)
255#               node 0 size: 7808 MB
256#               node 0 free: 7457 MB
257#               node 1 size: 5807 MB
258#               node 1 free: 5731 MB
259#               node distances:
260#               node   0   1
261#                 0:  10  20
262#                 1:  20  10
263#
264test7()
265{
266	RC=0
267
268	numactl --hardware > gavail_nodes
269	RC=$(awk '{ if ( NR == 1 ) {print $1;} }' gavail_nodes)
270	if [ $RC = "available:" ]; then
271		RC=$(awk '{ if ( NR == 1 ) {print $3;} }' gavail_nodes)
272		if [ $RC = "nodes" ]; then
273			RC=$(awk '{ if ( NR == 1 ) {print $2;} }' gavail_nodes)
274			tst_res TPASS "NUMA policy on lib NUMA_NODE_SIZE API"
275		else
276			tst_res TFAIL "Failed with numa policy"
277		fi
278	else
279		tst_res TFAIL "Failed with numa policy"
280	fi
281}
282
283# Verification of migratepages
284test8()
285{
286	Mem_curr=0
287	COUNTER=1
288
289	for node in $nodes_list; do
290
291		if [ $COUNTER -eq $total_nodes ]; then
292			Preferred_node=$(echo $nodes_list | cut -d ' ' -f 1)
293		else
294			Preferred_node=$(echo $nodes_list | cut -d ' ' -f $((COUNTER+1)))
295		fi
296
297		numactl --preferred=$node support_numa alloc_1MB &
298		pid=$!
299
300		TST_RETRY_FUNC "check_for_support_numa $pid" 0
301
302		migratepages $pid $node $Preferred_node
303
304		Mem_curr=$(echo "$(extract_numastat_p $pid $Preferred_node) * $MB" |bc)
305		if [ $(echo "$Mem_curr < $MB" |bc ) -eq 1 ]; then
306			tst_res TFAIL \
307				"NUMA migratepages is not working fine"
308			kill -CONT $pid >/dev/null 2>&1
309			return
310		fi
311
312		COUNTER=$((COUNTER+1))
313		kill -CONT $pid >/dev/null 2>&1
314	done
315
316	tst_res TPASS "NUMA MIGRATEPAGES policy"
317}
318
319# Verification of hugepage memory allocated on a node
320test9()
321{
322	Mem_huge=0
323	Sys_node=/sys/devices/system/node
324
325	if [ ! -d "/sys/kernel/mm/hugepages/" ]; then
326		tst_res TCONF "hugepage is not supported"
327		return
328	fi
329
330	for node in $nodes_list; do
331		Ori_hpgs=$(cat ${Sys_node}/node${node}/hugepages/hugepages-${HPAGE_SIZE}kB/nr_hugepages)
332		New_hpgs=$((Ori_hpgs + 1))
333		echo $New_hpgs >${Sys_node}/node${node}/hugepages/hugepages-${HPAGE_SIZE}kB/nr_hugepages
334
335		Chk_hpgs=$(cat ${Sys_node}/node${node}/hugepages/hugepages-${HPAGE_SIZE}kB/nr_hugepages)
336		if [ "$Chk_hpgs" -ne "$New_hpgs" ]; then
337			tst_res TCONF "hugepage is not enough to test"
338			return
339		fi
340
341		numactl --cpunodebind=$node --membind=$node support_numa alloc_1huge_page &
342		pid=$!
343		TST_RETRY_FUNC "check_for_support_numa $pid" 0
344
345		Mem_huge=$(echo $(numastat -p $pid |awk '/^Huge/ {print $'$((node+2))'}'))
346		Mem_huge=$((${Mem_huge%.*} * 1024))
347
348		if [ "$Mem_huge" -lt "$HPAGE_SIZE" ]; then
349			tst_res TFAIL \
350				"NUMA memory allocated in node$node is less than expected"
351			kill -CONT $pid >/dev/null 2>&1
352			echo $Ori_hpgs >${Sys_node}/node${node}/hugepages/hugepages-${HPAGE_SIZE}kB/nr_hugepages
353			return
354		fi
355
356		kill -CONT $pid >/dev/null 2>&1
357		echo $Ori_hpgs >${Sys_node}/node${node}/hugepages/hugepages-${HPAGE_SIZE}kB/nr_hugepages
358	done
359
360	tst_res TPASS "NUMA local node hugepage memory allocated"
361}
362
363# Verification of THP memory allocated on preferred node
364test10()
365{
366	Mem_curr=0
367
368	if ! grep -q '\[always\]' /sys/kernel/mm/transparent_hugepage/enabled; then
369		tst_res TCONF "THP is not supported/enabled"
370		return
371	fi
372
373	COUNTER=1
374	for node in $nodes_list; do
375
376		if [ $COUNTER -eq $total_nodes ]; then   #wrap up for last node
377			Preferred_node=$(echo $nodes_list | cut -d ' ' -f 1)
378		else
379			# always next node is preferred node
380			Preferred_node=$(echo $nodes_list | cut -d ' ' -f $((COUNTER+1)))
381		fi
382
383		numactl --cpunodebind=$node --preferred=$Preferred_node support_numa alloc_2HPSZ_THP &
384		pid=$!
385
386		TST_RETRY_FUNC "check_for_support_numa $pid" 0
387
388		Mem_curr=$(echo "$(extract_numastat_p $pid $Preferred_node) * 1024" |bc)
389		if [ $(echo "$Mem_curr < $HPAGE_SIZE * 2" |bc ) -eq 1 ]; then
390			tst_res TFAIL \
391				"NUMA memory allocated in node$Preferred_node is less than expected"
392			kill -CONT $pid >/dev/null 2>&1
393			return
394		fi
395
396		COUNTER=$((COUNTER+1))
397		kill -CONT $pid >/dev/null 2>&1
398	done
399
400	tst_res TPASS "NUMA preferred node policy verified with THP enabled"
401}
402
403tst_run
404