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