LCOV - code coverage report
Current view: top level - drivers - io-optimize.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 138 0.0 %
Date: 2025-03-04 17:26:00 Functions: 0 19 0.0 %
Branches: 0 73 0.0 %

           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

Generated by: LCOV version 1.13