2020-11-27 08:30:26 +00:00
|
|
|
#!/usr/bin/env bash
|
2022-11-02 15:49:40 +00:00
|
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
# Copyright (C) 2020 Intel Corporation
|
|
|
|
# All rights reserved.
|
|
|
|
#
|
2020-11-27 08:30:26 +00:00
|
|
|
testdir=$(readlink -f "$(dirname "$0")")
|
|
|
|
rootdir=$(readlink -f "$testdir/../../")
|
|
|
|
source "$testdir/common.sh"
|
|
|
|
|
|
|
|
shopt -s extglob nullglob
|
|
|
|
|
|
|
|
declare -a nodes_sys=()
|
|
|
|
|
2021-11-25 01:40:59 +00:00
|
|
|
declare -i default_hugepages=0
|
2020-11-27 08:30:26 +00:00
|
|
|
declare -i no_nodes=0
|
|
|
|
declare -i nr_hugepages=0
|
|
|
|
|
2021-11-25 01:40:59 +00:00
|
|
|
default_hugepages=$(get_meminfo Hugepagesize)
|
|
|
|
default_huge_nr=/sys/kernel/mm/hugepages/hugepages-${default_hugepages}kB/nr_hugepages
|
2020-11-27 08:30:26 +00:00
|
|
|
global_huge_nr=/proc/sys/vm/nr_hugepages
|
|
|
|
|
2021-06-18 10:28:21 +00:00
|
|
|
# Make sure environment doesn't affect the tests
|
|
|
|
unset -v HUGE_EVEN_ALLOC
|
|
|
|
unset -v HUGEMEM
|
|
|
|
unset -v HUGENODE
|
|
|
|
unset -v NRHUGE
|
|
|
|
|
2020-11-27 08:30:26 +00:00
|
|
|
get_nodes() {
|
|
|
|
local node
|
|
|
|
|
|
|
|
for node in /sys/devices/system/node/node+([0-9]); do
|
2021-11-25 01:40:59 +00:00
|
|
|
nodes_sys[${node##*node}]=$(< "$node/hugepages/hugepages-${default_hugepages}kB/nr_hugepages")
|
2020-11-27 08:30:26 +00:00
|
|
|
done
|
|
|
|
no_nodes=${#nodes_sys[@]}
|
|
|
|
((no_nodes > 0))
|
|
|
|
}
|
|
|
|
|
|
|
|
clear_hp() {
|
|
|
|
local node hp
|
|
|
|
|
|
|
|
for node in "${!nodes_sys[@]}"; do
|
|
|
|
for hp in "/sys/devices/system/node/node$node/hugepages/hugepages-"*; do
|
|
|
|
echo 0 > "$hp/nr_hugepages"
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
export CLEAR_HUGE=yes
|
|
|
|
}
|
|
|
|
|
|
|
|
get_test_nr_hugepages() {
|
|
|
|
local size=$1 # kB
|
|
|
|
if (($# > 1)); then
|
|
|
|
shift
|
|
|
|
local node_ids=("$@")
|
|
|
|
fi
|
|
|
|
|
2021-11-25 01:40:59 +00:00
|
|
|
((size >= default_hugepages))
|
2020-11-27 08:30:26 +00:00
|
|
|
|
2021-11-25 01:40:59 +00:00
|
|
|
nr_hugepages=$(((size + default_hugepages - 1) / default_hugepages))
|
2020-11-27 08:30:26 +00:00
|
|
|
get_test_nr_hugepages_per_node "${node_ids[@]}"
|
|
|
|
}
|
|
|
|
|
|
|
|
get_test_nr_hugepages_per_node() {
|
|
|
|
local user_nodes=("$@")
|
|
|
|
|
|
|
|
local _nr_hugepages=$nr_hugepages
|
|
|
|
local _no_nodes=$no_nodes
|
|
|
|
|
|
|
|
local -g nodes_test=()
|
|
|
|
|
|
|
|
if ((${#user_nodes[@]} > 0)); then
|
|
|
|
for _no_nodes in "${user_nodes[@]}"; do
|
|
|
|
nodes_test[_no_nodes]=$nr_hugepages
|
|
|
|
done
|
|
|
|
return 0
|
|
|
|
elif ((${#nodes_hp[@]} > 0)); then
|
|
|
|
for _no_nodes in "${!nodes_hp[@]}"; do
|
|
|
|
nodes_test[_no_nodes]=${nodes_hp[_no_nodes]}
|
|
|
|
done
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
|
|
|
while ((_no_nodes > 0)); do
|
|
|
|
nodes_test[_no_nodes - 1]=$((_nr_hugepages / _no_nodes))
|
|
|
|
: $((_nr_hugepages -= nodes_test[_no_nodes - 1]))
|
|
|
|
: $((--_no_nodes))
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
verify_nr_hugepages() {
|
|
|
|
local node
|
|
|
|
local sorted_t
|
|
|
|
local sorted_s
|
2022-08-02 10:26:26 +00:00
|
|
|
local surp
|
|
|
|
local resv
|
|
|
|
local anon
|
|
|
|
|
|
|
|
if [[ $(< /sys/kernel/mm/transparent_hugepage/enabled) != *"[never]"* ]]; then
|
|
|
|
anon=$(get_meminfo AnonHugePages)
|
|
|
|
fi
|
|
|
|
surp=$(get_meminfo HugePages_Surp)
|
|
|
|
resv=$(get_meminfo HugePages_Rsvd)
|
2020-11-27 08:30:26 +00:00
|
|
|
|
|
|
|
echo "nr_hugepages=$nr_hugepages"
|
2022-08-02 10:26:26 +00:00
|
|
|
echo "resv_hugepages=$resv"
|
|
|
|
echo "surplus_hugepages=$surp"
|
|
|
|
echo "anon_hugepages=${anon:-disabled}"
|
|
|
|
|
|
|
|
(($(< "$default_huge_nr") == nr_hugepages + surp + resv))
|
|
|
|
# This knob doesn't account for the surp, resv hugepages
|
2020-11-27 08:30:26 +00:00
|
|
|
(($(< "$global_huge_nr") == nr_hugepages))
|
2022-08-02 10:26:26 +00:00
|
|
|
(($(get_meminfo HugePages_Total) == nr_hugepages + surp + resv))
|
2020-11-27 08:30:26 +00:00
|
|
|
|
|
|
|
get_nodes
|
|
|
|
|
2022-08-02 10:26:26 +00:00
|
|
|
# Take global resv and per-node surplus hugepages into account
|
|
|
|
for node in "${!nodes_test[@]}"; do
|
|
|
|
((nodes_test[node] += resv))
|
|
|
|
((nodes_test[node] += $(get_meminfo HugePages_Surp "$node")))
|
|
|
|
done
|
|
|
|
|
2020-11-27 08:30:26 +00:00
|
|
|
# There's no obvious way of determining which NUMA node is going to end
|
|
|
|
# up with an odd number of hugepages in case such number was actually
|
|
|
|
# allocated by the kernel. Considering that, let's simply check if our
|
2021-11-25 01:40:59 +00:00
|
|
|
# expectation is met by sorting and comparing it with nr of hugepages that
|
2020-11-27 08:30:26 +00:00
|
|
|
# was actually allocated on each node.
|
|
|
|
|
|
|
|
for node in "${!nodes_test[@]}"; do
|
|
|
|
sorted_t[nodes_test[node]]=1 sorted_s[nodes_sys[node]]=1
|
2022-08-02 10:26:26 +00:00
|
|
|
echo "node$node=${nodes_sys[node]} expecting ${nodes_test[node]}"
|
2020-11-27 08:30:26 +00:00
|
|
|
done
|
|
|
|
[[ ${!sorted_s[*]} == "${!sorted_t[*]}" ]]
|
|
|
|
}
|
|
|
|
|
|
|
|
# Test cases
|
|
|
|
default_setup() {
|
2021-06-18 10:28:21 +00:00
|
|
|
# Default HUGEMEM (2G) alloc on node0
|
|
|
|
get_test_nr_hugepages $((2048 * 1024)) 0
|
2020-11-27 08:30:26 +00:00
|
|
|
setup
|
|
|
|
verify_nr_hugepages
|
|
|
|
}
|
|
|
|
|
|
|
|
per_node_2G_alloc() {
|
|
|
|
# 2G alloc per node, total N*2G pages
|
|
|
|
local IFS=","
|
|
|
|
|
|
|
|
get_test_nr_hugepages $((2048 * 1024)) "${!nodes_sys[@]}"
|
|
|
|
NRHUGE=$nr_hugepages HUGENODE="${!nodes_sys[*]}" setup
|
|
|
|
nr_hugepages=$((nr_hugepages * ${#nodes_sys[@]})) verify_nr_hugepages
|
|
|
|
}
|
|
|
|
|
|
|
|
even_2G_alloc() {
|
|
|
|
# 2G alloc spread across N nodes
|
|
|
|
get_test_nr_hugepages $((2048 * 1024))
|
|
|
|
NRHUGE=$nr_hugepages HUGE_EVEN_ALLOC=yes setup
|
|
|
|
verify_nr_hugepages
|
|
|
|
}
|
|
|
|
|
|
|
|
odd_alloc() {
|
|
|
|
# Odd 2049MB alloc across N nodes
|
|
|
|
get_test_nr_hugepages $((2049 * 1024))
|
|
|
|
HUGEMEM=2049 HUGE_EVEN_ALLOC=yes setup
|
|
|
|
verify_nr_hugepages
|
|
|
|
}
|
|
|
|
|
|
|
|
custom_alloc() {
|
2021-05-24 09:02:33 +00:00
|
|
|
# Custom alloc: node0 == 1GB [node1 == 2 GB]
|
2020-11-27 08:30:26 +00:00
|
|
|
|
|
|
|
local IFS=","
|
|
|
|
|
|
|
|
local node
|
|
|
|
local nodes_hp=()
|
|
|
|
|
2021-05-24 09:02:33 +00:00
|
|
|
local nr_hugepages=0 _nr_hugepages=0
|
2020-11-27 08:30:26 +00:00
|
|
|
|
2021-05-24 09:02:33 +00:00
|
|
|
get_test_nr_hugepages $((1024 * 1024))
|
|
|
|
nodes_hp[0]=$nr_hugepages
|
2020-11-27 08:30:26 +00:00
|
|
|
if ((${#nodes_sys[@]} > 1)); then
|
2021-05-24 09:02:33 +00:00
|
|
|
get_test_nr_hugepages $((2048 * 1024))
|
|
|
|
nodes_hp[1]=$nr_hugepages
|
2020-11-27 08:30:26 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
for node in "${!nodes_hp[@]}"; do
|
|
|
|
HUGENODE+=("nodes_hp[$node]=${nodes_hp[node]}")
|
2021-05-24 09:02:33 +00:00
|
|
|
((_nr_hugepages += nodes_hp[node]))
|
2020-11-27 08:30:26 +00:00
|
|
|
done
|
|
|
|
|
|
|
|
get_test_nr_hugepages_per_node
|
|
|
|
HUGENODE="${HUGENODE[*]}" setup
|
2021-05-24 09:02:33 +00:00
|
|
|
nr_hugepages=$_nr_hugepages verify_nr_hugepages
|
2020-11-27 08:30:26 +00:00
|
|
|
}
|
|
|
|
|
2022-10-11 07:27:39 +00:00
|
|
|
no_shrink_alloc() {
|
|
|
|
# Defalut HUGEMEM (2G) alloc on node0
|
|
|
|
# attempt to shrink by half: 2G should remain
|
|
|
|
|
|
|
|
get_test_nr_hugepages $((2048 * 1024)) 0
|
|
|
|
|
|
|
|
# Verify the default first
|
|
|
|
setup
|
|
|
|
verify_nr_hugepages
|
|
|
|
|
|
|
|
# Now attempt to shrink the hp number
|
|
|
|
CLEAR_HUGE=no NRHUGE=$((nr_hugepages / 2)) setup
|
|
|
|
# 2G should remain
|
|
|
|
verify_nr_hugepages
|
|
|
|
}
|
|
|
|
|
2020-11-27 08:30:26 +00:00
|
|
|
get_nodes
|
|
|
|
clear_hp
|
|
|
|
|
|
|
|
run_test "default_setup" default_setup
|
|
|
|
run_test "per_node_2G_alloc" per_node_2G_alloc
|
|
|
|
run_test "even_2G_alloc" even_2G_alloc
|
|
|
|
run_test "odd_alloc" odd_alloc
|
|
|
|
run_test "custom_alloc" custom_alloc
|
2022-10-11 07:27:39 +00:00
|
|
|
run_test "no_shrink_alloc" no_shrink_alloc
|
2020-11-27 08:30:26 +00:00
|
|
|
|
|
|
|
clear_hp
|