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