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