Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <time.h>
36 : : #include <stdio.h>
37 : : #include <errno.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <inttypes.h>
41 : :
42 : : #include "io-optimize.h"
43 : : #include "tapdisk-log.h"
44 : :
45 : : #if (!defined(TEST) && defined(DEBUG))
46 : : #define DBG(ctx, f, a...) tlog_write(TLOG_DBG, f, ##a)
47 : : #elif defined(TEST)
48 : : #define DBG(ctx, f, a...) printf(f, ##a)
49 : : #else
50 : : #define DBG(ctx, f, a...) ((void)0)
51 : : #endif
52 : :
53 : : void
54 : 0 : opio_free(struct opioctx *ctx)
55 : : {
56 : 0 : free(ctx->opios);
57 : 0 : ctx->opios = NULL;
58 : :
59 : 0 : free(ctx->free_opios);
60 : 0 : ctx->free_opios = NULL;
61 : :
62 : 0 : free(ctx->iocb_queue);
63 : 0 : ctx->iocb_queue = NULL;
64 : :
65 : 0 : free(ctx->event_queue);
66 : 0 : ctx->event_queue = NULL;
67 : 0 : }
68 : :
69 : : int
70 : 0 : opio_init(struct opioctx *ctx, int num_iocbs)
71 : : {
72 : : int i;
73 : :
74 : : memset(ctx, 0, sizeof(struct opioctx));
75 : :
76 : 0 : ctx->num_opios = num_iocbs;
77 : 0 : ctx->free_opio_cnt = num_iocbs;
78 : 0 : ctx->opios = calloc(1, sizeof(struct opio) * num_iocbs);
79 : 0 : ctx->free_opios = calloc(1, sizeof(struct opio *) * num_iocbs);
80 : 0 : ctx->iocb_queue = calloc(1, sizeof(struct iocb *) * num_iocbs);
81 : 0 : ctx->event_queue = calloc(1, sizeof(struct io_event) * num_iocbs);
82 : :
83 [ # # ][ # # ]: 0 : if (!ctx->opios || !ctx->free_opios ||
[ # # ]
84 [ # # ]: 0 : !ctx->iocb_queue || !ctx->event_queue)
85 : : goto fail;
86 : :
87 [ # # ]: 0 : for (i = 0; i < num_iocbs; i++)
88 : 0 : ctx->free_opios[i] = &ctx->opios[i];
89 : :
90 : : return 0;
91 : :
92 : : fail:
93 : 0 : opio_free(ctx);
94 : 0 : return -ENOMEM;
95 : : }
96 : :
97 : : static inline struct opio *
98 : 0 : alloc_opio(struct opioctx *ctx)
99 : : {
100 [ # # ]: 0 : if (ctx->free_opio_cnt <= 0)
101 : : return NULL;
102 : 0 : return ctx->free_opios[--ctx->free_opio_cnt];
103 : : }
104 : :
105 : : static inline void
106 : 0 : free_opio(struct opioctx *ctx, struct opio *op)
107 : : {
108 : : memset(op, 0, sizeof(struct opio));
109 : 0 : ctx->free_opios[ctx->free_opio_cnt++] = op;
110 : 0 : }
111 : :
112 : : static inline void
113 : 0 : restore_iocb(struct opio *op)
114 : : {
115 : 0 : *op->iocb = op->orig_iocb;
116 : 0 : }
117 : :
118 : : static inline int
119 : 0 : iocb_optimized(struct opioctx *ctx, struct iocb *io)
120 : : {
121 : 0 : return iocb_vectorized(io->aio_lio_opcode) == io->aio_lio_opcode;
122 : : }
123 : :
124 : : static inline int
125 : 0 : contiguous_sectors(struct iocb *l, struct iocb *r)
126 : : {
127 : 0 : return (iocb_offset(l) + iocb_nbytes(l) == iocb_offset(r));
128 : : }
129 : :
130 : : static inline int
131 : : contiguous_iocbs(struct iocb *l, struct iocb *r)
132 : : {
133 [ # # # # ]: 0 : return ((l->aio_fildes == r->aio_fildes) &&
134 : 0 : contiguous_sectors(l, r));
135 : : }
136 : :
137 : : static inline void
138 : : init_opio_list(struct opio *op)
139 : : {
140 : 0 : op->list.head = op->list.tail = op;
141 : : }
142 : :
143 : : static struct opio *
144 : 0 : opio_iocb_init(struct opioctx *ctx, struct iocb *io)
145 : : {
146 : : struct opio *op;
147 : :
148 : 0 : op = alloc_opio(ctx);
149 [ # # ]: 0 : if (!op)
150 : : return NULL;
151 : :
152 : 0 : op->orig_iocb = *io;
153 : 0 : op->iocb = io;
154 : 0 : io->data = op;
155 : :
156 : : init_opio_list(op);
157 : :
158 : 0 : return op;
159 : : }
160 : :
161 : : static inline struct opio *
162 : 0 : opio_get(struct opioctx *ctx, struct iocb *io)
163 : : {
164 [ # # ]: 0 : if (iocb_optimized(ctx, io))
165 : 0 : return (struct opio *)io->data;
166 : : else
167 : 0 : return opio_iocb_init(ctx, io);
168 : : }
169 : :
170 : : static int
171 : 0 : merge_tail(struct opioctx *ctx, struct iocb *head, struct iocb *io)
172 : : {
173 : : struct opio *ophead, *opio;
174 : : struct iovec *iovec;
175 : :
176 : 0 : ophead = opio_get(ctx, head);
177 [ # # ]: 0 : if (!ophead)
178 : : return -ENOMEM;
179 : :
180 : 0 : opio = opio_get(ctx, io);
181 [ # # ]: 0 : if (!opio)
182 : : return -ENOMEM;
183 : :
184 : 0 : opio->head = ophead;
185 [ # # ]: 0 : if (!iocb_optimized(ctx, head)) {
186 : 0 : void *data = head->data;
187 : : /* convert PREAD/PWRITE into PREADV/PWRITEV with 1 element */
188 : 0 : iovec = &ophead->iov[0];
189 : 0 : iovec->iov_base = iocb_buf(head);
190 : 0 : iovec->iov_len = iocb_nbytes(head);
191 [ # # ]: 0 : ASSERT(iovec->iov_len > 0);
192 : :
193 [ # # # ]: 0 : switch(io->aio_lio_opcode) {
194 : : case IO_CMD_PREAD:
195 : 0 : io_prep_preadv(head, head->aio_fildes, iovec, 1, iocb_offset(head));
196 : : break;
197 : : case IO_CMD_PWRITE:
198 : 0 : io_prep_pwritev(head, head->aio_fildes, iovec, 1, iocb_offset(head));
199 : : break;
200 : : default:
201 : 0 : ASSERT(0);
202 : : }
203 : : /* prep above wipes this, restore it */
204 : 0 : head->data = data;
205 [ # # ]: 0 : ASSERT(head->data == ophead);
206 : : }
207 [ # # ]: 0 : ASSERT(iocb_optimized(ctx, head));
208 [ # # ]: 0 : ASSERT(head->u.v.nr < sizeof(ophead->iov)/sizeof(ophead->iov[0]));
209 : 0 : iovec = &ophead->iov[head->u.v.nr++];
210 : 0 : iovec->iov_base = iocb_buf(io);
211 : 0 : iovec->iov_len = iocb_nbytes(io);
212 : :
213 : 0 : ophead->list.tail = ophead->list.tail->next = opio;
214 : :
215 : 0 : return 0;
216 : : }
217 : :
218 : : static int
219 : 0 : merge(struct opioctx *ctx, struct iocb *head, struct iocb *io)
220 : : {
221 [ # # ]: 0 : if (iocb_vectorized(head->aio_lio_opcode) != iocb_vectorized(io->aio_lio_opcode))
222 : : return -EINVAL;
223 : :
224 [ # # ]: 0 : if (!contiguous_iocbs(head, io))
225 : : return -EINVAL;
226 : :
227 : : /* otherwise we overflow and overwrite other values in the record */
228 [ # # ][ # # ]: 0 : if(iocb_optimized(ctx, head) && head->u.v.nr == UIO_FASTIOV)
229 : : return -EINVAL;
230 : :
231 : 0 : return merge_tail(ctx, head, io);
232 : : }
233 : :
234 : : #if (defined(TEST) || defined(DEBUG))
235 : : /******************************************************************************
236 : : debug print functions
237 : : ******************************************************************************/
238 : : static inline void
239 : : __print_iocb(struct opioctx *ctx, struct iocb *io, char *prefix)
240 : : {
241 : : const void* buf = iocb_vectorized(io->aio_lio_opcode) == io->aio_lio_opcode ?
242 : : io->u.v.vec : iocb_buf(io);
243 : : DBG(ctx, "%soff: %08llx, nbytes: %04lx, buf: %p, type: %s, data: %08lx,"
244 : : " optimized: %d\n", prefix, iocb_offset(io), iocb_nbytes(io),
245 : : buf, iocb_opcode(io),
246 : : (unsigned long)io->data, iocb_optimized(ctx, io));
247 : : }
248 : :
249 : : #define print_iocb(ctx, io) __print_iocb(ctx, io, "")
250 : :
251 : : /******************************************************************************
252 : : end debug print functions
253 : : ******************************************************************************/
254 : :
255 : : static void
256 : : print_optimized_iocbs(struct opioctx *ctx, struct opio *op, int *cnt)
257 : : {
258 : : char pref[10];
259 : :
260 : : while (op) {
261 : : snprintf(pref, 10, " %d: ", (*cnt)++);
262 : : __print_iocb(ctx, op->iocb, pref);
263 : : op = op->next;
264 : : }
265 : : }
266 : :
267 : : static void
268 : : print_merged_iocbs(struct opioctx *ctx, struct iocb **iocbs, int num_iocbs)
269 : : {
270 : : int i, cnt;
271 : : char pref[10];
272 : : struct iocb *io;
273 : : struct opio *op;
274 : :
275 : : DBG(ctx, "merged iocbs:\n");
276 : : for (i = 0, cnt = 0; i < num_iocbs; i++) {
277 : : io = iocbs[i];
278 : : snprintf(pref, 10, "%d: ", cnt++);
279 : : __print_iocb(ctx, io, pref);
280 : :
281 : : if (iocb_optimized(ctx, io)) {
282 : : op = (struct opio *)io->data;
283 : : print_optimized_iocbs(ctx, op->next, &cnt);
284 : : }
285 : : }
286 : : }
287 : : #else
288 : : #define print_optimized_iocbs(...)
289 : : #define print_merged_iocbs(...)
290 : : #endif
291 : :
292 : : int
293 : 0 : io_merge(struct opioctx *ctx, struct iocb **queue, int num)
294 : : {
295 : : int i, on_queue;
296 : : struct iocb *io, **q;
297 : :
298 [ # # ]: 0 : if (!num)
299 : : return 0;
300 : :
301 : 0 : on_queue = 0;
302 : 0 : q = ctx->iocb_queue;
303 : 0 : memcpy(q, queue, num * sizeof(struct iocb *));
304 : :
305 [ # # ]: 0 : for (i = 1; i < num; i++) {
306 : 0 : io = q[i];
307 [ # # ]: 0 : if (merge(ctx, queue[on_queue], io) != 0)
308 : 0 : queue[++on_queue] = io;
309 : : }
310 : :
311 : : print_merged_iocbs(ctx, queue, on_queue + 1);
312 : :
313 : 0 : return ++on_queue;
314 : : }
315 : :
316 : : static int
317 : 0 : expand_iocb(struct opioctx *ctx, struct iocb **queue, struct iocb *io)
318 : : {
319 : : int idx;
320 : : struct opio *op, *next;
321 : :
322 : 0 : idx = 0;
323 : 0 : op = (struct opio *)io->data;
324 [ # # ]: 0 : while (op) {
325 : 0 : next = op->next;
326 : 0 : restore_iocb(op);
327 : 0 : queue[idx++] = op->iocb;
328 : 0 : free_opio(ctx, op);
329 : 0 : op = next;
330 : : }
331 : :
332 : 0 : return idx;
333 : : }
334 : :
335 : : int
336 : 0 : io_expand_iocbs(struct opioctx *ctx, struct iocb **queue, int idx, int num)
337 : : {
338 : : int i, on_queue;
339 : 0 : struct iocb *io, **q;
340 : :
341 [ # # ]: 0 : if (!num)
342 : : return 0;
343 : :
344 : 0 : on_queue = 0;
345 : 0 : q = ctx->iocb_queue;
346 : 0 : memcpy(q, queue, num * sizeof(struct iocb *));
347 : :
348 [ # # ]: 0 : for (i = idx; i < num; i++) {
349 : 0 : io = q[i];
350 [ # # ]: 0 : if (!iocb_optimized(ctx, io))
351 : 0 : queue[on_queue++] = io;
352 : : else
353 : 0 : on_queue += expand_iocb(ctx, queue + on_queue, io);
354 : : }
355 : :
356 : : return on_queue;
357 : : }
358 : :
359 : : static int
360 : 0 : expand_event(struct opioctx *ctx,
361 : : struct io_event *event, struct io_event *queue, int idx)
362 : : {
363 : : int err;
364 : : struct iocb *io;
365 : : struct io_event *ep;
366 : : struct opio *ophead, *op, *next;
367 : :
368 : 0 : io = event->obj;
369 : 0 : ophead = (struct opio *)io->data;
370 : 0 : op = ophead;
371 : :
372 [ # # ]: 0 : if (event->res == iocb_nbytes(io))
373 : : err = 0;
374 [ # # ]: 0 : else if ((int)event->res < 0)
375 : 0 : err = (int)event->res;
376 : : else
377 : : err = -EIO;
378 : :
379 [ # # ]: 0 : while (op) {
380 : 0 : next = op->next;
381 : 0 : ep = &queue[idx++];
382 : 0 : ep->obj = op->iocb;
383 [ # # ]: 0 : ep->res = (err ? err : iocb_nbytes(&op->orig_iocb));
384 : 0 : restore_iocb(op);
385 : 0 : free_opio(ctx, op);
386 : 0 : op = next;
387 : : }
388 : :
389 : 0 : return idx;
390 : : }
391 : :
392 : : int
393 : 0 : io_split(struct opioctx *ctx, struct io_event *events, int num)
394 : : {
395 : : int on_queue;
396 : 0 : struct iocb *io;
397 : : struct io_event *ep, *q;
398 : :
399 [ # # ]: 0 : if (!num)
400 : : return 0;
401 : :
402 : 0 : on_queue = 0;
403 : 0 : q = ctx->event_queue;
404 : 0 : memcpy(q, events, num * sizeof(struct io_event));
405 : :
406 [ # # ]: 0 : for (ep = q; num-- > 0; ep++) {
407 : 0 : io = ep->obj;
408 [ # # ]: 0 : if (!iocb_optimized(ctx, io))
409 : 0 : events[on_queue++] = *ep;
410 : : else
411 : 0 : on_queue = expand_event(ctx, ep, events, on_queue);
412 : : }
413 : :
414 : : return on_queue;
415 : : }
416 : :
417 : : #if defined(TEST)
418 : :
419 : : #define hmask 0x80000000UL
420 : : #define smask 0x40000000UL
421 : : #define make_data(idx, is_head, sparse) \
422 : : (void *)((idx) | ((is_head) ? hmask : 0) | ((sparse) ? smask : 0))
423 : : #define data_idx(data) (int)((unsigned long)(data) & (0x0fffffff))
424 : : #define data_is_head(data) (((unsigned long)(data) & hmask) ? 1 : 0)
425 : : #define data_is_sparse(data) (((unsigned long)(data) & smask) ? 1 : 0)
426 : :
427 : : static void
428 : : usage(void)
429 : : {
430 : : fprintf(stderr, "usage: io_optimize [-n num_runs] "
431 : : "[-i num_iocbs] [-s num_secs] [-r random_seed]\n");
432 : : exit(-1);
433 : : }
434 : :
435 : : static int xalloc_cnt, xfree_cnt;
436 : : static inline char *
437 : : xalloc(int size)
438 : : {
439 : : char *buf = malloc(size);
440 : : if (!buf) {
441 : : fprintf(stderr, "xalloc failed\n");
442 : : exit(ENOMEM);
443 : : }
444 : : xalloc_cnt++;
445 : : return buf;
446 : : }
447 : :
448 : : static inline void
449 : : xfree(void *buf)
450 : : {
451 : : free(buf);
452 : : xfree_cnt++;
453 : : }
454 : :
455 : : static void
456 : : randomize_iocbs(struct iocb **iocbs, int num_iocbs, int num_secs)
457 : : {
458 : : int i, j;
459 : :
460 : : i = 0;
461 : : while (i < num_iocbs) {
462 : : char *buf;
463 : : short type;
464 : : int segs, sparse_mem;
465 : : uint64_t offset, nbytes;
466 : :
467 : : type = (random() % 10 < 5 ? IO_CMD_PREAD : IO_CMD_PWRITE);
468 : : offset = ((random() % num_secs) << 9);
469 : :
470 : : if (random() % 10 < 4) {
471 : : segs = 1;
472 : : nbytes = (((random() % 7) + 1) << 9);
473 : : } else {
474 : : segs = (random() % 10) + 1;
475 : : nbytes = 4096;
476 : : }
477 : :
478 : : if (i + segs > num_iocbs)
479 : : segs = (num_iocbs - i);
480 : :
481 : : sparse_mem = (random() % 10 < 2 ? 1 : 0);
482 : :
483 : : if (sparse_mem)
484 : : buf = xalloc(nbytes);
485 : : else
486 : : buf = xalloc(segs * nbytes);
487 : :
488 : : for (j = 0; j < segs; j++) {
489 : : struct iocb *io = iocbs[i + j];
490 : : io->aio_lio_opcode = type;
491 : : io->u.c.nbytes = nbytes;
492 : : io->u.c.offset = offset;
493 : : io->u.c.buf = buf;
494 : : offset += nbytes;
495 : :
496 : : io->data = make_data(i + j, (j == 0), sparse_mem);
497 : :
498 : : if (j + 1 < segs && sparse_mem)
499 : : buf = xalloc(nbytes);
500 : : else
501 : : buf += nbytes;
502 : : }
503 : :
504 : : i += segs;
505 : : }
506 : : }
507 : :
508 : : static int
509 : : simulate_io(struct iocb **iocbs, struct io_event *events, int num_iocbs)
510 : : {
511 : : int i, done;
512 : : struct iocb *io;
513 : : struct io_event *ep;
514 : :
515 : : if (num_iocbs > 1)
516 : : done = (random() % (num_iocbs - 1)) + 1;
517 : : else
518 : : done = num_iocbs;
519 : :
520 : : for (i = 0; i < done; i++) {
521 : : io = iocbs[i];
522 : : ep = &events[i];
523 : : ep->obj = io;
524 : : ep->res = (random() % 10 < 8 ? iocb_nbytes(io) : 0);
525 : : }
526 : :
527 : : return done;
528 : : }
529 : :
530 : : static inline void
531 : : process_events(struct opioctx *ctx,
532 : : struct iocb *iocb_list, struct io_event *events, int num)
533 : : {
534 : : int i;
535 : : struct iocb *io;
536 : :
537 : : for (i = 0; i < num; i++) {
538 : : io = events[i].obj;
539 : : print_iocb(ctx, io);
540 : : if (data_idx(io->data) != (io - iocb_list)) {
541 : : printf("corrupt data! data_idx = %d, io = %ld\n",
542 : : data_idx(io->data), (io - iocb_list));
543 : : exit(-1);
544 : : }
545 : : if (data_is_head(io->data) || data_is_sparse(io->data))
546 : : xfree(iocb_buf(io));
547 : : memset(io, 0, sizeof(struct iocb));
548 : : }
549 : : }
550 : :
551 : : static inline void
552 : : init_optest(struct iocb *iocb_list,
553 : : struct iocb **iocbs, struct io_event *events, int num)
554 : : {
555 : : int i;
556 : :
557 : : memset(iocb_list, 0, num * sizeof(struct iocb));
558 : : memset(events, 0, num * sizeof(struct io_event));
559 : :
560 : : for (i = 0; i < num; i++)
561 : : iocbs[i] = &iocb_list[i];
562 : : }
563 : :
564 : : static void
565 : : print_iocbs(struct opioctx *ctx, struct iocb **iocbs, int num_iocbs)
566 : : {
567 : : int i;
568 : : char pref[10];
569 : : struct iocb *io;
570 : :
571 : : DBG(ctx, "iocbs:\n");
572 : : for (i = 0; i < num_iocbs; i++) {
573 : : io = iocbs[i];
574 : : snprintf(pref, 10, "%d: ", i);
575 : : __print_iocb(ctx, io, pref);
576 : : }
577 : : }
578 : :
579 : : static void
580 : : print_events(struct opioctx *ctx, struct io_event *events, int num_events)
581 : : {
582 : : int i;
583 : : struct iocb *io;
584 : :
585 : : for (i = 0; i < num_events; i++) {
586 : : io = events[i].obj;
587 : : print_iocb(ctx, io);
588 : : }
589 : : }
590 : :
591 : : int
592 : : main(int argc, char **argv)
593 : : {
594 : : uint64_t num_secs;
595 : : struct opioctx ctx;
596 : : struct io_event *events;
597 : : int i, c, num_runs, num_iocbs, seed;
598 : : struct iocb *iocb_list, **iocbs, **ioqueue;
599 : :
600 : : num_runs = 1;
601 : : num_iocbs = 300;
602 : : seed = time(NULL);
603 : : num_secs = ((4ULL << 20) >> 9); /* 4GB disk */
604 : :
605 : : while ((c = getopt(argc, argv, "n:i:s:r:h")) != -1) {
606 : : switch (c) {
607 : : case 'n':
608 : : num_runs = atoi(optarg);
609 : : break;
610 : : case 'i':
611 : : num_iocbs = atoi(optarg);
612 : : break;
613 : : case 's':
614 : : num_secs = strtoull(optarg, NULL, 10);
615 : : break;
616 : : case 'r':
617 : : seed = atoi(optarg);
618 : : break;
619 : : case 'h':
620 : : usage();
621 : : case '?':
622 : : fprintf(stderr, "Unrecognized option: -%c\n", optopt);
623 : : usage();
624 : : }
625 : : }
626 : :
627 : : printf("Running %d tests with %d iocbs on %lu sectors, seed = %d\n",
628 : : num_runs, num_iocbs, num_secs, seed);
629 : :
630 : : srand(seed);
631 : :
632 : : iocb_list = malloc(num_iocbs * sizeof(struct iocb));
633 : : iocbs = malloc(num_iocbs * sizeof(struct iocb *));
634 : : events = malloc(num_iocbs * sizeof(struct io_event));
635 : :
636 : : if (!iocb_list || !iocbs || !events || opio_init(&ctx, num_iocbs)) {
637 : : fprintf(stderr, "initialization failed\n");
638 : : exit(ENOMEM);
639 : : }
640 : :
641 : : for (i = 0; i < num_runs; i++) {
642 : : int op_rem, op_done, num_split, num_events, num_done;
643 : :
644 : : ioqueue = iocbs;
645 : : init_optest(iocb_list, ioqueue, events, num_iocbs);
646 : : randomize_iocbs(ioqueue, num_iocbs, num_secs);
647 : : print_iocbs(&ctx, ioqueue, num_iocbs);
648 : :
649 : : op_done = 0;
650 : : num_done = 0;
651 : : op_rem = io_merge(&ctx, ioqueue, num_iocbs);
652 : : print_iocbs(&ctx, ioqueue, op_rem);
653 : : print_merged_iocbs(&ctx, ioqueue, op_rem);
654 : :
655 : : while (num_done < num_iocbs) {
656 : : DBG(&ctx, "optimized remaining: %d\n", op_rem);
657 : :
658 : : DBG(&ctx, "simulating\n");
659 : : num_events = simulate_io(ioqueue + op_done, events, op_rem);
660 : : print_events(&ctx, events, num_events);
661 : :
662 : : DBG(&ctx, "splitting %d\n", num_events);
663 : : num_split = io_split(&ctx, events, num_events);
664 : : print_events(&ctx, events, num_split);
665 : :
666 : : DBG(&ctx, "processing %d\n", num_split);
667 : : process_events(&ctx, iocb_list, events, num_split);
668 : :
669 : : op_rem -= num_events;
670 : : op_done += num_events;
671 : : num_done += num_split;
672 : : }
673 : :
674 : : DBG(&ctx, "run %d: processed: %d, xallocs: %d, xfrees: %d\n",
675 : : i, num_done, xalloc_cnt, xfree_cnt);
676 : : if (xalloc_cnt != xfree_cnt)
677 : : exit(-1);
678 : : xalloc_cnt = xfree_cnt = 0;
679 : : }
680 : :
681 : : free(iocbs);
682 : : free(events);
683 : : free(iocb_list);
684 : : opio_free(&ctx);
685 : :
686 : : return 0;
687 : : }
688 : : #endif
|