xref: /spdk/scripts/fio-wrapper (revision dbac81ecffced70062c2dc9306609b0a8593bd6f)
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		${rwmixread:+rwmixread=$rwmixread}
27	FIO
28
29	if ((verify == 1)); then
30		cat <<- FIO
31			verify_dump=1
32			verify_backlog=512
33			verify_state_save=0
34			do_verify=$verify
35			verify=crc32c-intel
36		FIO
37	fi
38
39	for dev in "${!devs[@]}"; do
40		cat <<- FIO
41			[job$dev]
42			filename=/dev/${devs[dev]}
43		FIO
44	done
45}
46
47run_fio() {
48	local output_args
49	if [[ -n "$output" ]]; then
50		output_args=("--group_reporting=1" "--output-format=json" "--output=$output")
51	fi
52	fio_config "$@" | fio "${output_args[@]}" -
53}
54
55get_iscsi() {
56	while read -r; do
57		[[ $REPLY =~ "Attached scsi disk "(sd[a-z]+) ]] && echo "${BASH_REMATCH[1]}"
58	done < <(iscsiadm -m session -P 3)
59}
60
61get_nvme() {
62	local blocks nvme nvme_sub
63	for nvme in /sys/block/nvme*; do
64		# Some kernels expose hidden fabrics devices ("nvmeXcXnX") under sysfs - skip them.
65		if (($(< "$nvme/hidden") == 1)); then
66			continue
67		fi
68		# Make sure we touch only the block devices which belong to bdev subsystem.
69		[[ $(< "$nvme/device/model") == "SPDK bdev Controller"* ]] || continue
70		blocks+=("${nvme##*/}")
71	done
72	printf '%s\n' "${blocks[@]}"
73}
74
75get_ublk() {
76	local blocks
77	blocks=(/sys/block/ublk*)
78	printf '%s\n' "${blocks[@]##*/}"
79}
80
81get_devices() {
82	local devs=("$@")
83
84	if ((${#devs[@]} == 0)); then
85		case "$protocol" in
86			iscsi) devs=($(get_iscsi)) ;;
87			nvmf) devs=($(get_nvme)) ;;
88			ublk) devs=($(get_ublk)) ;;
89			*) ;;
90		esac
91	fi
92	printf '%s\n' "${devs[@]}"
93}
94
95configure_devices() {
96	local devs=("$@") dev qd
97
98	if [[ -e $rootdir/scripts/sync_dev_uevents.sh ]]; then
99		"$rootdir/scripts/sync_dev_uevents.sh" block/disk "${devs[@]}"
100	fi > /dev/null
101
102	for dev in "${devs[@]}"; do
103		qd=128
104		# Disable all merge tries"
105		echo 2 > "/sys/block/$dev/queue/nomerges"
106		# FIXME: nr_requests already has its default value at 128. Also, when no
107		# scheduler is associated with the device this value cannot be changed
108		# and is automatically adjusted as well.
109		# echo 128 > "/sys/block/$dev/queue/nr_requests"
110		if [[ -e /sys/block/$dev/device/queue_depth ]]; then
111			# FIXME: Is this really needed though? Can't we use the default? This is not
112			# very deterministic as depending on the device we may end up with different
113			# qd in the range of 1-128.
114			while ((qd > 0)) && ! echo "$qd" > "/sys/block/$dev/device/queue_depth"; do
115				((--qd))
116			done 2> /dev/null
117			if ((qd == 0)); then
118				printf 'Failed to set queue_depth (%s)\n' "$dev"
119				return 1
120			fi
121			printf 'queue_depth set to %u (%s)\n' "$qd" "$dev"
122		else
123			printf 'Could not set queue depth (%s)\n' "$dev" >&2
124		fi
125		if [[ -e /sys/block/$dev/queue/scheduler ]]; then
126			echo none > "/sys/block/$dev/queue/scheduler"
127		fi
128	done
129}
130
131# Defaults
132blocksize=4096
133iodepth=1
134numjobs=1
135protocol="nvmf"
136runtime=1
137testtype="read"
138output=""
139rwmixread=""
140verify=0
141
142# Keep short args compatible with fio.py
143while getopts :i:d:n:p:r:t:o:m:v arg; do
144	case "$arg" in
145		i) blocksize=$OPTARG ;;
146		d) iodepth=$OPTARG ;;
147		n) numjobs=$OPTARG ;;
148		p) protocol=$OPTARG ;;
149		r) runtime=$OPTARG ;;
150		t) testtype=$OPTARG ;;
151		o) output=$OPTARG ;;
152		m) rwmixread=$OPTARG ;;
153		v) verify=1 ;;
154		*) ;;
155	esac
156done
157shift $((OPTIND - 1))
158
159devices=($(get_devices "$@"))
160if ((${#devices[@]} == 0)); then
161	printf '* No devices were found for the test, aborting\n' >&2
162	exit 1
163fi
164
165fio_config "${devices[@]}"
166configure_devices "${devices[@]}" && run_fio "${devices[@]}"
167