one-core-peak.sh: Fixing bash
[fio.git] / t / one-core-peak.sh
CommitLineData
0c6c0ebb
EV
1#!/bin/bash
2
3args=$*
4first_cores=""
5taskset_cores=""
6first_cores_count=0
7nb_threads=4 #default from the benchmark
55875a2c
EV
8drives=""
9
10# Default options
11latency_cmdline=""
0c6c0ebb
EV
12
13fatal() {
14 echo "$@"
15 exit 1
16}
17
18hint() {
19 echo "Warning: $*"
20}
21
22info() {
23 item=$1
24 shift
25 echo "${item}: $*"
26}
27
28check_root() {
29 [[ ${EUID} -eq 0 ]] || fatal "You should be root to run this tool"
30}
31
32check_binary() {
33 # Ensure the binaries are present and executable
34 for bin in "$@"; do
35 if [ ! -x ${bin} ]; then
36 which ${bin} >/dev/null
37 [ $? -eq 0 ] || fatal "${bin} doesn't exists or is not executable"
38 fi
39 done
40}
41
42
43detect_first_core() {
44 # Detect which logical cpus belongs to the first physical core
45 # If Hyperthreading is enabled, two cores are returned
46 cpus=$(lscpu --all -pSOCKET,CORE,CPU |grep "0,0")
47 for cpu in ${cpus}; do
48 IFS=','
49 # shellcheck disable=SC2206
50 array=(${cpu})
51 if [ ${first_cores_count} -eq 0 ]; then
52 first_cores="${array[2]}"
53 else
54 first_cores="${first_cores} ${array[2]}"
55 fi
56
57 first_cores_count=$((first_cores_count + 1))
58 unset IFS
59 done
60 [ ${first_cores_count} -eq 0 ] && fatal "Cannot detect first core"
61 taskset_cores=$(echo "${first_cores}" | tr ' ' ',')
62}
63
55875a2c
EV
64usage() {
65 echo "usage: [options] block_device [other_block_devices]
66
67 -h : print help
68 -l : enable latency reporting
69
70 example:
71 t/one-core-peak.sh /dev/nvme0n1
72 t/one-core-peak.sh -l /dev/nvme0n1 /dev/nvme1n1
73 "
74 exit 0
75}
76
0c6c0ebb 77check_args() {
0551c571 78 local OPTIND option
55875a2c
EV
79 while getopts "hl" option; do
80 case "${option}" in
81 h) # Show help
82 usage
83 ;;
84 l) # Report latency
85 latency_cmdline="1"
86 ;;
87 *)
88 fatal "Unsupported ${option} option"
89 ;;
90 esac
91 done
92 shift $((OPTIND-1))
93 [ $# -eq 0 ] && fatal "Missing drive(s) as argument"
0551c571 94 drives="$*"
0c6c0ebb
EV
95}
96
97check_drive_exists() {
98 # Ensure the block device exists
99 [ -b $1 ] || fatal "$1 is not a valid block device"
100}
101
102is_nvme() {
103 [[ ${*} == *"nvme"* ]]
104}
105
106check_poll_queue() {
107 # Print a warning if the nvme poll queues aren't enabled
55875a2c 108 is_nvme ${drives} || return
0c6c0ebb
EV
109 poll_queue=$(cat /sys/module/nvme/parameters/poll_queues)
110 [ ${poll_queue} -eq 0 ] && hint "For better performance, you should enable nvme poll queues by setting nvme.poll_queues=32 on the kernel commande line"
111}
112
113block_dev_name() {
114 echo ${1#"/dev/"}
115}
116
117get_sys_block_dir() {
118 # Returns the /sys/block/ directory of a given block device
119 device_name=$1
120 sys_block_dir="/sys/block/${device_name}"
121 [ -d "${sys_block_dir}" ] || fatal "Cannot find ${sys_block_dir} directory"
122 echo ${sys_block_dir}
123}
124
125check_io_scheduler() {
126 # Ensure io_sched is set to none
127 device_name=$(block_dev_name $1)
128 sys_block_dir=$(get_sys_block_dir ${device_name})
129 sched_file="${sys_block_dir}/queue/scheduler"
130 [ -f "${sched_file}" ] || fatal "Cannot find IO scheduler for ${device_name}"
131 grep -q '\[none\]' ${sched_file}
132 if [ $? -ne 0 ]; then
133 info "${device_name}" "set none as io scheduler"
134 echo "none" > ${sched_file}
135 fi
136
137}
138
139check_sysblock_value() {
140 device_name=$(block_dev_name $1)
141 sys_block_dir=$(get_sys_block_dir ${device_name})
142 target_file="${sys_block_dir}/$2"
143 value=$3
144 [ -f "${target_file}" ] || fatal "Cannot find ${target_file} for ${device_name}"
145 content=$(cat ${target_file})
146 if [ "${content}" != "${value}" ]; then
147 info "${device_name}" "${target_file} set to ${value}."
148 echo ${value} > ${target_file} 2>/dev/null || hint "${device_name}: Cannot set ${value} on ${target_file}"
149 fi
150}
151
152compute_nb_threads() {
153 # Increase the number of threads if there is more devices or cores than the default value
154 [ $# -gt ${nb_threads} ] && nb_threads=$#
155 [ ${first_cores_count} -gt ${nb_threads} ] && nb_threads=${first_cores_count}
156}
157
158check_scaling_governor() {
159 driver=$(LC_ALL=C cpupower frequency-info |grep "driver:" |awk '{print $2}')
160 if [ -z "${driver}" ]; then
161 hint "Cannot detect processor scaling driver"
162 return
163 fi
164 cpupower frequency-set -g performance >/dev/null 2>&1 || fatal "Cannot set scaling processor governor"
165}
166
167check_idle_governor() {
168 filename="/sys/devices/system/cpu/cpuidle/current_governor"
169 if [ ! -f "${filename}" ]; then
170 hint "Cannot detect cpu idle governor"
171 return
172 fi
173 echo "menu" > ${filename} 2>/dev/null || fatal "Cannot set cpu idle governor to menu"
174}
175
176show_nvme() {
177 device_name=$(block_dev_name $1)
178 device_dir="/sys/block/${device_name}/device/"
179 pci_addr=$(cat ${device_dir}/address)
180 pci_dir="/sys/bus/pci/devices/${pci_addr}/"
181 link_speed=$(cat ${pci_dir}/current_link_speed)
182 irq=$(cat ${pci_dir}/irq)
183 numa=$(cat ${pci_dir}/numa_node)
184 cpus=$(cat ${pci_dir}/local_cpulist)
185 model=$(cat ${device_dir}/model | xargs) #xargs for trimming spaces
186 fw=$(cat ${device_dir}/firmware_rev | xargs) #xargs for trimming spaces
187 serial=$(cat ${device_dir}/serial | xargs) #xargs for trimming spaces
188 info ${device_name} "MODEL=${model} FW=${fw} serial=${serial} PCI=${pci_addr}@${link_speed} IRQ=${irq} NUMA=${numa} CPUS=${cpus} "
189}
190
191show_device() {
192 device_name=$(block_dev_name $1)
193 is_nvme $1 && show_nvme $1
194}
195
196show_system() {
55875a2c
EV
197 CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo | awk '{print substr($0, index($0,$4))}')
198 MEMORY_SPEED=$(dmidecode -t 17 -q | grep -m 1 "Configured Memory Speed: [0-9]" | awk '{print substr($0, index($0,$4))}')
199 KERNEL=$(uname -r)
200 info "system" "CPU: ${CPU_MODEL}"
201 info "system" "MEMORY: ${MEMORY_SPEED}"
202 info "system" "KERNEL: ${KERNEL}"
0551c571 203 tsc=$(journalctl -k | grep 'tsc: Refined TSC clocksource calibration:' | awk '{print $11}')
55875a2c
EV
204 if [ -n "${tsc}" ]; then
205 info "system" "TSC: ${tsc} Mhz"
206 tsc=$(echo ${tsc} | tr -d '.')
207 [ -n "${latency_cmdline}" ] && latency_cmdline="-t1 -T${tsc}000"
208 fi
0c6c0ebb
EV
209}
210
211### MAIN
55875a2c 212check_args ${args}
0c6c0ebb
EV
213check_root
214check_binary t/io_uring lscpu grep taskset cpupower awk tr xargs dmidecode
215detect_first_core
216
217info "##################################################"
218show_system
55875a2c 219for drive in ${drives}; do
0c6c0ebb
EV
220 check_drive_exists ${drive}
221 check_io_scheduler ${drive}
222 check_sysblock_value ${drive} "queue/iostats" 0 # Ensure iostats are disabled
223 check_sysblock_value ${drive} "queue/nomerges" 2 # Ensure merge are disabled
224 check_sysblock_value ${drive} "queue/io_poll" 1 # Ensure io_poll is enabled
225 show_device ${drive}
226done
227
228check_poll_queue
55875a2c 229compute_nb_threads ${drives}
0c6c0ebb
EV
230check_scaling_governor
231check_idle_governor
232
233info "##################################################"
234echo
235
55875a2c 236cmdline="taskset -c ${taskset_cores} t/io_uring -b512 -d128 -c32 -s32 -p1 -F1 -B1 -n${nb_threads} ${latency_cmdline} ${drives}"
0c6c0ebb
EV
237info "io_uring" "Running ${cmdline}"
238${cmdline}