Commit | Line | Data |
---|---|---|
0c6c0ebb EV |
1 | #!/bin/bash |
2 | ||
3 | args=$* | |
4 | first_cores="" | |
5 | taskset_cores="" | |
6 | first_cores_count=0 | |
7 | nb_threads=4 #default from the benchmark | |
55875a2c EV |
8 | drives="" |
9 | ||
10 | # Default options | |
11 | latency_cmdline="" | |
0c6c0ebb EV |
12 | |
13 | fatal() { | |
14 | echo "$@" | |
15 | exit 1 | |
16 | } | |
17 | ||
18 | hint() { | |
19 | echo "Warning: $*" | |
20 | } | |
21 | ||
22 | info() { | |
23 | item=$1 | |
24 | shift | |
25 | echo "${item}: $*" | |
26 | } | |
27 | ||
28 | check_root() { | |
29 | [[ ${EUID} -eq 0 ]] || fatal "You should be root to run this tool" | |
30 | } | |
31 | ||
32 | check_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 | ||
43 | detect_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 |
64 | usage() { |
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 | 77 | check_args() { |
55875a2c EV |
78 | local OPTIND h option |
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" | |
94 | drives="$@" | |
0c6c0ebb EV |
95 | } |
96 | ||
97 | check_drive_exists() { | |
98 | # Ensure the block device exists | |
99 | [ -b $1 ] || fatal "$1 is not a valid block device" | |
100 | } | |
101 | ||
102 | is_nvme() { | |
103 | [[ ${*} == *"nvme"* ]] | |
104 | } | |
105 | ||
106 | check_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 | ||
113 | block_dev_name() { | |
114 | echo ${1#"/dev/"} | |
115 | } | |
116 | ||
117 | get_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 | ||
125 | check_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 | ||
139 | check_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 | ||
152 | compute_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 | ||
158 | check_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 | ||
167 | check_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 | ||
176 | show_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 | ||
191 | show_device() { | |
192 | device_name=$(block_dev_name $1) | |
193 | is_nvme $1 && show_nvme $1 | |
194 | } | |
195 | ||
196 | show_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}" | |
203 | tsc=$(journalctl -k | grep 'tsc: Refined TSC clocksource calibration:' | awk '{print $11'}) | |
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 | 212 | check_args ${args} |
0c6c0ebb EV |
213 | check_root |
214 | check_binary t/io_uring lscpu grep taskset cpupower awk tr xargs dmidecode | |
215 | detect_first_core | |
216 | ||
217 | info "##################################################" | |
218 | show_system | |
55875a2c | 219 | for 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} | |
226 | done | |
227 | ||
228 | check_poll_queue | |
55875a2c | 229 | compute_nb_threads ${drives} |
0c6c0ebb EV |
230 | check_scaling_governor |
231 | check_idle_governor | |
232 | ||
233 | info "##################################################" | |
234 | echo | |
235 | ||
55875a2c | 236 | cmdline="taskset -c ${taskset_cores} t/io_uring -b512 -d128 -c32 -s32 -p1 -F1 -B1 -n${nb_threads} ${latency_cmdline} ${drives}" |
0c6c0ebb EV |
237 | info "io_uring" "Running ${cmdline}" |
238 | ${cmdline} |