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