2 # SPDX-License-Identifier: GPL-2.0
5 # This file is part of Lustre, http://www.lustre.org/
8 ######################################################################
11 # Prerequisite: For "stripe_count > 0" you need to have ost setup and mounted.
14 # case 1 (stripe_count=0 default):
15 # $ thrhi=8 dir_count=4 sh mds-survey
16 # one can also run test with user defined targets as follows,
17 # $ thrhi=8 dir_count=4 file_count=50000 targets="lustre-MDT0000" sh mds-survey
18 # case 2 (stripe_count > 0, must have ost mounted):
19 # $ thrhi=8 dir_count=4 file_count=50000 stripe_count=2
20 # targets="lustre-MDT0000" sh mds-survey
21 # [ NOTE: It is advised to have automated login (passwordless entry) on server ]
24 source $(dirname $0)/iokit-libecho
26 # Customisation variables
27 #####################################################################
28 # One can change variable values in this section as per requirements
29 # The following variables can be set in the environment, or on the
31 # result file prefix (date/time + hostname makes unique)
32 # NB ensure path to it exists
33 rslt_loc=${rslt_loc:-"/tmp"}
34 rslt=${rslt:-"$rslt_loc/mds_survey_`date +%F@%R`_`uname -n`"}
36 # min and max thread count
40 # number of directories to test
41 dir_count=${dir_count:-$thrlo}
42 # number of files per thread
43 file_count=${file_count:-100000}
45 targets=${targets:-""}
46 stripe_count=${stripe_count:-0}
47 # what tests to run (first must be create, and last must be destroy)
48 # default=(create lookup md_getattr setxattr destroy)
49 tests_str=${tests_str:-"create lookup md_getattr setxattr destroy"}
51 # start number for each thread
52 start_number=${start_number:-2}
56 # Customisation variables ends here.
57 #####################################################################
58 # leave the rest of this alone unless you know what you're doing...
63 create_directories () {
72 for ((idx = 0; idx < $ndir; idx++)); do
73 if (( idx == 0 )); then
74 dirname="$(printf "${mdtbasedir}" $mdtidx)${basedir}"
76 dirname="$(printf "${mdtbasedir}" $mdtidx)${basedir}${idx}"
78 remote_shell $host $LCTL --device $devno test_mkdir /$dirname \
79 -c $dir_stripes --stripe_index $mdtidx > $rfile 2>&1
81 echo "$line" | grep -q 'error: test_mkdir'
84 echo "ERROR: fail test_mkdir" >&2
93 destroy_directories () {
101 for ((idx = 0; idx < $ndir; idx++)); do
102 if (( idx == 0 )); then
103 dirname="$(printf "${mdtbasedir}" $mdtidx)${basedir}"
105 dirname="$(printf "${mdtbasedir}" $mdtidx)${basedir}${idx}"
107 remote_shell $host $LCTL --device $devno test_rmdir /$dirname > $rfile 2>&1
122 /PID [0-9]+ had rc=0/ { \
125 /^Total: total [0-9]+ threads [0-9]+ sec [0-9\.]+ [0-9]+\.[0-9]+\/second$/ { \
126 ave = strtonum($8); \
130 /^[0-9]+\/[0-9]+ Total: [0-9]+\.[0-9]+\/second$/ { \
131 n++; v = strtonum($3); \
132 if (n == 1 || v < min) min = v; \
133 if (n == 1 || v > max) max = v; \
147 printf "%d %f %f %f\n", n, ave, min, max \
151 get_global_stats () {
178 printf "%d %f %f %f\n", err, ave/n, min, max \
183 if [ "$1" = "-n" ]; then
188 echo $minusn "$*" >> $rsltf
194 for name in $tests_str; do
199 # hide a little trick to unset this from the command line
200 if [ "$lustre_root" == " " ]; then
204 # find where 'lctl' binary is installed on this system
205 if [[ -x "$LCTL" ]]; then # full pathname specified
206 : # echo "LCTL=$LCTL"
207 elif [[ -n "$lustre_root" && -x "$lustre_root/utils/lctl" ]]; then
208 LCTL=${lustre_root}/utils/lctl
209 elif [[ -n "$LUSTRE" && -x "$LUSTRE/utils/lctl" ]]; then
210 LCTL=$LUSTRE/utils/lctl
211 else # hope that it is in the PATH
214 [[ -n "$(which $LCTL)" ]] || { echo "error: lctl not found"; exit 99; }
216 declare -a client_names
217 declare -a host_names
218 declare -a client_indexes
219 if [ -z "$targets" ]; then
220 targets=$($LCTL device_list | awk "{if (\$2 == \"UP\" && \
221 \$3 == \"mdt\") {print \$4} }")
222 if [ -z "$targets" ]; then
223 echo "Can't find any MDT to test. Please set targets=..."
228 # split out hostnames from mdt names
230 for trgt in $targets; do
231 str=($(split_hostname $trgt))
232 host_names[$ndevs]=${str[0]}
233 client_names[$ndevs]=${str[1]}
234 client_indexes[$ndevs]=0x$(echo ${str[1]} |
235 sed 's/.*MDT\([0-9a-f][0-9a-f][0-9a-f][0-9a-f]\).*/\1/')
240 if (( $stripe_count > 0 )); then
241 for ((i=0; i < $ndevs; i++)); do
242 host=${host_names[$i]}
243 obd=$(remote_shell $host $LCTL device_list |
244 awk "{ if (\$2 == \"UP\" &&
245 (\$3 == \"osc\" || \$3 == \"osp\"))
247 if [ -z "$obd" ]; then
248 echo "Need obdfilter to test stripe_count"
254 # check and insert obdecho module
255 if ! lsmod | grep obdecho > /dev/null; then
259 if [ $count -eq 0 -o "${tests[0]}" != "create" -o "${tests[(($count - 1))]}" != "destroy" ]; then
260 echo "tests: ${tests[@]}"
261 echo "First test must be 'create', and last test must be 'destroy'" 1>&2
265 rsltf="${rslt}.summary"
266 workf="${rslt}.detail"
267 cmdsf="${rslt}.script"
268 vmstatf="${rslt}.vmstat"
273 # disable portals debug and get obdecho loaded on all relevant hosts
274 unique_hosts=($(unique ${host_names[@]}))
277 for host in ${unique_hosts[@]}; do
278 host_vmstatf=${vmstatf}_${host}
279 echo -n > $host_vmstatf
280 remote_shell $host "vmstat 5 >> $host_vmstatf" &> /dev/null &
282 vmstatpids[$pidcount]=$pid
283 pidcount=$((pidcount+1))
285 # get all the echo_client device numbers and names
286 for ((i=0; i < $ndevs; i++)); do
287 host=${host_names[$i]}
288 devno=($(get_ec_devno $host "${client_names[$i]}" "${client_names[$i]}" "mdt" $layer))
289 if ((${#devno[@]} != 3)); then
292 devnos[$i]=${devno[0]}
293 client_names[$i]=${devno[1]}
294 do_teardown_ec[$i]=${devno[2]}
296 if (($ndevs <= 0 || ${#host_names[@]} <= 0)); then
297 echo "no devices or hosts specified"
300 print_summary "$(date) $0 from $(hostname)"
303 for ((idx = 0; idx < $ndevs; idx++)); do
304 host=${host_names[$idx]}
305 devno=${devnos[$idx]}
306 client_name="${host}:${client_names[$idx]}"
307 mdtidx=${client_indexes[$idx]}
308 echo "=======> Create $dir_count directories on $client_name" >> $workf
309 destroy_directories $host $devno $dir_count $tmpf $mdtidx
310 ret=$(create_directories $host $devno $dir_count $tmpf $mdtidx $ndevs)
313 if [ $ret = "ERROR" ]; then
314 print_summary "created directories on $client_name failed"
321 for ((thr = $thrlo; thr <= $thrhi; thr*=2)); do
322 thr_per_dir=$((${thr}/${dir_count}))
323 # skip if no enough thread
324 if (( thr_per_dir <= 0 )); then
327 file_count_per_thread=$((${file_count}/${thr}))
328 str=$(printf 'mdt %1d file %7d dir %4d thr %4d ' \
329 $ndevs $file_count $dir_count $thr)
330 echo "=======> $str" >> $workf
331 print_summary -n "$str"
333 for test in ${tests[@]}; do
335 for host in ${unique_hosts[@]}; do
336 echo "starting run for config: $config test: $test " \
337 "file: $file_count threads: $thr " \
338 "directories: $dir_count" >> ${vmstatf}_${host}
340 print_summary -n "$test "
341 # create per-host script files
342 for host in ${unique_hosts[@]}; do
343 echo -n > ${cmdsf}_${host}
345 for ((idx = 0; idx < $ndevs; idx++)); do
346 host=${host_names[$idx]}
347 devno=${devnos[$idx]}
348 dirname="$(printf "${mdtbasedir}" ${client_indexes[$idx]})$basedir"
350 [ "$test" = "create" ] && test="create -c $stripe_count"
351 echo >> ${cmdsf}_${host} \
352 "$LCTL > $tmpfi 2>&1 \
353 --threads $thr -$snap $devno test_$test \
354 -d /$dirname -D $dir_count \
355 -b $start_number -n $file_count_per_thread"
358 for host in ${unique_hosts[@]}; do
359 echo "wait" >> ${cmdsf}_${host}
360 pidarray[$pidcount]=0
361 pidcount=$((pidcount+1))
364 for host in ${unique_hosts[@]}; do
365 remote_shell $host bash < ${cmdsf}_${host} &
366 pidarray[$pidcount]=$!
367 pidcount=$((pidcount+1))
370 for host in ${unique_hosts[@]}; do
371 wait ${pidarray[$pidcount]}
372 pidcount=$((pidcount+1))
375 # clean up per-host script files
376 for host in ${unique_hosts[@]}; do
380 # collect/check individual MDT stats
382 for ((idx = 0; idx < $ndevs; idx++)); do
383 client_name="${host_names[$idx]}:${client_names[$idx]}"
385 echo "=============> $test $client_name" >> $workf
386 host="${host_names[$idx]}"
387 remote_shell $host cat $tmpfi > ${tmpfi}_local
388 cat ${tmpfi}_local >> $workf
389 get_stats ${tmpfi}_local >> $tmpf
390 rm -f $tmpfi ${tmpfi}_local
392 # compute/display global min/max stats
393 echo "=============> $test global" >> $workf
395 stats=($(get_global_stats $tmpf))
397 if ((stats[0] <= 0)); then
398 str=$(printf "%17s " ERROR)
401 str=$(awk "BEGIN {printf \"%7.2f [ %7.2f, %7.2f] \", \
402 ${stats[1]}, ${stats[2]}, ${stats[3]}; exit}")
404 print_summary -n "$str"
409 # destroy directories
411 for ((idx = 0; idx < $ndevs; idx++)); do
412 host=${host_names[$idx]}
413 devno=${devnos[$idx]}
414 mdtidx=${client_indexes[$idx]}
415 client_name="${host}:${client_names[$idx]}"
416 echo "====> Destroy $dir_count directories on $client_name" >> $workf
417 destroy_directories $host $devno $dir_count $tmpf $mdtidx