xref: /spdk/scripts/fio-wrapper (revision 99a43e75ed9ac3c87d23e3746173cf5a5a992544)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2021 Intel Corporation
4#  All rights reserved.
5
6rootdir=$(readlink -f "$(dirname "$0")/../")
7
8shopt -s nullglob extglob
9
10fio_config() {
11	local devs=("$@") dev
12
13	cat <<- FIO
14		[global]
15		thread=1
16		invalidate=1
17		rw=$testtype
18		time_based=1
19		runtime=$runtime
20		ioengine=libaio
21		direct=1
22		bs=$blocksize
23		iodepth=$iodepth
24		norandommap=$((verify == 1 ? 0 : 1))
25		numjobs=$numjobs
26		verify_dump=1
27		verify_backlog=512
28		verify_state_save=0
29	FIO
30
31	if ((verify == 1)); then
32		cat <<- FIO
33			do_verify=$verify
34			verify=crc32c-intel
35		FIO
36	fi
37
38	for dev in "${!devs[@]}"; do
39		cat <<- FIO
40			[job$dev]
41			filename=/dev/${devs[dev]}
42		FIO
43	done
44}
45
46run_fio() {
47	fio_config "$@" | fio -
48}
49
50get_iscsi() {
51	while read -r; do
52		[[ $REPLY =~ "Attached scsi disk "(sd[a-z]+) ]] && echo "${BASH_REMATCH[1]}"
53	done < <(iscsiadm -m session -P 3)
54}
55
56get_nvme() {
57	local blocks nvme nvme_sub
58	for nvme in /sys/block/nvme*; do
59		# Some kernels expose hidden fabrics devices ("nvmeXcXnX") under sysfs - skip them.
60		if (($(< "$nvme/hidden") == 1)); then
61			continue
62		fi
63		# Make sure we touch only the block devices which belong to bdev subsystem.
64		[[ $(< "$nvme/device/model") == "SPDK bdev Controller"* ]] || continue
65		blocks+=("${nvme##*/}")
66	done
67	printf '%s\n' "${blocks[@]}"
68}
69
70get_devices() {
71	local devs=("$@")
72
73	if ((${#devs[@]} == 0)); then
74		case "$protocol" in
75			iscsi) devs=($(get_iscsi)) ;;
76			nvmf) devs=($(get_nvme)) ;;
77			*) ;;
78		esac
79	fi
80	printf '%s\n' "${devs[@]}"
81}
82
83configure_devices() {
84	local devs=("$@") dev qd
85
86	if [[ -e $rootdir/scripts/sync_dev_uevents.sh ]]; then
87		"$rootdir/scripts/sync_dev_uevents.sh" block/disk "${devs[@]}"
88	fi > /dev/null
89
90	for dev in "${devs[@]}"; do
91		qd=128
92		# Disable all merge tries"
93		echo 2 > "/sys/block/$dev/queue/nomerges"
94		# FIXME: nr_requests already has its default value at 128. Also, when no
95		# scheduler is associated with the device this value cannot be changed
96		# and is automatically adjusted as well.
97		# echo 128 > "/sys/block/$dev/queue/nr_requests"
98		if [[ -e /sys/block/$dev/device/queue_depth ]]; then
99			# FIXME: Is this really needed though? Can't we use the default? This is not
100			# very deterministic as depending on the device we may end up with different
101			# qd in the range of 1-128.
102			while ((qd > 0)) && ! echo "$qd" > "/sys/block/$dev/device/queue_depth"; do
103				((--qd))
104			done 2> /dev/null
105			if ((qd == 0)); then
106				printf 'Failed to set queue_depth (%s)\n' "$dev"
107				return 1
108			fi
109			printf 'queue_depth set to %u (%s)\n' "$qd" "$dev"
110		else
111			printf 'Could not set queue depth (%s)\n' "$dev" >&2
112		fi
113		echo none > "/sys/block/$dev/queue/scheduler"
114	done
115}
116
117# Defaults
118blocksize=4096
119iodepth=1
120numjobs=1
121protocol="nvmf"
122runtime=1
123testtype="read"
124verify=0
125
126# Keep short args compatible with fio.py
127while getopts :i:d:n:p:r:t:v arg; do
128	case "$arg" in
129		i) blocksize=$OPTARG ;;
130		d) iodepth=$OPTARG ;;
131		n) numjobs=$OPTARG ;;
132		p) protocol=$OPTARG ;;
133		r) runtime=$OPTARG ;;
134		t) testtype=$OPTARG ;;
135		v) verify=1 ;;
136		*) ;;
137	esac
138done
139shift $((OPTIND - 1))
140
141devices=($(get_devices "$@"))
142if ((${#devices[@]} == 0)); then
143	printf '* No devices were found for the test, aborting\n' >&2
144	exit 1
145fi
146
147fio_config "${devices[@]}"
148configure_devices "${devices[@]}" && run_fio "${devices[@]}"
149