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