xref: /spdk/test/setup/hugepages.sh (revision 0070858e33ec0937e93e68b06a7f170b02a352b6)
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