Whamcloud - gitweb
77ebeaaa568e72398b812fe6aebbd16362431dda
[fs/lustre-release.git] / lustre / tests / reads.c
1 /*
2  * Lustre Reads test
3  *
4  * Copyright (c) 2005 Cluster File Systems, Inc.
5  * Copyright (c) 2008 SUN Microsystems.
6  *
7  * Author: Nikita Danilov <nikita@clusterfs.com>
8  *
9  * This file is part of Lustre, http://www.lustre.org.
10  *
11  * Lustre is free software; you can redistribute it and/or modify it under the
12  * terms of version 2 of the GNU General Public License as published by the
13  * Free Software Foundation.
14  *
15  * Lustre is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with Lustre; if not, write to the Free Software Foundation, Inc., 675 Mass
22  * Ave, Cambridge, MA 02139, USA.
23  */
24
25 #define _XOPEN_SOURCE 500 /* for pread(2) */
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <sys/types.h>
36 #include <sys/time.h>
37
38 static void usage(void)
39 {
40         printf("reads: read random or stride chunks of a file.\n");
41         printf("Usage:\n\n");
42         printf("reads -f <filename> -s <filesize> -b <buffersize>"
43                "-a <adjacent reads> [-v] [-h] [-C] [-l <stride_length> ] "
44                "[ -o <stride_offset> ] [-S <seed>] [-n <iterations>]"
45                "[-w <width>] [-t <timelimit>]\n");
46 }
47
48 enum {
49         BSIZE_DEFAULT = 16 * 4096
50 };
51
52 #define LOG(level, ...)                         \
53 ({                                              \
54         if ((level) <= verbosity)               \
55                 fprintf(stderr, __VA_ARGS__);   \
56 })
57
58 enum {
59         LOG_CRIT,
60         LOG_WARN,
61         LOG_INFO,
62         LOG_DEBUG
63 };
64
65 enum {
66         RR_OK,
67         RR_PARSE,
68         RR_SET,
69         RR_MALLOC,
70         RR_OPEN,
71         RR_PRECLEAN,
72         RR_READ
73 };
74
75 int main(int argc, char **argv)
76 {
77         int    verbosity = LOG_CRIT;
78         char  *fname = NULL;
79         loff_t size = 0;
80         size_t bsize = 0;
81         int    ad = 1;
82         int    preclean = 0;
83         int    width = 10;
84         unsigned int seed = 0;
85         unsigned long iterations = 0;
86         unsigned long timelimit = 24 * 3600;
87         unsigned long stride_length = 0;
88         unsigned long stride_offset = 0;
89
90         int opt;
91         int fd;
92         unsigned long nblocks;
93         unsigned long i;
94         ssize_t  ret;
95
96         struct timeval start;
97         struct timeval stop;
98
99         double usecs;
100
101         char *buf;
102         char *term;
103
104         do {
105                 opt = getopt(argc, argv, "f:s:b:va:hCS:n:t:l:o:w:");
106                 switch (opt) {
107                 case -1:
108                         break;
109                 default:
110                         LOG(LOG_CRIT, "Unable to parse command line.\n");
111                 case 'h':
112                         usage();
113                         return RR_PARSE;
114                 case 'v':
115                         verbosity ++;
116                         break;
117                 case 'f':
118                         fname = strdup(optarg);
119                         break;
120                 case 's':
121                         size = strtol(optarg, &term, 0);
122                         if (term == optarg) {
123                                 fprintf (stderr, "Can't parse size %s\n", optarg);
124                                 usage();
125                                 return RR_SET;
126                         }
127                         break;
128                 case 'b':
129                         bsize = strtol(optarg, &term, 0);
130                         if (term == optarg) {
131                                 fprintf (stderr, "Can't parse bsize %s\n", optarg);
132                                 usage();
133                                 return RR_SET;
134                         }
135                         break;
136                 case 'a':
137                         ad = (int)strtol(optarg, &term, 0);
138                         if (term == optarg) {
139                                 fprintf (stderr, "Can't parse ad %s\n", optarg);
140                                 usage();
141                                 return RR_SET;
142                         }
143                         break;
144                 case 'C':
145                         preclean = 1;
146                         break;
147                 case 'S':
148                         seed = strtol(optarg, &term, 0);
149                         if (term == optarg) {
150                                 fprintf (stderr, "Can't parse seed %s\n", optarg);
151                                 usage();
152                                 return RR_SET;
153                         }
154                         break;
155                 case 'n':
156                         iterations = strtol(optarg, &term, 0);
157                         if (term == optarg) {
158                                 fprintf (stderr, "Can't parse seed %s\n", optarg);
159                                 usage();
160                                 return RR_SET;
161                         }
162                         break;
163
164                         break;
165                 case 't':
166                         timelimit = strtol(optarg, &term, 0);
167                         if (term == optarg) {
168                                 fprintf (stderr, "Can't parse seed %s\n", optarg);
169                                 usage();
170                                 return RR_SET;
171                         }
172                         break;
173                 case 'l':
174                         stride_length = strtol(optarg, &term, 0);
175                         if (term == optarg) {
176                                 fprintf (stderr, "Can't parse seed %s\n", optarg);
177                                 usage();
178                                 return RR_SET;
179                         }
180                         break;
181                 case 'o':
182                         stride_offset = strtol(optarg, &term, 0);
183                         if (term == optarg) {
184                                 fprintf (stderr, "Can't parse seed %s\n", optarg);
185                                 usage();
186                                 return RR_SET;
187                         }
188                         break;
189                 case 'w':
190                         width = (int)strtol(optarg, &term, 0);
191                         if (term == optarg) {
192                                 fprintf (stderr, "Can't parse seed %s\n", optarg);
193                                 usage();
194                                 return RR_SET;
195                         }
196                         break;
197                 }
198         } while (opt != -1);
199
200         if (fname == NULL || size == 0 || bsize == 0 || ad <= 0) {
201                 usage();
202                 return RR_SET;
203         }
204
205         bsize /= ad;
206         nblocks = size / bsize;
207         buf = malloc(bsize);
208         if (buf == NULL) {
209                 LOG(LOG_CRIT, "malloc(%lu) failure: %s\n", (long)bsize,
210                     strerror(errno));
211                 return RR_MALLOC;
212         }
213
214         fd = open(fname, (preclean ? O_RDWR : O_RDONLY) | O_CREAT, 0700);
215         if (fd == -1) {
216                 LOG(LOG_CRIT, "malloc(\"%s\") failure: %s\n", fname,
217                     strerror(errno));
218                 return RR_OPEN;
219         }
220         if (preclean) {
221                 loff_t towrite;
222                 size_t count;
223
224                 LOG(LOG_INFO, "precleaning");
225                 for (i = 0, towrite = size; towrite > 0; towrite -= ret) {
226                         count = bsize < towrite ? bsize : towrite;
227                         memset(buf, bsize, seed + i++);
228                         ret = write(fd, buf, count);
229                         if (ret < 0) {
230                                 LOG(LOG_CRIT, "write() failure: %s\n",
231                                     strerror(errno));
232                                 close(fd);
233                                 return RR_PRECLEAN;
234                         }
235                 }
236         }
237         if (seed != 0)
238                 srand(seed);
239         gettimeofday(&start, NULL);
240         timelimit += start.tv_sec;
241         for (i = 0; !iterations || i < iterations; i ++) {
242                 unsigned long block_nr;
243                 int j;
244
245                 if (stride_length) 
246                         block_nr = (unsigned long)(i*stride_length + 
247                                                    stride_offset) % nblocks;
248                 else
249                         block_nr = (unsigned long)((double)nblocks*rand()/
250                                                    (RAND_MAX+1.0));
251                 if (i % width == 0)
252                         LOG(LOG_INFO, "\n%9lu: ", i);
253                 LOG(LOG_INFO, "%7lu ", block_nr);
254                 for (j = 0; j < ad; j++) {
255                         ret = pread(fd, buf, bsize, (block_nr + j) * bsize);
256                         if (ret != bsize) {
257                                 LOG(LOG_CRIT,
258                                     "pread(...%zi, %li) got: %zi, %s\n", bsize,
259                                     block_nr * bsize, ret, strerror(errno));
260                                 close(fd);
261                                 return RR_READ;
262                         }
263                 }
264                 gettimeofday(&stop, NULL);
265                 if (stop.tv_sec > timelimit)
266                         break;
267         }
268         close(fd);
269         usecs = (stop.tv_sec - start.tv_sec) * 1000000. +
270                 stop.tv_usec - start.tv_usec;
271         printf("\n%fs, %gMB/s\n", usecs / 1000000.,
272                (double)bsize * ad * i / usecs);
273         return RR_OK;
274 }