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