xref: /spdk/scripts/perf/vhost/conf-generator (revision dfb2950fd5b13ba0a2a2b533e3e534202a89de74)
1c1e9ed6dSMichal Berger#!/usr/bin/env bash
2c1e9ed6dSMichal Berger#  SPDX-License-Identifier: BSD-3-Clause
3c1e9ed6dSMichal Berger#  Copyright (C) 2022 Intel Corporation.
4c1e9ed6dSMichal Berger#  All rights reserved.
5c1e9ed6dSMichal Berger
6c1e9ed6dSMichal Bergercurdir=$(readlink -f "$(dirname "$0")")
7c1e9ed6dSMichal Bergerrootdir=$(readlink -f "$curdir/../../../")
8c1e9ed6dSMichal Berger
948945e3dSMichal Bergershopt -s nullglob extglob
1048945e3dSMichal Berger
11c1e9ed6dSMichal Bergersource "$rootdir/scripts/common.sh"
12c1e9ed6dSMichal Bergersource "$rootdir/test/scheduler/common.sh"
13c1e9ed6dSMichal Berger
14c1e9ed6dSMichal Bergerget_auto_cfg() {
15cca7c14aSMichal Berger	local vm_cpus vm_node vm vms
16c1e9ed6dSMichal Berger	local cpu node nodes_idxs node_idx
17c1e9ed6dSMichal Berger	local nvmes nvme nvme_idx nvme_diff nvmes_per_node
18c1e9ed6dSMichal Berger	local vm_diff aligned_number_of_vms=0
19c1e9ed6dSMichal Berger	local diff iter
20c1e9ed6dSMichal Berger
21c1e9ed6dSMichal Berger	local -g auto_cpu_map=() auto_disk_map=() spdk=()
22c1e9ed6dSMichal Berger
23c1e9ed6dSMichal Berger	map_cpus
24c1e9ed6dSMichal Berger	get_nvme_numa_map
25c1e9ed6dSMichal Berger
26c1e9ed6dSMichal Berger	nodes_idxs=("${!nodes[@]}")
27c1e9ed6dSMichal Berger
28c1e9ed6dSMichal Berger	# Construct initial NUMA-aware setup by pinning VM to given nvme's node. First run is meant
29c1e9ed6dSMichal Berger	# to pin enough number of VMs (as per vm_count) to match the number of available nvme ctrls.
30c1e9ed6dSMichal Berger	vm=0
31c1e9ed6dSMichal Berger	for node in "${nodes_idxs[@]}"; do
32c1e9ed6dSMichal Berger		nvmes=(${!nvme_numa_map[node]})
33c1e9ed6dSMichal Berger		for ((nvme_idx = 0; nvme_idx < ${#nvmes[@]} && vm < vm_count; vm++, nvme_idx++)); do
34c1e9ed6dSMichal Berger			eval "vm${vm}_node=$node"
35c1e9ed6dSMichal Berger		done
36c1e9ed6dSMichal Berger		nvmes_per_node[node]=${#nvmes[@]}
37c1e9ed6dSMichal Berger	done
38c1e9ed6dSMichal Berger
39c1e9ed6dSMichal Berger	vm_diff=$((vm_count - vm))
40c1e9ed6dSMichal Berger
41c1e9ed6dSMichal Berger	# Align extra number of VMs in case nvme ctrls are not distributed evenly across the existing
42c1e9ed6dSMichal Berger	# NUMA nodes.
43c1e9ed6dSMichal Berger	# FIXME: This is targeted for systems with only 2 NUMA nodes. Technically, kernel supports
44c1e9ed6dSMichal Berger	# more than that - it's possible to achieve setups with > 2 NUMA nodes under virtual env
45c1e9ed6dSMichal Berger	# for instance. Should this be of any concern?
46c1e9ed6dSMichal Berger	if ((nvmes_per_node[0] < nvmes_per_node[1])); then
47c1e9ed6dSMichal Berger		nvme_diff=$((nvmes_per_node[1] - nvmes_per_node[0]))
48c1e9ed6dSMichal Berger	elif ((nvmes_per_node[0] > nvmes_per_node[1])); then
49c1e9ed6dSMichal Berger		nvme_diff=$((nvmes_per_node[0] - nvmes_per_node[1]))
50c1e9ed6dSMichal Berger	else
51c1e9ed6dSMichal Berger		nvme_diff=0
52c1e9ed6dSMichal Berger	fi
53c1e9ed6dSMichal Berger
54c1e9ed6dSMichal Berger	diff=$((vm_diff + nvme_diff))
55c1e9ed6dSMichal Berger
56c1e9ed6dSMichal Berger	if ((diff % 2 == 0)); then
57c1e9ed6dSMichal Berger		aligned_number_of_vms=$((diff / ${#nodes_idxs[@]}))
58c1e9ed6dSMichal Berger	fi
59c1e9ed6dSMichal Berger
60c1e9ed6dSMichal Berger	# Second run distributes extra VMs across existing NUMA nodes. In case we can distribute even
61c1e9ed6dSMichal Berger	# number of extra VMs (as per vm_count) then simply assign them in bulk. In case there's an
62c1e9ed6dSMichal Berger	# odd number, do some simple rr balancing where we assign them one by one - first to node0,
63c1e9ed6dSMichal Berger	# second to node1, third to node0, etc.
64c1e9ed6dSMichal Berger	if ((aligned_number_of_vms)); then
65c1e9ed6dSMichal Berger		for node in "${nodes_idxs[@]}"; do
66c1e9ed6dSMichal Berger			for ((iter = 0; iter < aligned_number_of_vms && vm < vm_count; iter++, vm++)); do
67c1e9ed6dSMichal Berger				eval "vm${vm}_node=$node"
68c1e9ed6dSMichal Berger			done
69c1e9ed6dSMichal Berger		done
70c1e9ed6dSMichal Berger	else
71c1e9ed6dSMichal Berger		while ((vm < vm_count)); do
72c1e9ed6dSMichal Berger			for node in "${nodes_idxs[@]}"; do
73c1e9ed6dSMichal Berger				eval "vm${vm}_node=$node"
74c1e9ed6dSMichal Berger				((++vm))
75c1e9ed6dSMichal Berger			done
76c1e9ed6dSMichal Berger		done
77c1e9ed6dSMichal Berger	fi
78c1e9ed6dSMichal Berger
79c1e9ed6dSMichal Berger	local -g vm_numa_map=()
80c1e9ed6dSMichal Berger	for ((vm = 0; vm < vm_count; vm++)); do
81c1e9ed6dSMichal Berger		# Load balance the cpus across available numa nodes based on the pinning
82c1e9ed6dSMichal Berger		# done prior. If there are no cpus left under selected node, iterate over
83c1e9ed6dSMichal Berger		# all available nodes. If no cpus are left, fail. We don't allow to mix
84c1e9ed6dSMichal Berger		# cpus from different nodes for the sake of the performance.
85c1e9ed6dSMichal Berger		node_idx=0 node_idx_perc=0
86b86184c5SMichal Berger		eval "vm_node=\${VM${vm}_NODE:-\$vm${vm}_node}"
87c1e9ed6dSMichal Berger
88c1e9ed6dSMichal Berger		local -n node_cpus=node_${vm_node}_cpu
89c1e9ed6dSMichal Berger		local -n vm_nodes=node_${vm_node}_vm
90c1e9ed6dSMichal Berger
91c1e9ed6dSMichal Berger		vm_numa_map[vm_node]="node_${vm_node}_vm[@]"
92c1e9ed6dSMichal Berger
93c1e9ed6dSMichal Berger		while ((${#node_cpus[@]} < vm_cpu_num && node_idx < ${#nodes_idxs[@]})); do
94c1e9ed6dSMichal Berger			vm_node=${nodes_idxs[node_idx]}
95c1e9ed6dSMichal Berger			local -n node_cpus=node_${nodes_idxs[node_idx++]}_cpu
96c1e9ed6dSMichal Berger		done
97c1e9ed6dSMichal Berger
98c1e9ed6dSMichal Berger		if ((${#node_cpus[@]} < vm_cpu_num)); then
99c1e9ed6dSMichal Berger			printf 'Not enough CPUs available for VM %u (CPUs: %u, Nodes: %u, CPUs per VM: %u)\n' \
100c1e9ed6dSMichal Berger				"$vm" "${#cpus[@]}" "${#nodes_idxs[@]}" "$vm_cpu_num" >&2
101c1e9ed6dSMichal Berger			return 1
102c1e9ed6dSMichal Berger		fi
103c1e9ed6dSMichal Berger
104c1e9ed6dSMichal Berger		# Normalize indexes
105c1e9ed6dSMichal Berger		node_cpus=("${node_cpus[@]}")
106c1e9ed6dSMichal Berger
107c1e9ed6dSMichal Berger		vm_cpus=("${node_cpus[@]::vm_cpu_num}")
108c1e9ed6dSMichal Berger		node_cpus=("${node_cpus[@]:vm_cpu_num}")
109c1e9ed6dSMichal Berger
110c1e9ed6dSMichal Berger		auto_cpu_map+=("$(
111c1e9ed6dSMichal Berger			cat <<- CPU_VM
112c1e9ed6dSMichal Berger				VM_${vm}_qemu_mask=$(
113c1e9ed6dSMichal Berger					IFS=","
114c1e9ed6dSMichal Berger					echo "${vm_cpus[*]}"
115c1e9ed6dSMichal Berger				)
116c1e9ed6dSMichal Berger				VM_${vm}_qemu_numa_node=$vm_node
117c1e9ed6dSMichal Berger			CPU_VM
118c1e9ed6dSMichal Berger		)")
119c1e9ed6dSMichal Berger
120c1e9ed6dSMichal Berger		# Save map of each VM->NUMA node to be able to construct a disk map in later steps.
121c1e9ed6dSMichal Berger		vm_nodes+=("$vm")
122c1e9ed6dSMichal Berger	done
123c1e9ed6dSMichal Berger
124c1e9ed6dSMichal Berger	# auto_cpu_map is ready, all requested VMs should be balanced across all NUMA nodes
125c1e9ed6dSMichal Berger	# making sure each nvme drive will be bound to at least 1 VM placed on the
126c1e9ed6dSMichal Berger	# corresponding NUMA node. Now, construct disk_cfg and assign VMs, with proper
127c1e9ed6dSMichal Berger	# split value, to each nvme - extra VMs will be added to nvme drives in their
128c1e9ed6dSMichal Berger	# bus order.
129c1e9ed6dSMichal Berger	local -A nvme_vm_map=()
130cca7c14aSMichal Berger	local iter nvmes_no=0 vms_no=0 _vms_per_nvme
131c1e9ed6dSMichal Berger	for node in "${nodes_idxs[@]}"; do
132c1e9ed6dSMichal Berger		if [[ ! -v nvme_numa_map[node] ]]; then
133c1e9ed6dSMichal Berger			# There are no drives available on that node, skip it
134c1e9ed6dSMichal Berger			continue
135c1e9ed6dSMichal Berger		fi
136c1e9ed6dSMichal Berger		nvmes=(${!nvme_numa_map[node]}) nvmes_no=${#nvmes[@]}
137c1e9ed6dSMichal Berger		vms=(${!vm_numa_map[node]}) vms_no=${#vms[@]}
138c1e9ed6dSMichal Berger		for ((iter = 0; iter <= (vms_no - nvmes_no <= 0 ? 1 : vms_no - nvmes_no); iter++)); do
139c1e9ed6dSMichal Berger			for nvme in "${nvmes[@]}"; do
140cca7c14aSMichal Berger				_vms_per_nvme=0
141c1e9ed6dSMichal Berger				if ((${#vms[@]} == 0)); then
142c1e9ed6dSMichal Berger					# No VMs on given node or they have been exhausted - skip all remaining drives.
143c1e9ed6dSMichal Berger					continue 3
144c1e9ed6dSMichal Berger				fi
145c1e9ed6dSMichal Berger				nvme_vm_map["$nvme"]="_${nvme//[:.]/_}_[@]"
146c1e9ed6dSMichal Berger				local -n nvme_vms=_${nvme//[:.]/_}_
147cca7c14aSMichal Berger				while ((++_vms_per_nvme <= vms_per_nvme)); do
148c1e9ed6dSMichal Berger					nvme_vms+=("${vms[0]}") vms=("${vms[@]:1}")
149c1e9ed6dSMichal Berger				done
150c1e9ed6dSMichal Berger			done
151c1e9ed6dSMichal Berger		done
152cca7c14aSMichal Berger	done
153c1e9ed6dSMichal Berger
154c1e9ed6dSMichal Berger	local sorted_nvmes=()
155c1e9ed6dSMichal Berger	sorted_nvmes=($(printf '%s\n' "${!nvme_vm_map[@]}" | sort))
156c1e9ed6dSMichal Berger	for nvme in "${!sorted_nvmes[@]}"; do
157c1e9ed6dSMichal Berger		vms=(${!nvme_vm_map["${sorted_nvmes[nvme]}"]})
158c1e9ed6dSMichal Berger		auto_disk_map+=("${sorted_nvmes[nvme]},Nvme$((nvme++)),${#vms[*]},${vms[*]}")
159c1e9ed6dSMichal Berger	done
160c1e9ed6dSMichal Berger
161c1e9ed6dSMichal Berger	get_spdk_cpus || return 1
162c1e9ed6dSMichal Berger
163c1e9ed6dSMichal Berger	auto_cpu_map+=("vhost_0_reactor_mask=[$(
164c1e9ed6dSMichal Berger		IFS=","
165c1e9ed6dSMichal Berger		echo "${spdk[*]}"
166c1e9ed6dSMichal Berger	)]")
167*161ef3f5SMichal Berger	auto_cpu_map+=("vhost_0_main_core=${spdk[0]}")
168c1e9ed6dSMichal Berger}
169c1e9ed6dSMichal Berger
170c1e9ed6dSMichal Bergerget_nvme_numa_map() {
171c1e9ed6dSMichal Berger	local nvmes nvme node
172c1e9ed6dSMichal Berger	local -g nvme_numa_map=()
173c1e9ed6dSMichal Berger
174c1e9ed6dSMichal Berger	cache_pci_bus
175c1e9ed6dSMichal Berger
176c1e9ed6dSMichal Berger	for nvme in ${pci_bus_cache[0x010802]}; do
177c1e9ed6dSMichal Berger		node=$(< "/sys/bus/pci/devices/$nvme/numa_node")
178c1e9ed6dSMichal Berger		nvme_numa_map[node]="node_${node}_nvme[@]"
179c1e9ed6dSMichal Berger		local -n node_nvmes=node_${node}_nvme
180c1e9ed6dSMichal Berger		node_nvmes+=("$nvme")
181c1e9ed6dSMichal Berger	done
182c1e9ed6dSMichal Berger}
183c1e9ed6dSMichal Berger
184c1e9ed6dSMichal Bergerget_spdk_cpus() {
185c1e9ed6dSMichal Berger	local -g spdk=()
186c1e9ed6dSMichal Berger	local node vms perc
187c1e9ed6dSMichal Berger	local cpus_per_node cpus_exhausted=() cpus_remained=()
188c1e9ed6dSMichal Berger
189c1e9ed6dSMichal Berger	if [[ -z $spdk_cpu_num ]]; then
190c1e9ed6dSMichal Berger		spdk=(0)
191c1e9ed6dSMichal Berger		return 0
192c1e9ed6dSMichal Berger	fi
193c1e9ed6dSMichal Berger
194c1e9ed6dSMichal Berger	if [[ -n $spdk_cpu_list ]]; then
195c1e9ed6dSMichal Berger		spdk=($(parse_cpu_list <(echo "$spdk_cpu_list")))
196c1e9ed6dSMichal Berger		return 0
197c1e9ed6dSMichal Berger	fi
198c1e9ed6dSMichal Berger
199c1e9ed6dSMichal Berger	# Start allocating from NUMA node with greater number of pinned VMs.
200c1e9ed6dSMichal Berger	node_sort=($(for node in "${!vm_numa_map[@]}"; do
201c1e9ed6dSMichal Berger		vms=(${!vm_numa_map[node]})
202c1e9ed6dSMichal Berger		echo "${#vms[@]}:$node"
203c1e9ed6dSMichal Berger	done | sort -rn))
204c1e9ed6dSMichal Berger
205c1e9ed6dSMichal Berger	for _node in "${node_sort[@]}"; do
206c1e9ed6dSMichal Berger		node=${_node#*:} vms=${_node%:*}
207c1e9ed6dSMichal Berger		local -n node_all_cpus=node_${node}_cpu
208c1e9ed6dSMichal Berger		perc=$((vms * 100 / vm_count))
209c1e9ed6dSMichal Berger		cpus_per_node=$((spdk_cpu_num * perc / 100))
210c1e9ed6dSMichal Berger		cpus_per_node=$((cpus_per_node == 0 ? 1 : cpus_per_node))
211c1e9ed6dSMichal Berger
212c1e9ed6dSMichal Berger		if ((${#node_all_cpus[@]} == 0)); then
213c1e9ed6dSMichal Berger			printf 'No CPUs left to allocate for SPDK on node%u. Need %u CPUs\n' \
214c1e9ed6dSMichal Berger				"$node" "$cpus_per_node" >&2
215c1e9ed6dSMichal Berger
216c1e9ed6dSMichal Berger			cpus_exhausted[node]=1
217c1e9ed6dSMichal Berger			continue
218c1e9ed6dSMichal Berger		fi
219c1e9ed6dSMichal Berger		if ((${#node_all_cpus[@]} < cpus_per_node)); then
220c1e9ed6dSMichal Berger			printf 'Not enough CPUs to allocate for SPDK on node%u. Need %u CPUs, getting %u\n' \
221c1e9ed6dSMichal Berger				"$node" "$cpus_per_node" "${#node_all_cpus[@]}" >&2
222c1e9ed6dSMichal Berger			cpus_per_node=${#node_all_cpus[@]}
223c1e9ed6dSMichal Berger			cpus_exhauseted[node]=1
224c1e9ed6dSMichal Berger		fi
225c1e9ed6dSMichal Berger
226c1e9ed6dSMichal Berger		spdk+=("${node_all_cpus[@]::cpus_per_node}")
227c1e9ed6dSMichal Berger		node_all_cpus=("${node_all_cpus[@]:cpus_per_node}")
228c1e9ed6dSMichal Berger		cpus_remained+=("${node_all_cpus[@]}")
229c1e9ed6dSMichal Berger	done
230c1e9ed6dSMichal Berger
231c1e9ed6dSMichal Berger	# If we didn't allocate the entire number of requested cpus in the initial run,
232c1e9ed6dSMichal Berger	# adjust it by adding the remaining portion from the node having greater number
233c1e9ed6dSMichal Berger	# of pinned VMs.
234c1e9ed6dSMichal Berger	if ((${#spdk[@]} < spdk_cpu_num)); then
235c1e9ed6dSMichal Berger		if [[ -n $ALIGN_FROM_ALL_NODES ]] && ((${#cpus_remained[@]} > 0)); then
236c1e9ed6dSMichal Berger			printf 'Trying to get extra CPUs from all nodes\n'
237c1e9ed6dSMichal Berger			local -n node_all_cpus=cpus_remained
238c1e9ed6dSMichal Berger		else
239c1e9ed6dSMichal Berger			node=${node_sort[0]#*:}
240c1e9ed6dSMichal Berger			printf 'Trying to get extra CPUs from the dominant node%u to align: %u < %u\n' \
241c1e9ed6dSMichal Berger				"$node" "${#spdk[@]}" "$spdk_cpu_num"
242c1e9ed6dSMichal Berger			if ((cpus_exhausted[node])); then
243c1e9ed6dSMichal Berger				printf 'No CPUs available on node%u\n' "$node"
244c1e9ed6dSMichal Berger			else
245c1e9ed6dSMichal Berger				local -n node_all_cpus=node_${node}_cpu
246c1e9ed6dSMichal Berger			fi
247c1e9ed6dSMichal Berger		fi
248c1e9ed6dSMichal Berger		spdk+=("${node_all_cpus[@]::spdk_cpu_num-${#spdk[@]}}")
249c1e9ed6dSMichal Berger	fi >&2
250c1e9ed6dSMichal Berger	if ((${#spdk[@]} != spdk_cpu_num)); then
251c1e9ed6dSMichal Berger		printf 'Different number of SPDK CPUs allocated to meet the requirements: requested %u, got %u\n' \
252c1e9ed6dSMichal Berger			"$spdk_cpu_num" "${#spdk[@]}"
253c1e9ed6dSMichal Berger	else
254c1e9ed6dSMichal Berger		printf 'Requested number of SPDK CPUs allocated: %u\n' "$spdk_cpu_num"
255c1e9ed6dSMichal Berger	fi >&2
256c1e9ed6dSMichal Berger}
257c1e9ed6dSMichal Berger
258c1e9ed6dSMichal Berger_p_disk_map() {
259c1e9ed6dSMichal Berger	((${#auto_disk_map[@]} > 0)) || return 0
260c1e9ed6dSMichal Berger	printf '%s\n' "${auto_disk_map[@]}"
261c1e9ed6dSMichal Berger}
262c1e9ed6dSMichal Berger
263c1e9ed6dSMichal Berger_p_cpu_map() {
264c1e9ed6dSMichal Berger	((${#auto_cpu_map[@]} > 0)) || return 0
265c1e9ed6dSMichal Berger	printf '%s\n' "${auto_cpu_map[@]}"
266c1e9ed6dSMichal Berger}
267c1e9ed6dSMichal Berger
268c1e9ed6dSMichal Bergerp_disk_map() {
269c1e9ed6dSMichal Berger	cat <<- DISK_MAP
270c1e9ed6dSMichal Berger		# Generated automatically by ${0##*/}
271c1e9ed6dSMichal Berger		# NVMe Drives: ${#auto_disk_map[@]} VM count: $vm_count
272c1e9ed6dSMichal Berger		$(_p_disk_map)
273c1e9ed6dSMichal Berger	DISK_MAP
274c1e9ed6dSMichal Berger}
275c1e9ed6dSMichal Berger
276c1e9ed6dSMichal Bergerp_vms_in_node() {
277c1e9ed6dSMichal Berger	((${#vm_numa_map[@]} > 0)) || return 0
278c1e9ed6dSMichal Berger
279c1e9ed6dSMichal Berger	local node vms
280c1e9ed6dSMichal Berger	for node in "${!vm_numa_map[@]}"; do
281c1e9ed6dSMichal Berger		vms=(${!vm_numa_map[node]})
282c1e9ed6dSMichal Berger		echo "Node$node: ${#vms[@]} VMs"
283c1e9ed6dSMichal Berger	done
284c1e9ed6dSMichal Berger}
285c1e9ed6dSMichal Berger
286c1e9ed6dSMichal Bergerp_cpu_map() {
287c1e9ed6dSMichal Berger	local node_stats
288c1e9ed6dSMichal Berger
289c1e9ed6dSMichal Berger	mapfile -t node_stats < <(p_vms_in_node)
290c1e9ed6dSMichal Berger	cat <<- CPU_MAP
291c1e9ed6dSMichal Berger		# Generated automatically by ${0##*/}
292c1e9ed6dSMichal Berger		# VM NUMA Nodes: ${#vm_numa_map[@]} VM count: $vm_count CPU Per VM: $vm_cpu_num SPDK CPU count: ${#spdk[@]}
293c1e9ed6dSMichal Berger		$(printf '#  - %s\n' "${node_stats[@]}")
294c1e9ed6dSMichal Berger		$(_p_cpu_map)
295c1e9ed6dSMichal Berger	CPU_MAP
296c1e9ed6dSMichal Berger}
297c1e9ed6dSMichal Berger
298c1e9ed6dSMichal Bergerp_all() {
299c1e9ed6dSMichal Berger	p_disk_map
300c1e9ed6dSMichal Berger	printf '\n'
301c1e9ed6dSMichal Berger	p_cpu_map
302c1e9ed6dSMichal Berger}
303c1e9ed6dSMichal Berger
304c1e9ed6dSMichal Bergerfetch_env() {
305c1e9ed6dSMichal Berger	spdk_cpu_num=${spdk_cpu_num:-1}
306c1e9ed6dSMichal Berger	vm_count=${vm_count:-1}
307c1e9ed6dSMichal Berger	vm_cpu_num=${vm_cpu_num:-1}
308cca7c14aSMichal Berger	vms_per_nvme=${vms_per_nvme:-1}
309c1e9ed6dSMichal Berger
310c1e9ed6dSMichal Berger	# Normalize
311c1e9ed6dSMichal Berger	spdk_cpu_num=$((spdk_cpu_num <= 0 ? 1 : spdk_cpu_num))
312c1e9ed6dSMichal Berger	vm_count=$((vm_count <= 0 ? 1 : vm_count))
313c1e9ed6dSMichal Berger	vm_cpu_num=$((vm_cpu_num <= 0 ? 1 : vm_cpu_num))
314cca7c14aSMichal Berger	vms_per_nvme=$((vms_per_nvme <= 0 ? 1 : vms_per_nvme))
315c1e9ed6dSMichal Berger
316c1e9ed6dSMichal Berger	cpu_out=${cpu_out:-"$PWD/auto-cpu.conf"}
317c1e9ed6dSMichal Berger	disk_out=${disk_out:-"$PWD/auto-disk.conf"}
318c1e9ed6dSMichal Berger}
319c1e9ed6dSMichal Berger
320c1e9ed6dSMichal Bergerhelp() {
321c1e9ed6dSMichal Berger	cat <<- HELP
322c1e9ed6dSMichal Berger		${0##*/}: [-p all|cpu|disk -s]
323c1e9ed6dSMichal Berger
324c1e9ed6dSMichal Berger		Configuration is generated based on system's cpu and nvme topology. Parameters
325c1e9ed6dSMichal Berger		taken directly from the environment:
326c1e9ed6dSMichal Berger
327c1e9ed6dSMichal Berger		spdk_cpu_list - list of CPUs to assign to a SPDK app
328c1e9ed6dSMichal Berger		spdk_cpu_num  - number of CPUs to use across all NUMA nodes
329c1e9ed6dSMichal Berger		                (spdk_cpu_list takes priority, default: 1)
330c1e9ed6dSMichal Berger		vm_count      - number of VMs to prepare the configuration for
331c1e9ed6dSMichal Berger		                (default: 1)
332c1e9ed6dSMichal Berger		vm_cpu_num    - number of CPUs to assign per VM (default: 1)
333cca7c14aSMichal Berger		vms_per_nvme  - Number of VMs to pin to a single nvme (default: 1)
334c1e9ed6dSMichal Berger
335c1e9ed6dSMichal Berger		Override parameters:
336b86184c5SMichal Berger		VM[N]_NODE    - overrides selected NUMA node for VM N - by default,
337c1e9ed6dSMichal Berger		                this is allocated up to number of nvme drives
338c1e9ed6dSMichal Berger		cpu_out       - with -s, points at location where to save cpu conf
339c1e9ed6dSMichal Berger		disk_out      - with -s, points at location where to save disk conf
340c1e9ed6dSMichal Berger
341c1e9ed6dSMichal Berger		Note: VMs are pinned to nvme drives based on their NUMA location.
342c1e9ed6dSMichal Berger
343c1e9ed6dSMichal Berger		Example:
344c1e9ed6dSMichal Berger		# Allocate 6 cpus from node1 for SPDK. Configure 24 VMs, 2 CPUs per VM
345c1e9ed6dSMichal Berger		$ export spdk_cpu_num=6 vm_count=24 vm_cpu_num=2
346c1e9ed6dSMichal Berger		$ ${0##*/} -p all
347c1e9ed6dSMichal Berger	HELP
348c1e9ed6dSMichal Berger}
349c1e9ed6dSMichal Berger
350c1e9ed6dSMichal Bergerprint=""
351c1e9ed6dSMichal Bergersave=no
352c1e9ed6dSMichal Berger
353c1e9ed6dSMichal Bergerfetch_env
354c1e9ed6dSMichal Berger
355c1e9ed6dSMichal Bergerwhile getopts :hsp: arg; do
356c1e9ed6dSMichal Berger	case "$arg" in
357c1e9ed6dSMichal Berger		h)
358c1e9ed6dSMichal Berger			help
359c1e9ed6dSMichal Berger			exit 0
360c1e9ed6dSMichal Berger			;;
361c1e9ed6dSMichal Berger		p) print=$OPTARG ;;
362c1e9ed6dSMichal Berger		s) save=yes ;;
363c1e9ed6dSMichal Berger		*) ;;
364c1e9ed6dSMichal Berger	esac
365c1e9ed6dSMichal Bergerdone
366c1e9ed6dSMichal Berger
367c1e9ed6dSMichal Bergerget_auto_cfg || exit 1
368c1e9ed6dSMichal Berger
369c1e9ed6dSMichal Bergercase "$print" in
370c1e9ed6dSMichal Berger	all) p_all ;;
371c1e9ed6dSMichal Berger	cpu) p_cpu_map ;;
372c1e9ed6dSMichal Berger	disk) p_disk_map ;;
373c1e9ed6dSMichal Berger	*) ;;
374c1e9ed6dSMichal Bergeresac
375c1e9ed6dSMichal Berger
376c1e9ed6dSMichal Bergerif [[ $save == yes ]]; then
377c1e9ed6dSMichal Berger	p_cpu_map > "$cpu_out"
378c1e9ed6dSMichal Berger	p_disk_map > "$disk_out"
379c1e9ed6dSMichal Bergerfi
380