Whamcloud - gitweb
LU-911 osd: OI is implemented internally within OSD
[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 $(dirname $0)/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
58 create_directories () {
59     local host=$1
60     local devno=$2
61     local ndir=$3
62     local rfile=$4
63     local idx
64
65     for ((idx = 0; idx < $ndir; idx++)); do
66         if (( idx == 0 )); then
67             dirname=${basedir}
68         else
69             dirname=${basedir}${idx}
70         fi
71         remote_shell $host $lctl --device $devno test_mkdir /$dirname > $rfile 2>&1
72         while read line; do
73             echo "$line" | grep -q 'error: test_mkdir'
74             if [ $?  -eq 0 ]; then
75                 cat $rfile >&2
76                 echo "ERROR: fail test_mkdir" >&2
77                 echo "ERROR"
78                 return
79             fi
80         done < $rfile
81     done
82     echo $basedir
83 }
84
85 destroy_directories () {
86     local host=$1
87     local devno=$2
88     local ndir=$3
89     local rfile=$4
90     local idx
91
92     for ((idx = 0; idx < $ndir; idx++)); do
93         if (( idx == 0 )); then
94             dirname=${basedir}
95         else
96             dirname=${basedir}${idx}
97         fi
98         remote_shell $host $lctl --device $devno test_rmdir /$dirname > $rfile 2>&1
99     done
100 }
101
102 get_stats () {
103     local rfile=$1
104     gawk < $rfile                                                               \
105     '/starting/ { n=0; next }                                                   \
106      /error/ {n = -1; exit}                                                     \
107      /^Total: total [0-9]+ threads [0-9]+ sec [0-9\.]+ [0-9]+\.[0-9]+\/second$/ \
108      { ave = strtonum($8); n++; next}                                           \
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 { if (n == 1) { min = ave; max = ave; }                                \
117            printf "%d %f %f %f\n", n, ave, min, max}'
118 }
119
120 get_global_stats () {
121     local rfile=$1
122     awk < $rfile                                               \
123     'BEGIN {n = 0;}                                            \
124     {    n++;                                                  \
125          if (n == 1) { err = $1; ave = $2; min = $3; max = $4} \
126          else                                                  \
127          { if ($1 < err) err = $1;                             \
128            if ($2 < min) min = $2;                             \
129            if ($3 > max) max = $3;                             \
130          }                                                     \
131     }                                                          \
132     END { if (n == 0) err = 0;                                 \
133           printf "%d %f %f %f\n", err, ave, min, max}'
134 }
135
136 print_summary () {
137     if [ "$1" = "-n" ]; then
138         minusn=$1; shift
139     else
140         minusn=""
141     fi
142     echo $minusn "$*" >> $rsltf
143     echo $minusn "$*"
144 }
145
146 declare -a tests
147 count=0
148 for name in $tests_str; do
149     tests[$count]=$name
150     count=$((count+1))
151 done
152
153 # hide a little trick to unset this from the command line
154 if [ "$lustre_root" == " " ]; then
155     unset lustre_root
156 fi
157
158 if [ -z "$lustre_root" ]; then
159     lctl=lctl
160 else
161     lctl=${lustre_root}/utils/lctl
162 fi
163
164 declare -a client_names
165 declare -a host_names
166 if [ -z "$targets" ]; then
167     targets=$($lctl device_list | awk "{if (\$2 == \"UP\" && \
168             \$3 == \"mdt\") {print \$4} }")
169     if [ -z "$targets" ]; then
170         echo "Can't find any MDT to test.  Please set targets=..."
171         exit 1
172     fi
173 fi
174
175 # split out hostnames from mdt names
176 ndevs=0
177 for trgt in $targets; do
178     str=(`split_hostname $trgt`)
179     host_names[$ndevs]=${str[0]}
180     client_names[$ndevs]=${str[1]}
181     ndevs=$((ndevs+1))
182 done
183
184 # check for ost
185 if (( $stripe_count > 0 )); then
186     for ((i=0; i < $ndevs; i++)); do
187         host=${host_names[$i]}
188         obd=$(remote_shell $host $lctl device_list | awk "{if (\$2 == \"UP\" &&
189             \$3 == \"osc\") { print \$4 } }")
190         if [ -z "$obd" ]; then
191             echo "Need obdfilter to test stripe_count"
192             exit 1
193         fi
194     done
195 fi
196
197 # check and insert obdecho module
198 if ! lsmod | grep obdecho > /dev/null; then
199     modprobe obdecho
200 fi
201 count=${#tests[@]}
202 if [ $count -eq 0 -o "${tests[0]}" != "create" -o "${tests[(($count - 1))]}" != "destroy" ]; then
203     echo "tests: ${tests[@]}"
204     echo "First test must be 'create', and last test must be 'destroy'" 1>&2
205     exit 1
206 fi
207
208 rsltf="${rslt}.summary"
209 workf="${rslt}.detail"
210 cmdsf="${rslt}.script"
211 vmstatf="${rslt}.vmstat"
212 echo -n > $rsltf
213 echo -n > $workf
214
215 # get vmstat started
216 # disable portals debug and get obdecho loaded on all relevant hosts
217 unique_hosts=(`unique ${host_names[@]}`)
218 load_obdechos
219 pidcount=0
220 for host in ${unique_hosts[@]}; do
221     host_vmstatf=${vmstatf}_${host}
222     echo -n > $host_vmstatf
223     remote_shell $host "vmstat 5 >> $host_vmstatf" &> /dev/null &
224     pid=$!
225     vmstatpids[$pidcount]=$pid
226     pidcount=$((pidcount+1))
227 done
228 # get all the echo_client device numbers and names
229 for ((i=0; i < $ndevs; i++)); do
230     host=${host_names[$i]}
231     devno=(`get_ec_devno $host "${client_names[$i]}" "${client_names[$i]}" "mdt" $layer`)
232     if ((${#devno[@]} != 3)); then
233         exit 1
234     fi
235     devnos[$i]=${devno[0]}
236     client_names[$i]=${devno[1]}
237     do_teardown_ec[$i]=${devno[2]}
238 done
239 if (($ndevs <= 0 || ${#host_names[@]} <= 0)); then
240     echo "no devices or hosts specified"
241     cleanup 0
242 fi
243 print_summary "$(date) $0 from $(hostname)"
244 # create directories
245 tmpf="${workf}_tmp"
246 for ((idx = 0; idx < $ndevs; idx++)); do
247     host=${host_names[$idx]}
248     devno=${devnos[$idx]}
249     client_name="${host}:${client_names[$idx]}"
250     echo "=============> Create $dir_count directories on $client_name" >> $workf
251     destroy_directories $host $devno $dir_count $tmpf
252     ret=`create_directories $host $devno $dir_count $tmpf`
253     cat $tmpf >> $workf
254     rm $tmpf
255     if [ $ret = "ERROR" ]; then
256         print_summary "created directories on $client_name failed"
257         cleanup 1
258     fi
259 done
260
261 snap=1
262 status=0
263 for ((thr = $thrlo; thr <= $thrhi; thr*=2)); do
264     thr_per_dir=$((${thr}/${dir_count}))
265     # skip if no enough thread
266     if (( thr_per_dir <= 0 )); then
267         continue
268     fi
269     str=`printf 'mdt %1d file %7d dir %4d thr %4d ' \
270     $ndevs $file_count $dir_count $thr`
271     echo "=======================> $str" >> $workf
272     print_summary -n "$str"
273     # run tests
274     for test in ${tests[@]}; do
275         declare -a pidarray
276         for host in ${unique_hosts[@]}; do
277             echo "starting run for config: $config test: $test file: \
278             $file_count threads: $thr directories: $dir_count" >> ${vmstatf}_${host}
279         done
280         print_summary -n "$test "
281         # create per-host script files
282         for host in ${unique_hosts[@]}; do
283             echo -n > ${cmdsf}_${host}
284         done
285         for ((idx = 0; idx < $ndevs; idx++)); do
286             host=${host_names[$idx]}
287             devno=${devnos[$idx]}
288             tmpfi="${tmpf}_$idx"
289             [ $test = "create" ] && test="create -c $stripe_count"
290             echo >> ${cmdsf}_${host}                                                     \
291                 "$lctl > $tmpfi 2>&1                                                     \
292                  --threads $thr -$snap $devno test_$test -d /$basedir -D $dir_count      \
293                  -b $start_number -n $file_count"
294         done
295         pidcount=0
296         for host in ${unique_hosts[@]}; do
297             echo "wait" >> ${cmdsf}_${host}
298             pidarray[$pidcount]=0
299             pidcount=$((pidcount+1))
300         done
301         pidcount=0
302         for host in ${unique_hosts[@]}; do
303             remote_shell $host bash < ${cmdsf}_${host} &
304             pidarray[$pidcount]=$!
305             pidcount=$((pidcount+1))
306         done
307         pidcount=0
308         for host in ${unique_hosts[@]}; do
309             wait ${pidarray[$pidcount]}
310             pidcount=$((pidcount+1))
311         done
312         #wait
313         # clean up per-host script files
314         for host in ${unique_hosts[@]}; do
315             rm ${cmdsf}_${host}
316         done
317
318         # collect/check individual MDT stats
319         echo -n > $tmpf
320         for ((idx = 0; idx < $ndevs; idx++)); do
321             client_name="${host_names[$idx]}:${client_names[$idx]}"
322             tmpfi="${tmpf}_$idx"
323             echo "=============> $test $client_name" >> $workf
324             host="${host_names[$idx]}"
325             remote_shell $host cat $tmpfi > ${tmpfi}_local
326             cat ${tmpfi}_local >> $workf
327             get_stats ${tmpfi}_local >> $tmpf
328             rm -f $tmpfi ${tmpfi}_local
329         done
330         # compute/display global min/max stats
331         echo "=============> $test global" >> $workf
332         cat $tmpf >> $workf
333         stats=(`get_global_stats $tmpf`)
334         rm $tmpf
335         if ((stats[0] <= 0)); then
336             str=`printf "%17s " ERROR`
337             status=1
338         else
339             str=`awk "BEGIN {printf \"%7.2f [%7.2f,%7.2f] \", \
340             ${stats[1]}, ${stats[2]}, ${stats[3]}; exit}"`
341         fi
342         print_summary -n "$str"
343     done
344     print_summary ""
345 done
346 # destroy directories
347 tmpf="${workf}_tmp"
348 for ((idx = 0; idx < $ndevs; idx++)); do
349     host=${host_names[$idx]}
350     devno=${devnos[$idx]}
351     client_name="${host}:${client_names[$idx]}"
352     echo "=============> Destroy $dir_count directories on $client_name" >> $workf
353     destroy_directories $host $devno $dir_count $tmpf
354 done
355
356 cleanup $status
357 exit $status