Whamcloud - gitweb
LU-633 iokit: mdt-survey script for MD echo client test
[fs/lustre-release.git] / lustre-iokit / mdt-survey / mdt-survey
1 #!/bin/bash
2 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
3
4 ######################################################################
5 # customize per survey
6
7 # Prerequisite: For "stripe_count > 0" you need to have ost setup and mounted.
8 #
9 # How to run test:
10 # case 1 (stripe_count=0 default):
11 #   $ thrhi=8 dir_count=4 sh md-survey
12 #   one can also run test with user defined targets as follows,
13 #   $ thrhi=8 dir_count=4 file_count=50000 targets="lustre-MDT0000" sh md-survey
14 # case 2 (stripe_count > 0, must have ost mounted):
15 #   $ thrhi=8 dir_count=4 file_count=50000 stripe_count=2 targets="lustre-MDT0000" sh md-survey
16 # [ NOTE: It is advised to have automated login (passwordless entry) on server ]
17
18 # include library
19 source libecho
20
21 # Customisation variables
22 #####################################################################
23 # One can change variable values in this section as per requirements
24 # The following variables can be set in the environment, or on the
25 # command line
26 # result file prefix (date/time + hostname makes unique)
27 # NB ensure path to it exists
28 rslt_loc=${rslt_loc:-"/tmp"}
29 rslt=${rslt:-"$rslt_loc/mdt_survey_`date +%F@%R`_`uname -n`"}
30
31 # min and max thread count
32 thrlo=${thrlo:-4}
33 thrhi=${thrhi:-32}
34
35 # number of directories to test
36 dir_count=${dir_count:-$thrlo}
37 # number of files per thread
38 file_count=${file_count:-100000}
39
40 targets=${targets:-""}
41 stripe_count=${stripe_count:-0}
42 # what tests to run (first must be create, and last must be destroy)
43 # default=(create lookup md_getattr setxattr destroy)
44 tests_str=${tests_str:-"create lookup md_getattr setxattr destroy"}
45
46 # start number for each thread
47 start_number=${start_number:-2}
48 # Customisation variables ends here.
49 #####################################################################
50 # leave the rest of this alone unless you know what you're doing...
51 export LC_ALL=POSIX
52 basedir="tests"
53 case=disk
54
55 create_directories () {
56     local host=$1
57     local devno=$2
58     local ndir=$3
59     local rfile=$4
60     local idx
61
62     for ((idx = 0; idx < $ndir; idx++)); do
63         if (( idx == 0 )); then
64             dirname=${basedir}
65         else
66             dirname=${basedir}${idx}
67         fi
68         remote_shell $host $lctl --device $devno test_mkdir /$dirname > $rfile 2>&1
69         while read line; do
70             echo "$line" | grep -q 'error: test_mkdir'
71             if [ $?  -eq 0 ]; then
72                 cat $rfile >&2
73                 echo "ERROR: fail test_mkdir" >&2
74                 echo "ERROR"
75                 return
76             fi
77         done < $rfile
78     done
79     echo $basedir
80 }
81
82 destroy_directories () {
83     local host=$1
84     local devno=$2
85     local ndir=$3
86     local rfile=$4
87     local idx
88
89     for ((idx = 0; idx < $ndir; idx++)); do
90         if (( idx == 0 )); then
91             dirname=${basedir}
92         else
93             dirname=${basedir}${idx}
94         fi
95         remote_shell $host $lctl --device $devno test_rmdir /$dirname > $rfile 2>&1
96     done
97 }
98
99 get_stats () {
100     local rfile=$1
101     gawk < $rfile                                    \
102     '/start at/ { n=0; next }                        \
103     /error at/ {n = -1; exit}                        \
104     /end/ {exit}                                     \
105     /^[0-9]+\/[0-9]+ Total: [0-9]+\.[0-9]+\/second$/ \
106     {    n++; v=strtonum($3);                        \
107          if (n == 1 || v < min) min = v;             \
108          if (n == 1 || v > max) max = v;             \
109          next;                                       \
110     }                                                \
111     {    if (n != 0) {n = -1; exit } }               \
112     END {printf "%d %f %f\n", n, min, max}'
113 }
114
115 get_global_stats () {
116     local rfile=$1
117     awk < $rfile                                    \
118     'BEGIN {n = 0;}                                 \
119     {    n++;                                       \
120          if (n == 1) { err = $1; min = $2; max = $3}\
121          else                                       \
122          { if ($1 < err) err = $1;                  \
123            if ($2 < min) min = $2;                  \
124            if ($3 > max) max = $3;                  \
125          }                                          \
126     }                                               \
127     END { if (n == 0) err = 0;                      \
128           printf "%d %f %f\n", err, min, max}'
129 }
130
131 print_summary () {
132     if [ "$1" = "-n" ]; then
133         minusn=$1; shift
134     else
135         minusn=""
136     fi
137     echo $minusn "$*" >> $rsltf
138     echo $minusn "$*"
139 }
140
141 declare -a tests
142 count=0
143 for name in $tests_str; do
144     tests[$count]=$name
145     count=$((count+1))
146 done
147
148 # hide a little trick to unset this from the command line
149 if [ "$lustre_root" == " " ]; then
150     unset lustre_root
151 fi
152
153 if [ -z "$lustre_root" ]; then
154     lctl=lctl
155 else
156     lctl=${lustre_root}/utils/lctl
157 fi
158
159 declare -a client_names
160 declare -a host_names
161 if [ -z "$targets" ]; then
162     targets=$($lctl device_list | awk "{if (\$2 == \"UP\" && \
163             \$3 == \"mdt\") {print \$4} }")
164     if [ -z "$targets" ]; then
165         echo "Can't find any MDT to test.  Please set targets=..."
166         exit 1
167     fi
168 fi
169
170 # check for ost
171 if (( $stripe_count > 0 )); then
172     obd=$($lctl device_list | awk "{if (\$2 == \"UP\" && \
173             \$3 == \"obdfilter\") {print \$4} }")
174     if [ -z "$obd" ]; then
175         echo "Need obdfilter to test stripe_count"
176         exit 1
177     fi
178 fi
179
180 # split out hostnames from mdt names
181 ndevs=0
182 for trgt in $targets; do
183     str=(`split_hostname $trgt`)
184     host_names[$ndevs]=${str[0]}
185     client_names[$ndevs]=${str[1]}
186     ndevs=$((ndevs+1))
187 done
188
189 # check and insert obdecho module
190 if ! lsmod | grep obdecho > /dev/null; then
191     modprobe obdecho
192 fi
193 count=${#tests[@]}
194 if [ $count -eq 0 -o "${tests[0]}" != "create" -o "${tests[(($count - 1))]}" != "destroy" ]; then
195     echo "tests: ${tests[@]}"
196     echo "First test must be 'create', and last test must be 'destroy'" 1>&2
197     exit 1
198 fi
199
200 rsltf="${rslt}.summary"
201 workf="${rslt}.detail"
202 cmdsf="${rslt}.script"
203 vmstatf="${rslt}.vmstat"
204 echo -n > $rsltf
205 echo -n > $workf
206
207 # get vmstat started
208 # disable portals debug and get obdecho loaded on all relevant hosts
209 unique_hosts=(`unique ${host_names[@]}`)
210 load_obdechos
211 pidcount=0
212 for host in ${unique_hosts[@]}; do
213     host_vmstatf=${vmstatf}_${host}
214     echo -n > $host_vmstatf
215     remote_shell $host "vmstat 5 >> $host_vmstatf" &> /dev/null &
216     pid=$!
217     vmstatpids[$pidcount]=$pid
218     pidcount=$((pidcount+1))
219 done
220 # get all the echo_client device numbers and names
221 for ((i=0; i < $ndevs; i++)); do
222     host=${host_names[$i]}
223     devno=(`get_ec_devno $host "${client_names[$i]}" "${client_names[$i]}" "mdt" "mdd"`)
224     if ((${#devno[@]} != 3)); then
225         exit 1
226     fi
227     devnos[$i]=${devno[0]}
228     client_names[$i]=${devno[1]}
229     do_teardown_ec[$i]=${devno[2]}
230 done
231 if (($ndevs <= 0 || ${#host_names[@]} <= 0)); then
232     echo "no devices or hosts specified"
233     cleanup 0
234 fi
235 print_summary "$(date) Mdt-survey from $(hostname)"
236 # create directories
237 tmpf="${workf}_tmp"
238 for ((idx = 0; idx < $ndevs; idx++)); do
239     host=${host_names[$idx]}
240     devno=${devnos[$idx]}
241     client_name="${host}:${client_names[$idx]}"
242     echo "=============> Create $dir_count directories on $client_name" >> $workf
243     destroy_directories $host $devno $dir_count $tmpf
244     ret=`create_directories $host $devno $dir_count $tmpf`
245     cat $tmpf >> $workf
246     rm $tmpf
247     if [ $ret = "ERROR" ]; then
248         print_summary "created directories on $client_name failed"
249         cleanup 1
250     fi
251 done
252
253 snap=1
254 for ((thr = $thrlo; thr <= $thrhi; thr*=2)); do
255     thr_per_dir=$((${thr}/${dir_count}))
256     # skip if no enough thread
257     if (( thr_per_dir <= 0 )); then
258         continue
259     fi
260     str=`printf 'mdt %1d file %7d dir %4d thr %4d ' \
261     $ndevs $file_count $dir_count $thr`
262     echo "=======================> $str" >> $workf
263     print_summary -n "$str"
264     # run tests
265     for test in ${tests[@]}; do
266         declare -a pidarray
267         for host in ${unique_hosts[@]}; do
268             echo "starting run for config: $config test: $test file: \
269             $file_count threads: $thr directories: $dir_count" >> ${vmstatf}_${host}
270         done
271         print_summary -n "$test "
272         # create per-host script files
273         for host in ${unique_hosts[@]}; do
274             echo -n > ${cmdsf}_${host}
275         done
276         for ((idx = 0; idx < $ndevs; idx++)); do
277             host=${host_names[$idx]}
278             devno=${devnos[$idx]}
279             tmpfi="${tmpf}_$idx"
280             [ $test = "create" ] && test="create -c $stripe_count"
281             echo >> ${cmdsf}_${host}                                                     \
282                 "$lctl > $tmpfi 2>&1                                                     \
283                  --threads $thr -$snap $devno test_$test -d /$basedir -D $dir_count      \
284                  -b $start_number -n $file_count"
285         done
286         pidcount=0
287         for host in ${unique_hosts[@]}; do
288             echo "wait" >> ${cmdsf}_${host}
289             pidarray[$pidcount]=0
290             pidcount=$((pidcount+1))
291         done
292         # timed run of all the per-host script files
293         t0=`date +%s.%N`
294         pidcount=0
295         for host in ${unique_hosts[@]}; do
296             remote_shell $host bash < ${cmdsf}_${host} &
297             pidarray[$pidcount]=$!
298             pidcount=$((pidcount+1))
299         done
300         pidcount=0
301         for host in ${unique_hosts[@]}; do
302             wait ${pidarray[$pidcount]}
303             pidcount=$((pidcount+1))
304         done
305         #wait
306         t1=`date +%s.%N`
307         # clean up per-host script files
308         for host in ${unique_hosts[@]}; do
309             rm ${cmdsf}_${host}
310         done
311
312         # compute bandwidth from total data / elapsed time
313         str=`awk "BEGIN {printf \"%7.2f \", \
314         ( $file_count * $thr_per_dir ) / ( $t1 - $t0 )}"`
315         print_summary -n "$str"
316         # collect/check individual MDT stats
317         echo -n > $tmpf
318         for ((idx = 0; idx < $ndevs; idx++)); do
319             client_name="${host_names[$idx]}:${client_names[$idx]}"
320             tmpfi="${tmpf}_$idx"
321             echo "=============> $test $client_name" >> $workf
322             host="${host_names[$idx]}"
323             remote_shell $host cat $tmpfi > ${tmpfi}_local
324             cat ${tmpfi}_local >> $workf
325             get_stats ${tmpfi}_local >> $tmpf
326             rm -f $tmpfi ${tmpfi}_local
327         done
328         # compute/display global min/max stats
329         echo "=============> $test global" >> $workf
330         cat $tmpf >> $workf
331         stats=(`get_global_stats $tmpf`)
332         rm $tmpf
333         if ((stats[0] <= 0)); then
334             if ((stats[0] < 0)); then
335                 str=`printf "%17s " ERROR`
336             else
337                 str=`printf "%17s " SHORT`
338             fi
339         else
340             str=`awk "BEGIN {printf \"[%7.2f,%7.2f] \", \
341             ${stats[1]}, ${stats[2]}; exit}"`
342         fi
343         print_summary -n "$str"
344     done
345     print_summary ""
346 done
347 # destroy directories
348 tmpf="${workf}_tmp"
349 for ((idx = 0; idx < $ndevs; idx++)); do
350     host=${host_names[$idx]}
351     devno=${devnos[$idx]}
352     client_name="${host}:${client_names[$idx]}"
353     echo "=============> Destroy $dir_count directories on $client_name" >> $workf
354     destroy_directories $host $devno $dir_count $tmpf
355 done
356
357 cleanup 0
358 exit 0