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