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