Whamcloud - gitweb
06c26e83f0a514ed05a8699e959549dd0818a3c5
[fs/lustre-release.git] / lustre-iokit / obdfilter-survey / obdfilter-survey
1 #!/bin/bash
2
3 ######################################################################
4 # customize per survey
5
6 # specify obd names (host:name if remote)
7 # these can either be the echo_client names (client_names)
8 # or the ost names (ost_names)
9 #client_names=(ns8:ECHO_ns8 ns9:ECHO_ns9)
10 ost_names=(ns9:ost{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16})
11
12 # result file prefix (date/time + hostname makes unique)
13 rslt=/home_nfs/eeb/obdfilter_survey_`date +%F@%R`_`uname -n`
14
15 # lustre root (if running with own source tree)
16 lustre_root=/home_nfs/eeb/lustre
17
18 # what to do (we always do an initial write)
19 #tests="rewrite read reread rewrite_again"
20 tests="rewrite read"
21
22 # total size (MBytes) per OST
23 # large enough to avoid cache effects 
24 # and to make test startup/shutdown overhead insignificant
25 size=8192
26
27 # record size (KBytes)
28 rszlo=1024
29 rszhi=1024
30
31 # number of objects per OST
32 nobjlo=1
33 nobjhi=512
34
35 # threads per OST (1024 max)
36 thrlo=1
37 thrhi=64
38
39 # restart from here iff all are defined
40 restart_rsz=
41 restart_thr=1
42 restart_nobj=1
43
44 # machine's page size (K)
45 PAGE_SIZE=64
46
47 # max buffer_mem (total_threads * buffer size)
48 # (to avoid lctl ENOMEM problems)
49 max_buffer_mem=$((1024*1024))
50
51 # how to run commands on other nodes
52 custom_remote_shell () {
53     host=$1
54     shift
55     cmds="$*"
56     here=`pwd`
57     # Hop on to the remote node, chdir to 'here' and run the given
58     # commands. One of the following will probably work.
59     ssh $host "cd $here; $cmds"
60     #rsh $host "cd $here; $cmds"
61     # we have to remove the leading `uname -n`: from pdsh output lines
62     #pdsh -w $host "cd $here; $cmds" | sed 's/^[^:]*://'
63 }
64
65 #####################################################################
66 # leave the rest of this alone unless you know what you're doing...
67
68 lsmod="/sbin/lsmod"
69 modprobe="/sbin/modprobe"
70 insmod="/sbin/insmod"
71 rmmod="/sbin/rmmod"
72
73 snap=1
74 verify=1
75
76 rsltf="${rslt}.summary"
77 cmdsf="${rslt}.script"
78 workf="${rslt}.detail"
79 echo -n > $rsltf
80 echo -n > $workf
81
82 if [ -z "$lustre_root" ]; then
83     lctl=lctl
84 else
85     lctl=${lustre_root}/utils/lctl
86 fi
87
88 remote_shell () {
89     host=$1
90     shift
91     cmds="$*"
92     if [ "$host" = "localhost" -o "$host" = `uname -n` ]; then
93         eval "$cmds"
94     else
95         custom_remote_shell $host "$cmds"
96     fi
97 }
98
99 check_obdecho() {
100     local host=$1
101     remote_shell $host $lsmod | grep obdecho > /dev/null 2>&1
102 }
103
104 load_obdecho () {
105     local host=$1
106     if [ -z "$lustre_root" ]; then
107         remote_shell $host $modprobe obdecho
108     elif [ -f ${lustre_root}/obdecho/obdecho.ko ]; then
109         remote_shell $host $insmod ${lustre_root}/obdecho/obdecho.ko
110     else
111         remote_shell $host $insmod ${lustre_root}/obdecho/obdecho.o
112     fi
113 }
114
115 unload_obdecho () {
116     local host=$1
117     remote_shell $host $rmmod obdecho
118 }
119
120 get_devno () {
121     local host=$1
122     local type=$2
123     local name=$3
124     remote_shell $host $lctl device_list | \
125         awk "{if (\$2 == \"UP\" && \$3 == \"$type\" && \$4 == \"$name\") {\
126                   print \$1; exit}}"
127 }
128
129 get_ec_devno () {
130     local host=$1
131     local client_name="$2"
132     local ost_name="$3"
133     if [ -z "$client_name" ]; then
134         if [ -z "$ost_name" ]; then
135             echo "client and ost name both null" 1>&2
136             return
137         fi
138         client_name=${ost_name}_echo_client
139     fi
140     ec=`get_devno $host echo_client $client_name`
141     if [ -n "$ec" ]; then
142         echo $ec $client_name 0
143         return
144     fi
145     if [ -z "$ost_name" ]; then
146         echo "no echo client and ost_name not set" 1>&2
147         return
148     fi
149     ost=`get_devno $host obdfilter $ost_name`
150     if [ -z "$ost" ]; then
151         echo "OST $ost_name not setup" 1>&2
152         return
153     fi
154     remote_shell $host "$lctl <<EOF
155         attach echo_client $client_name ${client_name}_UUID
156         setup $ost_name
157 EOF"
158     ec=`get_devno $host echo_client $client_name`
159     if [ -z "$ec" ]; then
160         echo "Can't setup echo client" 1>&2
161         return
162     fi
163     echo $ec $client_name 1
164 }
165
166 teardown_ec_devno () {
167     local host=$1
168     local client_name=$2
169     remote_shell $host "$lctl <<EOF
170         cfg $client_name
171         cleanup
172         detach
173 EOF"
174 }
175
176 create_objects () {
177     # create a set of objects, check there are 'n' contiguous ones and
178     # return the first or 'ERROR'
179     local host=$1
180     local devno=$2
181     local nobj=$3
182     local rfile=$4
183     remote_shell $host $lctl --device $devno create $nobj > $rfile 2>&1
184     n=(`awk < $rfile \
185         '/is object id/ {obj=strtonum($6);\
186                          first=!not_first; not_first=1;\
187                          if (first) first_obj=obj;
188                          else if (obj != prev + 1) exit;\
189                          prev=obj; n++}\
190             END {printf "%d %d\n", first_obj, n}'`)
191     if ((n[1] != nobj)); then
192         echo "ERROR"
193     else
194         echo ${n[0]}
195     fi
196 }
197
198 destroy_objects () {
199     local host=$1
200     local devno=$2
201     local obj0=$3
202     local nobj=$4
203     local rfile=$5
204     remote_shell $host $lctl --device $devno destroy $obj0 $nobj > $rfile 2>&1
205 }
206
207 get_stats () {
208     local rfile=$1
209     awk < $rfile \
210         '/^Selected device [0-9]+$/ {n = 0; next}\
211         /error/ {n = -1; exit}\
212         /^[0-9]+\/[0-9]+ Total: [0-9]+\.[0-9]+\/second$/ {n++; v=strtonum($3); \
213                                                           if (n == 1 || v < min) min = v;\
214                                                           if (n == 1 || v > max) max = v;\
215                                                           next}\
216         {if (n != 0) {n = -1; exit}}\
217         END {printf "%d %f %f\n", n, min, max}'
218 }
219
220 get_global_stats () {
221     local rfile=$1
222     awk < $rfile 'BEGIN {n = 0;}\
223                   {n++; if (n == 1) {err = $1; min = $2; max = $3} else\
224                                     {if ($1 < err) err = $1;\
225                                      if ($2 < min) min = $2;\
226                                      if ($3 > max) max = $3}}\
227                   END {if (n == 0) err = 0;\
228                        printf "%d %f %f\n", err, min, max}'
229 }
230
231 testname2type () {
232     # 'x' disables data check
233     if ((verify)); then
234         x=""
235     else
236         x="x"
237     fi
238     case $1 in
239         *write*)  echo "w$x";;
240         *)        echo "r$x";;
241     esac
242 }
243
244 print_summary () {
245     if [ "$1" = "-n" ]; then
246         minusn=$1; shift
247     else
248         minusn=""
249     fi
250     echo $minusn "$*" >> $rsltf
251     echo $minusn "$*"
252 }
253
254 unique () {
255     echo "$@" | xargs -n1 echo | sort -u
256 }
257
258 split_hostname () {
259     name=$1
260     case $name in
261     *:*) host=`echo $name | sed 's/:.*$//'`
262          name=`echo $name | sed 's/[^:]*://'`
263          ;;
264     *)   host=localhost
265          ;;
266     esac
267     echo "$host $name"
268 }
269
270 ndevs=${#client_names[@]}
271 if ((ndevs != 0)); then
272     if ((${#ost_names[@]} != 0)); then
273         echo "Please specify client_names or ost_names, but not both" 1>&2
274         exit 1
275     fi
276     for ((i=0; i<ndevs;i++)); do
277         str=(`split_hostname ${client_names[$i]}`)
278         host_names[$i]=${str[0]}
279         client_names[$i]=${str[1]}
280     done
281 else
282     ndevs=${#ost_names[@]}
283     if ((ndevs == 0)); then
284         echo "Please specify either client_names or ost_names" 1>&2
285         exit 1
286     fi
287     for ((i=0; i<ndevs;i++)); do
288         str=(`split_hostname ${ost_names[$i]}`)
289         host_names[$i]=${str[0]}
290         ost_names[$i]=${str[1]}
291     done
292 fi
293
294 unique_hosts=(`unique ${host_names[@]}`)
295
296 for host in ${unique_hosts[@]}; do
297     remote_shell $host "echo 0 > /proc/sys/portals/debug"
298     do_unload_obdecho[$host]=0
299     if check_obdecho $host; then
300         continue
301     fi
302     load_obdecho $host
303     if check_obdecho $host; then
304         do_unload_obdecho[$host]=1
305         continue
306     fi
307     echo "Can't load obdecho on $host" 1>&2
308     exit 1
309 done
310
311 for ((i=0; i<ndevs; i++)); do
312     host=${host_names[$i]}
313     devno=(`get_ec_devno $host "${client_names[$i]}" "${ost_names[$i]}"`)
314     if ((${#devno[@]} != 3)); then
315         exit 1
316     fi
317     devnos[$i]=${devno[0]}
318     client_names[$i]=${devno[1]}
319     do_teardown_ec[$i]=${devno[2]}
320 done
321
322 for ((rsz=$rszlo;rsz<=$rszhi;rsz*=2)); do
323     for ((nobj=$nobjlo;nobj<=$nobjhi;nobj*=2)); do 
324         for ((thr=$thrlo;thr<=$thrhi;thr*=2)); do
325             if ((thr < nobj)); then
326                 continue
327             fi
328             # restart?
329             if [ -n "$restart_rsz" -a\
330                  -n "$restart_nobj" -a\
331                  -n "$restart_thr" ]; then
332                 if ((rsz < restart_rsz ||\
333                      (rsz == restart_rsz &&\
334                       (nobj < restart_nobj ||\
335                        (nobj == restart_nobj &&\
336                         thr < restart_thr))))); then
337                     continue;
338                 fi
339             fi
340             # compute parameters
341             total_thr=$((ndevs*thr))
342             total_nobj=$((ndevs*nobj))
343             pages=$((rsz/PAGE_SIZE))
344             actual_rsz=$((pages*PAGE_SIZE))
345             count=$((size*1024/(actual_rsz*thr)))
346             actual_size=$((actual_rsz*count*thr))
347             total_size=$((actual_size*ndevs))
348             # show computed parameters
349             str=`printf 'ost %2d sz %8dK rsz %4d obj %4d thr %4d ' \
350                      $ndevs $total_size $actual_rsz $total_nobj $total_thr`
351             echo "=======================> $str" >> $workf
352             print_summary -n "$str"
353             if ((total_thr * actual_rsz > max_buffer_mem)); then
354                 print_summary "Too much buffer space"
355                 continue
356             fi
357             # create the objects
358             tmpf="${workf}_tmp"
359             for ((idx=0; idx < ndevs; idx++)); do
360                 host=${host_names[$idx]}
361                 devno=${devnos[$idx]}
362                 client_name="${host}:${client_names[$idx]}"
363                 echo "=============> Create $nobj on $client_name" >> $workf
364                 first_obj=`create_objects $host $devno $nobj $tmpf`
365                 cat $tmpf >> $workf
366                 rm $tmpf
367                 if [ $first_obj = "ERROR" ]; then
368                     print_summary "created object #s on $client_name not contiguous"
369                     exit 1
370                 fi
371                 first_objs[$idx]=$first_obj
372             done
373             for test in write $tests; do
374                 print_summary -n "$test "
375                 for host in ${unique_hosts[@]}; do
376                     echo -n > ${cmdsf}_${host}
377                 done
378                 for ((idx=0; idx < ndevs; idx++)); do
379                     host=${host_names[$idx]}
380                     devno=${devnos[$idx]}
381                     tmpfi="${tmpf}_$idx"
382                     first_obj=${first_objs[$idx]}
383                     echo >> ${cmdsf}_${host} \
384                         "$lctl > $tmpfi 2>&1 \\
385                          --threads $thr -$snap $devno \\
386                          test_brw $count `testname2type $test` q $pages ${thr}t${first_obj} &"
387                 done
388                 for host in ${unique_hosts[@]}; do
389                     echo "wait" >> ${cmdsf}_${host}
390                 done
391                 t0=`date +%s.%N`
392                 for host in ${unique_hosts[@]}; do
393                     remote_shell $host bash ${cmdsf}_${host}&
394                 done
395                 wait
396                 t1=`date +%s.%N`
397                 for host in ${unique_hosts[@]}; do
398                     rm ${cmdsf}_${host}
399                 done
400                 str=`awk "BEGIN {printf \"%7.2f \",\
401                          $total_size / (( $t1 - $t0 ) * 1024)}"`
402                 print_summary -n "$str"
403                 echo -n > $tmpf
404                 for ((idx=0; idx < ndevs; idx++)); do
405                     client_name="${host_names[$idx]}:${client_names[$idx]}"
406                     tmpfi="${tmpf}_$idx"
407                     echo "=============> $test $client_name" >> $workf
408                     cat $tmpfi >> $workf
409                     get_stats $tmpfi >> $tmpf
410                     rm $tmpfi
411                 done
412                 echo "=============> $test global" >> $workf
413                 cat $tmpf >> $workf
414                 stats=(`get_global_stats $tmpf`)
415                 rm $tmpf
416                 if ((stats[0] <= 0)); then
417                     if ((stats[0] < 0)); then
418                         str=`printf "%17s " ERROR`
419                     else
420                         str=`printf "%17s " SHORT`
421                     fi
422                 else
423                     str=`awk "BEGIN {printf \"[%7.2f,%7.2f] \",\
424                              (${stats[1]} * $actual_rsz)/1024,\
425                              (${stats[2]} * $actual_rsz)/1024; exit}"`
426                 fi
427                 print_summary -n "$str"
428             done
429             print_summary ""
430             for ((idx=0; idx < ndevs; idx++)); do
431                 host=${host_names[$idx]}
432                 devno=${devnos[$idx]}
433                 client_name="${host}:${client_names[$idx]}"
434                 first_obj=${first_objs[$idx]}
435                 echo "=============> Destroy $nobj on $client_name" >> $workf
436                 destroy_objects $host $devno $first_obj $nobj $tmpf
437                 cat $tmpf >> $workf
438                 rm $tmpf
439             done
440         done
441     done
442 done
443
444 for ((i=0; i<ndevs; i++)); do
445     host=${host_names[$i]}
446     if ((${do_teardown_ec[$i]})); then
447         teardown_ec_devno $host ${client_names[$i]}
448     fi
449 done
450
451 for host in ${unique_hosts[@]}; do
452     if ((${do_unload_obdecho[$host]})); then
453         unload_obdecho $host
454     fi
455 done