1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2020 Intel Corporation 4# All rights reserved. 5# 6testdir=$(readlink -f "$(dirname "$0")") 7rootdir=$(readlink -f "$testdir/../../") 8source "$testdir/common.sh" 9 10declare -a nodes_sys=() 11 12declare -i default_hugepages=0 13declare -i no_nodes=0 14declare -i nr_hugepages=0 15 16default_hugepages=$(get_meminfo Hugepagesize) 17default_huge_nr=/sys/kernel/mm/hugepages/hugepages-${default_hugepages}kB/nr_hugepages 18global_huge_nr=/proc/sys/vm/nr_hugepages 19 20# Make sure environment doesn't affect the tests 21unset -v HUGEMEM 22unset -v HUGENODE 23unset -v NRHUGE 24 25get_nodes() { 26 local node 27 28 for node in /sys/devices/system/node/node+([0-9]); do 29 nodes_sys[${node##*node}]=$(< "$node/hugepages/hugepages-${default_hugepages}kB/nr_hugepages") 30 done 31 no_nodes=${#nodes_sys[@]} 32 ((no_nodes > 0)) 33} 34 35clear_hp() { 36 local node hp 37 38 for node in "${!nodes_sys[@]}"; do 39 for hp in "/sys/devices/system/node/node$node/hugepages/hugepages-"*; do 40 echo 0 > "$hp/nr_hugepages" 41 done 42 done 43 44 export CLEAR_HUGE=yes 45} 46 47get_test_nr_hugepages() { 48 local size=$1 # kB 49 if (($# > 1)); then 50 shift 51 local node_ids=("$@") 52 fi 53 54 ((size >= default_hugepages)) 55 56 nr_hugepages=$(((size + default_hugepages - 1) / default_hugepages)) 57 get_test_nr_hugepages_per_node "${node_ids[@]}" 58} 59 60get_test_nr_hugepages_per_node() { 61 local user_nodes=("$@") 62 63 local _nr_hugepages=$nr_hugepages 64 local _no_nodes=$no_nodes 65 66 local -g nodes_test=() 67 68 if ((${#user_nodes[@]} > 0)); then 69 for _no_nodes in "${user_nodes[@]}"; do 70 nodes_test[_no_nodes]=$nr_hugepages 71 done 72 return 0 73 elif ((${#nodes_hp[@]} > 0)); then 74 for _no_nodes in "${!nodes_hp[@]}"; do 75 nodes_test[_no_nodes]=${nodes_hp[_no_nodes]} 76 done 77 return 0 78 fi 79 80 while ((_no_nodes > 0)); do 81 nodes_test[_no_nodes - 1]=$((_nr_hugepages / _no_nodes)) 82 : $((_nr_hugepages -= nodes_test[_no_nodes - 1])) 83 : $((--_no_nodes)) 84 done 85} 86 87verify_nr_hugepages() { 88 local node 89 local sorted_t 90 local sorted_s 91 local surp 92 local resv 93 local anon 94 95 if [[ $(< /sys/kernel/mm/transparent_hugepage/enabled) != *"[never]"* ]]; then 96 anon=$(get_meminfo AnonHugePages) 97 fi 98 surp=$(get_meminfo HugePages_Surp) 99 resv=$(get_meminfo HugePages_Rsvd) 100 101 echo "nr_hugepages=$nr_hugepages" 102 echo "resv_hugepages=$resv" 103 echo "surplus_hugepages=$surp" 104 echo "anon_hugepages=${anon:-disabled}" 105 106 (($(< "$default_huge_nr") == nr_hugepages + surp + resv)) 107 # This knob doesn't account for the surp, resv hugepages 108 (($(< "$global_huge_nr") == nr_hugepages)) 109 (($(get_meminfo HugePages_Total) == nr_hugepages + surp + resv)) 110 111 get_nodes 112 113 # Take global resv and per-node surplus hugepages into account 114 for node in "${!nodes_test[@]}"; do 115 ((nodes_test[node] += resv)) 116 ((nodes_test[node] += $(get_meminfo HugePages_Surp "$node"))) 117 done 118 119 # There's no obvious way of determining which NUMA node is going to end 120 # up with an odd number of hugepages in case such number was actually 121 # allocated by the kernel. Considering that, let's simply check if our 122 # expectation is met by sorting and comparing it with nr of hugepages that 123 # was actually allocated on each node. 124 125 for node in "${!nodes_test[@]}"; do 126 sorted_t[nodes_test[node]]=1 sorted_s[nodes_sys[node]]=1 127 echo "node$node=${nodes_sys[node]} expecting ${nodes_test[node]}" 128 done 129 [[ ${!sorted_s[*]} == "${!sorted_t[*]}" ]] 130} 131 132# Test cases 133single_node_setup() { 134 # HUGEMEM (2G) alloc on node0 135 get_test_nr_hugepages $((2048 * 1024)) 0 136 NRHUGE=$nr_hugepages HUGENODE=0 setup output 137 verify_nr_hugepages 138} 139 140even_2G_alloc() { 141 # 2G alloc spread across N nodes 142 get_test_nr_hugepages $((2048 * 1024)) 143 NRHUGE=$nr_hugepages setup output 144 verify_nr_hugepages 145} 146 147odd_alloc() { 148 # Odd 2049MB alloc across N nodes 149 get_test_nr_hugepages $((2049 * 1024)) 150 HUGEMEM=2049 setup output 151 verify_nr_hugepages 152} 153 154custom_alloc() { 155 # Custom alloc: node0 == 1GB [node1 == 2 GB] 156 157 local IFS="," 158 159 local node 160 local nodes_hp=() 161 162 local nr_hugepages=0 _nr_hugepages=0 163 164 get_test_nr_hugepages $((1024 * 1024)) 165 nodes_hp[0]=$nr_hugepages 166 if ((${#nodes_sys[@]} > 1)); then 167 get_test_nr_hugepages $((2048 * 1024)) 168 nodes_hp[1]=$nr_hugepages 169 fi 170 171 for node in "${!nodes_hp[@]}"; do 172 HUGENODE+=("nodes_hp[$node]=${nodes_hp[node]}") 173 ((_nr_hugepages += nodes_hp[node])) 174 done 175 176 get_test_nr_hugepages_per_node 177 HUGENODE="${HUGENODE[*]}" setup output 178 nr_hugepages=$_nr_hugepages verify_nr_hugepages 179} 180 181no_shrink_alloc() { 182 # HUGEMEM (2G) alloc on node0 183 # attempt to shrink by half: 2G should remain 184 185 get_test_nr_hugepages $((2048 * 1024)) 0 186 187 # Verify the default first 188 NRHUGE=$nr_hugepages HUGENODE=0 setup output 189 verify_nr_hugepages 190 191 # Now attempt to shrink the hp number 192 CLEAR_HUGE=no NRHUGE=$((nr_hugepages / 2)) HUGENODE=0 setup output 193 # 2G should remain 194 verify_nr_hugepages 195} 196 197get_nodes 198clear_hp 199 200run_test "single_node_setup" single_node_setup 201run_test "even_2G_alloc" even_2G_alloc 202run_test "odd_alloc" odd_alloc 203run_test "custom_alloc" custom_alloc 204run_test "no_shrink_alloc" no_shrink_alloc 205 206clear_hp 207