2 * direct disk operation exerciser
4 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
29 #include <sys/ioctl.h>
38 static int io_size = 512; /* bytes */
39 static int sequential = 1; /* 0 for random, 1 for sequential */
40 static unsigned long long range = 2; /* megabytes */
41 static char filename[256] = "/dev/sdb";
42 static int depth = 32;
43 static int total_run = 15000;
44 static int display_stats = 0;
45 static int writing = 0;
48 struct iocb *iocbs[MAX_DEPTH];
49 struct io_event *events;
51 struct drand48_data random_state;
52 static unsigned long long next_block;
53 static unsigned long long blocks_done;
54 static unsigned long long nr_blocks;
56 #define ALIGN(buf) (((unsigned long) (buf) + (io_size-1)) & ~((io_size-1)))
58 unsigned long long get_next_offset(void)
60 unsigned long long block;
64 if (next_block >= nr_blocks)
68 next_block += (256 * 1024 / io_size);
72 lrand48_r(&random_state, &r);
73 block = (1 + (double) (nr_blocks) * (unsigned long long) r / (RAND_MAX+1.0));
77 void init_randomizer(void)
79 unsigned long seed = 0;
84 srand48_r(seed, &random_state);
87 unsigned long time_elapsed(struct timeval *start, struct timeval *end)
89 int seconds = end->tv_sec - start->tv_sec;
90 int useconds = end->tv_usec - start->tv_usec;
92 return (1000 * seconds) + (useconds / 1000);
95 void do_io(io_context_t io_ctx, int fd, char *buffer)
97 struct timeval real_start, start, end;
98 int i, ret, cur_depth;
99 unsigned long ops, best_ops;
100 unsigned long bytes, best_bytes;
102 for (i = 0; i < depth; i++) {
103 struct iocb *io = iocbs[i];
104 char *b = buffer + i * io_size;
105 unsigned long long off = get_next_offset();
106 unsigned long long offset = off * io_size;
109 io_prep_pwrite(io, fd, b, io_size, offset);
111 io_prep_pread(io, fd, b, io_size, offset);
114 ret = io_submit(io_ctx, depth, iocbs);
116 fprintf(stderr, "io_submit: %d\n", ret);
121 gettimeofday(&start, NULL);
122 gettimeofday(&real_start, NULL);
124 best_bytes = best_ops = bytes = ops = 0;
126 struct timespec ts = { .tv_sec = 30, .tv_nsec = 0 };
127 unsigned long elapsed;
129 ret = io_getevents(io_ctx, 1, cur_depth, events, &ts);
134 fprintf(stderr, "io_getevents: %d\n", ret);
137 fprintf(stderr, "No events completed, depth %d\n", cur_depth);
143 ops += (ret * (io_size >> 9));
144 bytes += (ret * io_size);
147 gettimeofday(&end, NULL);
149 elapsed = time_elapsed(&start, &end);
150 if (elapsed >= 1000) {
151 unsigned long kb = bytes >> 10;
154 o = ops * 1000 / elapsed;
155 b = kb * 1000 / elapsed;
158 printf("stat: ops/sec = %8lu, KiB/sec = %8lu (depth=%2d)\n", o, b, cur_depth);
165 gettimeofday(&start, NULL);
169 elapsed = time_elapsed(&real_start, &end);
170 if (total_run && (elapsed >= total_run)) {
171 printf("OPS_SEC=%'lu RATE=%'lu\n",best_ops, best_bytes);
176 for (i = 0; i < ret; i++) {
177 struct io_event *ev = events + i;
178 struct iocb *io = ev->obj;
179 unsigned long long offset = get_next_offset();
185 io_prep_pwrite(io, fd, io->u.c.buf, io_size, offset);
187 io_prep_pread(io, fd, io->u.c.buf, io_size, offset);
189 err = io_submit(io_ctx, 1, &io);
191 fprintf(stderr, "io_submit: %d\n", err);
202 io_getevents(io_ctx, cur_depth, cur_depth, events, NULL);
205 int parse_options(int argc, char **argv)
207 static struct option longoptions[] = {
208 { "device", 1, NULL, 'd' },
209 { "area", 1, NULL, 'a' },
210 { "random", 0, NULL, 'r' },
211 { "blocks", 1, NULL, 'b' },
212 { "queue depth",1, NULL, 'q' },
213 { "time", 1, NULL, 't' },
214 { "stats", 1, NULL, 's' },
215 { "write", 0, NULL, 'w' },
216 { "force", 0, NULL, 'w' },
221 c = getopt_long(argc, argv, "d:a:rb:q:t:swf", longoptions,&res);
227 strncpy(filename, optarg, sizeof(filename)-1);
230 range = atoi(optarg);
236 io_size = atoi(optarg) * 512;
239 depth = atoi(optarg);
240 if (depth <= 0 || depth > MAX_DEPTH) {
241 fprintf(stderr, "queue depth out-of-range %d\n", depth);
246 total_run = atoi(optarg) * 1000;
248 fprintf(stderr, "bad runtime\n");
264 printf("Dev=%s, %s, a=%LuMiB, %s, b=%u, q=%u, t=%u\n", filename, writing ? "write" : "read", range, sequential ? "sequential" : "random", io_size / 512, depth, total_run / 1000);
268 unsigned long get_size(int fd)
270 unsigned long long blocks;
273 if (fstat(fd, &sb) == -1) {
278 if (S_ISBLK(sb.st_mode)) {
280 * be a little cautious about writing to a device. if
281 * the user didn't use -f for force, ask for confirmation
283 if (writing && !force) {
284 printf("Writing directly to block device, are you sure? CTRL-C to cancel now\n");
287 if (ioctl(fd, BLKGETSIZE64, &blocks) == -1) {
288 perror("BLKGETSIZE64");
291 return blocks >> 20ULL;
292 } else if (S_ISREG(sb.st_mode))
293 return sb.st_size >> 20ULL;
295 fprintf(stderr, "Bad file type (must be file or block device)\n");
299 int main(int argc, char *argv[])
302 io_context_t *io_ctx;
306 if (parse_options(argc, argv))
310 fd = open(filename, O_WRONLY | O_DIRECT);
312 fd = open(filename, O_RDONLY | O_DIRECT);
323 if (!range || (range > mb))
326 nr_blocks = (range << 20ULL) / (unsigned long long) io_size;
328 printf("nr_blocks=%Lu (size=%u)\n", nr_blocks, io_size);
330 io_ctx = malloc(sizeof(*io_ctx));
332 i = io_queue_init(depth, io_ctx);
334 fprintf(stderr, "io_queue_init: %d\n", i);
340 orig = malloc((depth + 1) * io_size);
341 buffer = (char *) ALIGN(orig);
343 for (i = 0; i < depth; i++)
344 iocbs[i] = malloc(sizeof(struct iocb));
346 setlocale(LC_NUMERIC, "en_US");
348 events = malloc(depth * sizeof(struct io_event));
350 do_io(*io_ctx, fd, buffer);
354 for (i = 0; i < depth; i++)