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