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