Whamcloud - gitweb
LU-14585 tests: use striped ha_test_dir
[fs/lustre-release.git] / lustre-iokit / ost-survey / ost-survey
1 #!/usr/bin/perl
2 # This script is to be run on a client machine and will test all the
3 # OSTs to determine which is the fastest and slowest
4 # The current test method is as follows:
5 #   -Create a directory for each OST
6 #   -Use 'lfs setstripe' to set the Lustre striping such that IO goes to
7 #     only one OST
8 #   -Use 'dd' to write and read a file of a specified size
9 #   -Compute the average, and Standard deviation 
10 #   -Find the slowest OST for read and write
11 #   -Find the Fastest OST for read and write
12
13 # GLOBALS
14 $pname = $0;                     # to hold program name
15 $OSTS = 0;                       # Number of OSTS we will loop over
16 $BSIZE = 1024 * 1024;            # Size of i/o block
17 $MBSIZE = 1024 * 1024;           # One MB
18 $MNT = "/mnt/lustre";            # Location of Lustre file system
19 $CACHESZ = 0;                    # max_cached_mb parameter
20 $FSIZE = 30;                     # Number of i/o blocks
21
22 # Usage
23 sub usage () {
24         print "Usage: $pname [-s <size>] [-h] <Lustre_Path>\n";
25         print "[OPTIONS]\n";
26         print "  -s: size of test file in MB (default $FSIZE MB)\n";
27         print "  -h: To display this help\n";
28         print "example : $pname /mnt/lustre\n";
29         exit 1;
30 }
31
32 # ost_count subroutine sets global variable $OST with number of OSTs
33 # Also fills 1 for active OST indexes in ACTIVEOST_INX array.
34 sub ost_count () {
35         $OSTS = `lctl get_param -n lov.$FSNAME-clilov-*.activeobd`;
36         if ( $? ) {
37                 die "Read lov.*-clilov-$FSNAME.activeobd error: $?\n";
38         }
39         print "Number of Active OST devices : $OSTS";
40
41         $numost = `lctl get_param -n lov.$FSNAME-clilov-*.numobd`;
42         if ( $? ) {
43                 die "Read lov.$FSNAME-clilov-*.numobd error: $?\n";
44         }
45
46         if ( $numost != $OSTS ) {
47                 printf "Number of non active ots(s): %d\n", ( $numost - $OSTS );
48                 $OSTS = $numost;
49         }
50
51         $targets = `lctl get_param -n lov.$FSNAME-clilov-*.target_obd`;
52         if ( $? ) {
53                 die "Read lov.$FSNAME-clilov-*.target_obd error: $?\n";
54         }
55
56         my $count = 0;
57         foreach $line (split /\n/, $targets) {
58                 my ($ost_num, $ost_name, $ost_status) = split(/\s+/, $line);
59                 if ( $ost_status eq "ACTIVE" ) {
60                         $ACTIVEOST_INX[$count] = 1;
61                 }
62                 $count++;
63         }
64 }
65
66 # cache_mod subroutine sets global variable $CACHESZ and sets max_cached_mb
67 # to 256 * system page size in MB.
68 sub cache_mod () {
69         use POSIX qw(sysconf _SC_PAGESIZE);
70         $CACHESZ = `lctl get_param -n llite.$FSNAME-*.max_cached_mb`;
71         if ( $? ) {
72                 die "Read llite.$FSNAME-*.max_cached_mb error: $?\n";
73         }
74
75         $CACHESZ = `echo "$CACHESZ" | grep max_cached_mb | awk '{print \$2}'`;
76         my $pagesize = sysconf(_SC_PAGESIZE);
77         $req_cache_mb = ($pagesize * 256)/ $MBSIZE;
78
79         system("lctl set_param -n llite.$FSNAME-*.max_cached_mb=$req_cache_mb");
80         if ( $? ) {
81                 die "Set llite.$FSNAME-*.max_cached_mb error: $?\n";
82         }
83 }
84
85 # cache_return subroutine returns max_cached_mb to original value
86 sub cache_return () {
87         system("lctl set_param -n llite.$FSNAME-*.max_cached_mb=$CACHESZ");
88 }
89
90 # make_dummy subroutine creates a dummy file that will be used for read operation.
91 sub make_dummy () {
92         my $SIZE = $_[0];
93         my $tempfile = $_[1];
94         system ("dd of=$tempfile if=/dev/zero count=$SIZE bs=$BSIZE 2> /dev/null");
95 }
96
97 # run_test subroutine actually writes and reads data to/from dummy file
98 # and computes corresponding time taken for read and write operation and
99 # byte transfer for the both operations.
100 # This subroutine also fill corresponding global arrays with above information.
101 sub run_test () {
102         my $SIZE = $_[0];
103         my $INX=$_[1];
104         my $ACTION=$_[2];
105         my $tempfile = $_[3];
106
107         if ( !(-f $tempfile) && $ACTION eq "read" ) {
108                 &make_dummy($SIZE, $tempfile);
109         }
110         system("sync");
111         my ($ts0, $tu0) = gettimeofday();
112         $tu0 = $ts0 + ($tu0 / 1000000);
113         if ( $ACTION eq "write" ) {
114                 system("dd of=$tempfile if=/dev/zero count=$SIZE bs=$BSIZE 2> /dev/null");
115         } elsif ( $ACTION eq "read" ) {
116                 system("dd if=$tempfile of=/dev/null count=$SIZE bs=$BSIZE 2> /dev/null");
117         } else {
118                 print "Action is neither read nor write\n";
119                 exit 1;
120         }
121         system("sync");
122         my ($ts1, $tu1) = gettimeofday();
123         $tu1 = $ts1 + ($tu1/1000000);
124         my $tdelta = $tu1 - $tu0;
125         my $delta = ($SIZE * $BSIZE / ( $tu1 - $tu0 )) / (1024 * 1024);
126         if ( $ACTION eq "write" ) {
127                 $wTime[$INX] = $tdelta;
128                 $wMBs[$INX] = $delta;
129         } else {
130                 $rTime[$INX] = $tdelta;
131                 $rMBs[$INX] = $delta;
132         }
133 }
134
135 # calculate subroutine compute following things and displays them.
136 #  - Finds worst and best OST for both read and write operations.
137 #  - Compute average of read and write rate from all OSTS
138 #  - Compute Standard deviation for read and write form all OST's
139 sub calculate () {
140         my ($op, $MBs);
141         $op = $_[0];
142         @MBs = @_[1..$#_]; 
143         my $count = 0;
144         my $total = 0;
145         my $avg = 0;
146         my $sd = 0;
147         my $best_OST = 0;
148         my $worst_OST = 0;
149         my $max_mb = 0;
150         my $min_mb = 999999999;
151         while ($count < $OSTS ) {
152                 if ( $ACTIVEOST_INX[$count] ) {
153                         $total = $total + $MBs[$count];
154                         if ($max_mb < $MBs[$count] ) {
155                                 $max_mb = $MBs[$count];
156                                 $best_OST = $count; 
157                         }
158                         if ($min_mb > $MBs[$count] ) {
159                                 $min_mb = $MBs[$count];
160                                 $worst_OST = $count; 
161                         }
162                 }
163                 $count++;
164         }
165         $avg = $total/$OSTS;
166         $total = 0;
167         $count = 0;
168         while ($count < $OSTS ) {
169                 if ( $ACTIVEOST_INX[$count] ) {
170                         $total = $total + ($MBs[$count] - $avg) * ($MBs[$count] - $avg);
171                 }
172                 $count++;
173         }
174         $sd = sqrt($total/$OSTS);
175         printf "Worst  %s OST indx: %d speed: %f\n", $op, $worst_OST, $min_mb;
176         printf "Best   %s OST indx: %d speed: %f\n", $op, $best_OST, $max_mb;
177         printf "%s Average: %f +/- %f MB/s\n", $op, $avg, $sd;
178 }
179
180 # output_all_data subroutine displays speed and time information 
181 # for all OST's for both read and write operations.
182 sub output_all_data () {
183         my $count = 0;
184         print "Ost#  Read(MB/s)  Write(MB/s)  Read-time  Write-time\n";
185         print "----------------------------------------------------\n";
186         while ( $count < $OSTS ) {
187                 if ( $ACTIVEOST_INX[$count] ) {
188                         printf "%d     %.3f       %.3f        %.3f      %.3f\n",$count, 
189                         $rMBs[$count], $wMBs[$count], $rTime[$count], $wTime[$count];
190                 } else {
191                         printf "%d     Inactive ost\n",$count;
192                 }
193                 $count = $count + 1;
194         }
195 }
196
197 @rTime = ();
198 @wTime = ();
199 @rMBs = ();
200 @wMBs = ();
201 @ACTIVEOST_INX;
202
203 # Locals
204 my $filename = "";
205 my $dirpath = "";
206 my $flag = 0;
207
208 # Check number of arguments
209 my $numargs = $#ARGV + 1;
210 usage() if $numargs < 1;
211
212 # Command line parameter parsing
213 use Getopt::Std;
214 getopts('s:h') or usage();
215 usage() if $opt_h;
216 $FSIZE = $opt_s if $opt_s;
217
218 my $i = 0;
219 foreach (@ARGV) {
220         $MNT = $_;
221         $i++;
222         if ($i > 1) {
223                 print "ERROR: extra argument $_\n";
224                 usage();
225         }
226 }
227 #Check for Time::HiRes module
228 my $CheckTimeHiRes = "require Time::HiRes";
229 eval ($CheckTimeHiRes) or die "You need to install the perl-Time-HiRes package to use this script\n";
230 my $LoadTimeHiRes = "use Time::HiRes qw(gettimeofday)";
231 eval ($LoadTimeHiRes);
232
233 use POSIX qw(strftime);
234 my $time_v = time();
235 my $hostname = `lctl list_nids | head -1` or die "You need to install lctl to use this script\n";
236 chop($hostname);
237 print "$pname: ", strftime("%D", localtime($time_v));
238 print " OST speed survey on $MNT from $hostname\n";
239
240 # Get the file system name.
241 $FSNAME = `lfs getname $MNT`;
242 if ( $? ) {
243         die "`lfs getname $MNT` error: $?\n";
244 }
245 $FSNAME =~ /(.*)-/;
246 $FSNAME = $1;
247
248 # get OST count
249 ost_count ();
250 # Modify local cache
251 cache_mod ();
252
253 $dirpath = "$MNT/ost_survey_tmp";
254 eval { mkpath($dirpath) };
255 if ($@) {
256         print "Couldn't create $dirpath: $@";
257         exit 1;
258 }
259
260 use File::Path;
261 $CNT = 0;
262 while ($CNT < $OSTS) {
263         $filename = "$dirpath/file$CNT";
264         if ( $ACTIVEOST_INX[$CNT] ) {
265                 # set stripe for OST number $CNT
266                 system ("lfs setstripe -S 0 -i $CNT -c 1 $filename");
267                 # Perform write for OST number $CNT
268                 &run_test($FSIZE,$CNT,"write",$filename);
269                 $flag++;
270         }
271         $CNT = $CNT + 1;
272 }
273 $CNT = 0;
274 while ($CNT < $OSTS) {
275         $filename = "$dirpath/file$CNT";
276         if ( $ACTIVEOST_INX[$CNT] ) {
277                 # Perform read for OST number $CNT
278                 &run_test($FSIZE,$CNT,"read",$filename);
279                 $flag++;
280         }
281         $CNT = $CNT + 1;
282 }
283
284 # if read or write performed on any OST then display information.
285 if ( $flag ) {
286         if ( $flag > 1 ) {
287                 &calculate("Read",@rMBs);
288                 &calculate("Write",@wMBs);
289         }
290         output_all_data ();
291 } else {
292         print "There is no active OST's found\n";
293 }
294
295 # Return cache to original size
296 cache_return ();
297
298 eval { rmtree($dirpath) };
299 if ($@) {
300         print "Warning: Couldn't remove $dirpath: $@";
301 }