LCOV - code coverage report
Current view: top level - spdk/test/nvme/overhead - overhead.c (source / functions) Hit Total Coverage
Test: Combined Lines: 214 361 59.3 %
Date: 2024-07-10 16:15:41 Functions: 17 21 81.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 99 296 33.4 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2016 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/barrier.h"
       9                 :            : #include "spdk/fd.h"
      10                 :            : #include "spdk/nvme.h"
      11                 :            : #include "spdk/env.h"
      12                 :            : #include "spdk/string.h"
      13                 :            : #include "spdk/nvme_intel.h"
      14                 :            : #include "spdk/histogram_data.h"
      15                 :            : #include "spdk/string.h"
      16                 :            : #include "spdk/log.h"
      17                 :            : 
      18                 :            : #if HAVE_LIBAIO
      19                 :            : #include <libaio.h>
      20                 :            : #endif
      21                 :            : 
      22                 :            : struct ctrlr_entry {
      23                 :            :         struct spdk_nvme_ctrlr                  *ctrlr;
      24                 :            :         TAILQ_ENTRY(ctrlr_entry)                link;
      25                 :            :         char                                    name[1024];
      26                 :            : };
      27                 :            : 
      28                 :            : enum entry_type {
      29                 :            :         ENTRY_TYPE_NVME_NS,
      30                 :            :         ENTRY_TYPE_AIO_FILE,
      31                 :            : };
      32                 :            : 
      33                 :            : struct ns_entry {
      34                 :            :         enum entry_type         type;
      35                 :            : 
      36                 :            :         union {
      37                 :            :                 struct {
      38                 :            :                         struct spdk_nvme_ctrlr  *ctrlr;
      39                 :            :                         struct spdk_nvme_ns     *ns;
      40                 :            :                         struct spdk_nvme_qpair  *qpair;
      41                 :            :                 } nvme;
      42                 :            : #if HAVE_LIBAIO
      43                 :            :                 struct {
      44                 :            :                         int                     fd;
      45                 :            :                         struct io_event         *events;
      46                 :            :                         io_context_t            ctx;
      47                 :            :                 } aio;
      48                 :            : #endif
      49                 :            :         } u;
      50                 :            : 
      51                 :            :         uint32_t                io_size_blocks;
      52                 :            :         uint64_t                size_in_ios;
      53                 :            :         bool                    is_draining;
      54                 :            :         uint32_t                current_queue_depth;
      55                 :            :         char                    name[1024];
      56                 :            :         struct ns_entry         *next;
      57                 :            : 
      58                 :            :         struct spdk_histogram_data      *submit_histogram;
      59                 :            :         struct spdk_histogram_data      *complete_histogram;
      60                 :            : };
      61                 :            : 
      62                 :            : struct perf_task {
      63                 :            :         void                    *buf;
      64                 :            :         uint64_t                submit_tsc;
      65                 :            : #if HAVE_LIBAIO
      66                 :            :         struct iocb             iocb;
      67                 :            : #endif
      68                 :            : };
      69                 :            : 
      70                 :            : static bool g_enable_histogram = false;
      71                 :            : 
      72                 :            : static TAILQ_HEAD(, ctrlr_entry) g_ctrlr = TAILQ_HEAD_INITIALIZER(g_ctrlr);
      73                 :            : static struct ns_entry *g_ns = NULL;
      74                 :            : 
      75                 :            : static uint64_t g_tsc_rate;
      76                 :            : 
      77                 :            : static uint32_t g_io_size_bytes;
      78                 :            : static int g_time_in_sec;
      79                 :            : 
      80                 :            : static int g_aio_optind; /* Index of first AIO filename in argv */
      81                 :            : 
      82                 :            : struct perf_task *g_task;
      83                 :            : uint64_t g_tsc_submit = 0;
      84                 :            : uint64_t g_tsc_submit_min = UINT64_MAX;
      85                 :            : uint64_t g_tsc_submit_max = 0;
      86                 :            : uint64_t g_tsc_complete = 0;
      87                 :            : uint64_t g_tsc_complete_min = UINT64_MAX;
      88                 :            : uint64_t g_tsc_complete_max = 0;
      89                 :            : uint64_t g_io_completed = 0;
      90                 :            : 
      91                 :            : static struct spdk_nvme_transport_id g_trid = {};
      92                 :            : 
      93                 :            : static void
      94                 :         12 : register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
      95                 :            : {
      96                 :            :         struct ns_entry *entry;
      97                 :            :         const struct spdk_nvme_ctrlr_data *cdata;
      98                 :            : 
      99                 :         12 :         cdata = spdk_nvme_ctrlr_get_data(ctrlr);
     100                 :            : 
     101         [ -  + ]:         12 :         if (!spdk_nvme_ns_is_active(ns)) {
     102                 :          0 :                 printf("Controller %-20.20s (%-20.20s): Skipping inactive NS %u\n",
     103         [ #  # ]:          0 :                        cdata->mn, cdata->sn,
     104                 :            :                        spdk_nvme_ns_get_id(ns));
     105                 :          0 :                 return;
     106                 :            :         }
     107                 :            : 
     108         [ +  - ]:         12 :         if (spdk_nvme_ns_get_size(ns) < g_io_size_bytes ||
     109         [ -  + ]:         12 :             spdk_nvme_ns_get_sector_size(ns) > g_io_size_bytes) {
     110                 :          0 :                 printf("WARNING: controller %-20.20s (%-20.20s) ns %u has invalid "
     111                 :            :                        "ns size %" PRIu64 " / block size %u for I/O size %u\n",
     112         [ #  # ]:          0 :                        cdata->mn, cdata->sn, spdk_nvme_ns_get_id(ns),
     113                 :            :                        spdk_nvme_ns_get_size(ns), spdk_nvme_ns_get_sector_size(ns), g_io_size_bytes);
     114                 :          0 :                 return;
     115                 :            :         }
     116                 :            : 
     117                 :         12 :         entry = calloc(1, sizeof(struct ns_entry));
     118         [ -  + ]:         12 :         if (entry == NULL) {
     119                 :          0 :                 perror("ns_entry malloc");
     120                 :          0 :                 exit(1);
     121                 :            :         }
     122                 :            : 
     123                 :         12 :         entry->type = ENTRY_TYPE_NVME_NS;
     124                 :         12 :         entry->u.nvme.ctrlr = ctrlr;
     125                 :         12 :         entry->u.nvme.ns = ns;
     126                 :            : 
     127         [ -  + ]:         12 :         entry->size_in_ios = spdk_nvme_ns_get_size(ns) /
     128                 :            :                              g_io_size_bytes;
     129         [ -  + ]:         12 :         entry->io_size_blocks = g_io_size_bytes / spdk_nvme_ns_get_sector_size(ns);
     130                 :         12 :         entry->submit_histogram = spdk_histogram_data_alloc();
     131                 :         12 :         entry->complete_histogram = spdk_histogram_data_alloc();
     132                 :            : 
     133         [ -  + ]:         12 :         snprintf(entry->name, 44, "%-20.20s (%-20.20s)", cdata->mn, cdata->sn);
     134                 :            : 
     135                 :         12 :         entry->next = g_ns;
     136                 :         12 :         g_ns = entry;
     137                 :            : }
     138                 :            : 
     139                 :            : static void
     140                 :         12 : register_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
     141                 :            : {
     142                 :            :         int num_ns;
     143                 :         12 :         struct ctrlr_entry *entry = malloc(sizeof(struct ctrlr_entry));
     144                 :         12 :         const struct spdk_nvme_ctrlr_data *cdata = spdk_nvme_ctrlr_get_data(ctrlr);
     145                 :            : 
     146         [ -  + ]:         12 :         if (entry == NULL) {
     147                 :          0 :                 perror("ctrlr_entry malloc");
     148                 :          0 :                 exit(1);
     149                 :            :         }
     150                 :            : 
     151         [ -  + ]:         12 :         snprintf(entry->name, sizeof(entry->name), "%-20.20s (%-20.20s)", cdata->mn, cdata->sn);
     152                 :            : 
     153                 :         12 :         entry->ctrlr = ctrlr;
     154                 :            : 
     155                 :         12 :         TAILQ_INSERT_TAIL(&g_ctrlr, entry, link);
     156                 :            : 
     157                 :         12 :         num_ns = spdk_nvme_ctrlr_get_num_ns(ctrlr);
     158                 :            :         /* Only register the first namespace. */
     159         [ -  + ]:         12 :         if (num_ns < 1) {
     160   [ #  #  #  # ]:          0 :                 fprintf(stderr, "controller found with no namespaces\n");
     161                 :          0 :                 return;
     162                 :            :         }
     163                 :            : 
     164                 :         12 :         register_ns(ctrlr, spdk_nvme_ctrlr_get_ns(ctrlr, 1));
     165                 :            : }
     166                 :            : 
     167                 :            : #if HAVE_LIBAIO
     168                 :            : static int
     169                 :          0 : register_aio_file(const char *path)
     170                 :            : {
     171                 :            :         struct ns_entry *entry;
     172                 :            : 
     173                 :            :         int fd;
     174                 :            :         uint64_t size;
     175                 :            :         uint32_t blklen;
     176                 :            : 
     177         [ #  # ]:          0 :         fd = open(path, O_RDWR | O_DIRECT);
     178         [ #  # ]:          0 :         if (fd < 0) {
     179         [ #  # ]:          0 :                 fprintf(stderr, "Could not open AIO device %s: %s\n", path, strerror(errno));
     180                 :          0 :                 return -1;
     181                 :            :         }
     182                 :            : 
     183                 :          0 :         size = spdk_fd_get_size(fd);
     184         [ #  # ]:          0 :         if (size == 0) {
     185         [ #  # ]:          0 :                 fprintf(stderr, "Could not determine size of AIO device %s\n", path);
     186                 :          0 :                 close(fd);
     187                 :          0 :                 return -1;
     188                 :            :         }
     189                 :            : 
     190                 :          0 :         blklen = spdk_fd_get_blocklen(fd);
     191         [ #  # ]:          0 :         if (blklen == 0) {
     192         [ #  # ]:          0 :                 fprintf(stderr, "Could not determine block size of AIO device %s\n", path);
     193                 :          0 :                 close(fd);
     194                 :          0 :                 return -1;
     195                 :            :         }
     196                 :            : 
     197                 :          0 :         entry = calloc(1, sizeof(struct ns_entry));
     198         [ #  # ]:          0 :         if (entry == NULL) {
     199                 :          0 :                 close(fd);
     200                 :          0 :                 perror("aio ns_entry malloc");
     201                 :          0 :                 return -1;
     202                 :            :         }
     203                 :            : 
     204                 :          0 :         entry->type = ENTRY_TYPE_AIO_FILE;
     205                 :          0 :         entry->u.aio.fd = fd;
     206         [ #  # ]:          0 :         entry->size_in_ios = size / g_io_size_bytes;
     207         [ #  # ]:          0 :         entry->io_size_blocks = g_io_size_bytes / blklen;
     208                 :          0 :         entry->submit_histogram = spdk_histogram_data_alloc();
     209                 :          0 :         entry->complete_histogram = spdk_histogram_data_alloc();
     210                 :            : 
     211                 :          0 :         snprintf(entry->name, sizeof(entry->name), "%s", path);
     212                 :            : 
     213                 :          0 :         g_ns = entry;
     214                 :            : 
     215                 :          0 :         return 0;
     216                 :            : }
     217                 :            : 
     218                 :            : static int
     219                 :          0 : aio_submit(io_context_t aio_ctx, struct iocb *iocb, int fd, enum io_iocb_cmd cmd, void *buf,
     220                 :            :            unsigned long nbytes, uint64_t offset, void *cb_ctx)
     221                 :            : {
     222                 :          0 :         iocb->aio_fildes = fd;
     223                 :          0 :         iocb->aio_reqprio = 0;
     224                 :          0 :         iocb->aio_lio_opcode = cmd;
     225                 :          0 :         iocb->u.c.buf = buf;
     226                 :          0 :         iocb->u.c.nbytes = nbytes;
     227                 :          0 :         iocb->u.c.offset = offset;
     228                 :          0 :         iocb->data = cb_ctx;
     229                 :            : 
     230         [ #  # ]:          0 :         if (io_submit(aio_ctx, 1, &iocb) < 0) {
     231         [ #  # ]:          0 :                 printf("io_submit");
     232                 :          0 :                 return -1;
     233                 :            :         }
     234                 :            : 
     235                 :          0 :         return 0;
     236                 :            : }
     237                 :            : 
     238                 :            : static void
     239                 :          0 : aio_check_io(void)
     240                 :            : {
     241                 :            :         int count, i;
     242                 :          0 :         struct timespec timeout;
     243                 :            : 
     244                 :          0 :         timeout.tv_sec = 0;
     245                 :          0 :         timeout.tv_nsec = 0;
     246                 :            : 
     247                 :          0 :         count = io_getevents(g_ns->u.aio.ctx, 1, 1, g_ns->u.aio.events, &timeout);
     248         [ #  # ]:          0 :         if (count < 0) {
     249   [ #  #  #  # ]:          0 :                 fprintf(stderr, "io_getevents error\n");
     250                 :          0 :                 exit(1);
     251                 :            :         }
     252                 :            : 
     253         [ #  # ]:          0 :         for (i = 0; i < count; i++) {
     254                 :          0 :                 g_ns->current_queue_depth--;
     255                 :            :         }
     256                 :          0 : }
     257                 :            : #endif /* HAVE_LIBAIO */
     258                 :            : 
     259                 :            : static void io_complete(void *ctx, const struct spdk_nvme_cpl *completion);
     260                 :            : 
     261                 :            : static __thread unsigned int seed = 0;
     262                 :            : 
     263                 :            : static void
     264                 :     163045 : submit_single_io(void)
     265                 :            : {
     266                 :            :         uint64_t                offset_in_ios;
     267                 :            :         uint64_t                start;
     268                 :            :         int                     rc;
     269                 :     163045 :         struct ns_entry         *entry = g_ns;
     270                 :            :         uint64_t                tsc_submit;
     271                 :            : 
     272         [ -  + ]:     163045 :         offset_in_ios = rand_r(&seed) % entry->size_in_ios;
     273                 :            : 
     274                 :     163045 :         start = spdk_get_ticks();
     275                 :     163045 :         spdk_rmb();
     276                 :            : #if HAVE_LIBAIO
     277         [ -  + ]:     163045 :         if (entry->type == ENTRY_TYPE_AIO_FILE) {
     278                 :          0 :                 rc = aio_submit(g_ns->u.aio.ctx, &g_task->iocb, entry->u.aio.fd, IO_CMD_PREAD, g_task->buf,
     279                 :            :                                 g_io_size_bytes, offset_in_ios * g_io_size_bytes, g_task);
     280                 :            :         } else
     281                 :            : #endif
     282                 :            :         {
     283                 :     309060 :                 rc = spdk_nvme_ns_cmd_read(entry->u.nvme.ns, g_ns->u.nvme.qpair, g_task->buf,
     284                 :     163045 :                                            offset_in_ios * entry->io_size_blocks,
     285                 :            :                                            entry->io_size_blocks, io_complete, g_task, 0);
     286                 :            :         }
     287                 :            : 
     288                 :     163045 :         spdk_rmb();
     289                 :     163045 :         tsc_submit = spdk_get_ticks() - start;
     290                 :     163045 :         g_tsc_submit += tsc_submit;
     291         [ +  + ]:     163045 :         if (tsc_submit < g_tsc_submit_min) {
     292                 :        145 :                 g_tsc_submit_min = tsc_submit;
     293                 :            :         }
     294         [ +  + ]:     163045 :         if (tsc_submit > g_tsc_submit_max) {
     295                 :         33 :                 g_tsc_submit_max = tsc_submit;
     296                 :            :         }
     297   [ +  +  +  - ]:     163045 :         if (g_enable_histogram) {
     298                 :     163045 :                 spdk_histogram_data_tally(entry->submit_histogram, tsc_submit);
     299                 :            :         }
     300                 :            : 
     301         [ -  + ]:     163045 :         if (rc != 0) {
     302   [ #  #  #  # ]:          0 :                 fprintf(stderr, "starting I/O failed\n");
     303                 :            :         } else {
     304                 :     163045 :                 g_ns->current_queue_depth++;
     305                 :            :         }
     306                 :     163045 : }
     307                 :            : 
     308                 :            : static void
     309                 :     163045 : io_complete(void *ctx, const struct spdk_nvme_cpl *completion)
     310                 :            : {
     311                 :     163045 :         g_ns->current_queue_depth--;
     312                 :     163045 : }
     313                 :            : 
     314                 :            : uint64_t g_complete_tsc_start;
     315                 :            : 
     316                 :            : static uint64_t
     317                 :    8166096 : check_io(void)
     318                 :            : {
     319                 :            :         uint64_t end, tsc_complete;
     320                 :            : 
     321                 :    8166096 :         spdk_rmb();
     322                 :            : #if HAVE_LIBAIO
     323         [ -  + ]:    8166096 :         if (g_ns->type == ENTRY_TYPE_AIO_FILE) {
     324                 :          0 :                 aio_check_io();
     325                 :            :         } else
     326                 :            : #endif
     327                 :            :         {
     328                 :    8166096 :                 spdk_nvme_qpair_process_completions(g_ns->u.nvme.qpair, 0);
     329                 :            :         }
     330                 :    8166096 :         spdk_rmb();
     331                 :    8166096 :         end = spdk_get_ticks();
     332         [ +  + ]:    8166096 :         if (g_ns->current_queue_depth == 1) {
     333                 :            :                 /*
     334                 :            :                  * Account for race condition in AIO case where interrupt occurs
     335                 :            :                  *  after checking for queue depth.  If the timestamp capture
     336                 :            :                  *  is too big compared to the last capture, assume that an
     337                 :            :                  *  interrupt fired, and do not bump the start tsc forward.  This
     338                 :            :                  *  will ensure this extra time is accounted for next time through
     339                 :            :                  *  when we see current_queue_depth drop to 0.
     340                 :            :                  */
     341   [ -  +  -  - ]:    8003051 :                 if (g_ns->type == ENTRY_TYPE_NVME_NS || (end - g_complete_tsc_start) < 500) {
     342                 :    8003051 :                         g_complete_tsc_start = end;
     343                 :            :                 }
     344                 :            :         } else {
     345                 :     163045 :                 tsc_complete = end - g_complete_tsc_start;
     346                 :     163045 :                 g_tsc_complete += tsc_complete;
     347         [ +  + ]:     163045 :                 if (tsc_complete < g_tsc_complete_min) {
     348                 :        126 :                         g_tsc_complete_min = tsc_complete;
     349                 :            :                 }
     350         [ +  + ]:     163045 :                 if (tsc_complete > g_tsc_complete_max) {
     351                 :         67 :                         g_tsc_complete_max = tsc_complete;
     352                 :            :                 }
     353   [ +  +  +  - ]:     163045 :                 if (g_enable_histogram) {
     354                 :     163045 :                         spdk_histogram_data_tally(g_ns->complete_histogram, tsc_complete);
     355                 :            :                 }
     356                 :     163045 :                 g_io_completed++;
     357   [ +  +  +  + ]:     163045 :                 if (!g_ns->is_draining) {
     358                 :     163037 :                         submit_single_io();
     359                 :            :                 }
     360                 :     163045 :                 end = g_complete_tsc_start = spdk_get_ticks();
     361                 :            :         }
     362                 :            : 
     363                 :    8166096 :         return end;
     364                 :            : }
     365                 :            : 
     366                 :            : static void
     367                 :          8 : drain_io(void)
     368                 :            : {
     369                 :          8 :         g_ns->is_draining = true;
     370         [ +  + ]:        645 :         while (g_ns->current_queue_depth > 0) {
     371                 :        637 :                 check_io();
     372                 :            :         }
     373                 :          8 : }
     374                 :            : 
     375                 :            : static int
     376                 :          8 : init_ns_worker_ctx(void)
     377                 :            : {
     378         [ -  + ]:          8 :         if (g_ns->type == ENTRY_TYPE_AIO_FILE) {
     379                 :            : #ifdef HAVE_LIBAIO
     380                 :          0 :                 g_ns->u.aio.events = calloc(1, sizeof(struct io_event));
     381         [ #  # ]:          0 :                 if (!g_ns->u.aio.events) {
     382                 :          0 :                         return -1;
     383                 :            :                 }
     384                 :          0 :                 g_ns->u.aio.ctx = 0;
     385         [ #  # ]:          0 :                 if (io_setup(1, &g_ns->u.aio.ctx) < 0) {
     386                 :          0 :                         free(g_ns->u.aio.events);
     387                 :          0 :                         perror("io_setup");
     388                 :          0 :                         return -1;
     389                 :            :                 }
     390                 :            : #endif
     391                 :            :         } else {
     392                 :            :                 /*
     393                 :            :                  * TODO: If a controller has multiple namespaces, they could all use the same queue.
     394                 :            :                  *  For now, give each namespace/thread combination its own queue.
     395                 :            :                  */
     396                 :          8 :                 g_ns->u.nvme.qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_ns->u.nvme.ctrlr, NULL, 0);
     397         [ -  + ]:          8 :                 if (!g_ns->u.nvme.qpair) {
     398         [ #  # ]:          0 :                         printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair failed\n");
     399                 :          0 :                         return -1;
     400                 :            :                 }
     401                 :            :         }
     402                 :            : 
     403                 :          8 :         return 0;
     404                 :            : }
     405                 :            : 
     406                 :            : static void
     407                 :          8 : cleanup_ns_worker_ctx(void)
     408                 :            : {
     409         [ -  + ]:          8 :         if (g_ns->type == ENTRY_TYPE_AIO_FILE) {
     410                 :            : #ifdef HAVE_LIBAIO
     411                 :          0 :                 io_destroy(g_ns->u.aio.ctx);
     412                 :          0 :                 free(g_ns->u.aio.events);
     413                 :            : #endif
     414                 :            :         } else {
     415                 :          8 :                 spdk_nvme_ctrlr_free_io_qpair(g_ns->u.nvme.qpair);
     416                 :            :         }
     417                 :          8 : }
     418                 :            : 
     419                 :            : static int
     420                 :          8 : work_fn(void)
     421                 :            : {
     422                 :            :         uint64_t tsc_end, current;
     423                 :            : 
     424                 :            :         /* Allocate a queue pair for each namespace. */
     425         [ -  + ]:          8 :         if (init_ns_worker_ctx() != 0) {
     426         [ #  # ]:          0 :                 printf("ERROR: init_ns_worker_ctx() failed\n");
     427                 :          0 :                 return 1;
     428                 :            :         }
     429                 :            : 
     430                 :          8 :         tsc_end = spdk_get_ticks() + g_time_in_sec * g_tsc_rate;
     431                 :            : 
     432                 :            :         /* Submit initial I/O for each namespace. */
     433                 :          8 :         submit_single_io();
     434                 :          8 :         g_complete_tsc_start = spdk_get_ticks();
     435                 :            : 
     436                 :            :         while (1) {
     437                 :            :                 /*
     438                 :            :                  * Check for completed I/O for each controller. A new
     439                 :            :                  * I/O will be submitted in the io_complete callback
     440                 :            :                  * to replace each I/O that is completed.
     441                 :            :                  */
     442                 :    8165459 :                 current = check_io();
     443                 :            : 
     444         [ +  + ]:    8165459 :                 if (current > tsc_end) {
     445                 :          8 :                         break;
     446                 :            :                 }
     447                 :            :         }
     448                 :            : 
     449                 :          8 :         drain_io();
     450                 :          8 :         cleanup_ns_worker_ctx();
     451                 :            : 
     452                 :          8 :         return 0;
     453                 :            : }
     454                 :            : 
     455                 :            : static void
     456                 :          0 : usage(char *program_name)
     457                 :            : {
     458         [ #  # ]:          0 :         printf("%s options", program_name);
     459                 :            : #if HAVE_LIBAIO
     460         [ #  # ]:          0 :         printf(" [AIO device(s)]...");
     461                 :            : #endif
     462         [ #  # ]:          0 :         printf("\t\n");
     463         [ #  # ]:          0 :         printf("\t[-d DPDK huge memory size in MB]\n");
     464         [ #  # ]:          0 :         printf("\t[-o io size in bytes]\n");
     465         [ #  # ]:          0 :         printf("\t[-t time in seconds]\n");
     466         [ #  # ]:          0 :         printf("\t\t(default: 1)]\n");
     467         [ #  # ]:          0 :         printf("\t[-H enable histograms]\n");
     468         [ #  # ]:          0 :         printf("\t[-g use single file descriptor for DPDK memory segments]\n");
     469         [ #  # ]:          0 :         printf("\t[-i shared memory group ID]\n");
     470         [ #  # ]:          0 :         printf("\t[-r remote NVMe over Fabrics target address]\n");
     471                 :            : #ifdef DEBUG
     472         [ #  # ]:          0 :         printf("\t[-L enable debug logging]\n");
     473                 :            : #else
     474                 :            :         printf("\t[-L enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n");
     475                 :            : #endif
     476                 :          0 :         spdk_log_usage(stdout, "\t\t-L");
     477                 :          0 : }
     478                 :            : 
     479                 :            : static void
     480                 :     118784 : print_bucket(void *ctx, uint64_t start, uint64_t end, uint64_t count,
     481                 :            :              uint64_t total, uint64_t so_far)
     482                 :            : {
     483                 :            :         double so_far_pct;
     484                 :            : 
     485         [ +  + ]:     118784 :         if (count == 0) {
     486                 :     115571 :                 return;
     487                 :            :         }
     488                 :            : 
     489                 :       3213 :         so_far_pct = (double)so_far * 100 / total;
     490                 :            : 
     491                 :       3213 :         printf("%9.3f - %9.3f: %9.4f%%  (%9ju)\n",
     492                 :       3213 :                (double)start * 1000 * 1000 / g_tsc_rate,
     493         [ -  + ]:       3213 :                (double)end * 1000 * 1000 / g_tsc_rate,
     494                 :            :                so_far_pct, count);
     495                 :            : }
     496                 :            : 
     497                 :            : static void
     498                 :          8 : print_stats(void)
     499                 :            : {
     500                 :          8 :         double divisor = (double)g_tsc_rate / (1000 * 1000 * 1000);
     501                 :            : 
     502                 :          8 :         printf("submit (in ns)   avg, min, max = %8.1f, %8.1f, %8.1f\n",
     503                 :          8 :                (double)g_tsc_submit / g_io_completed / divisor,
     504                 :          8 :                (double)g_tsc_submit_min / divisor,
     505         [ -  + ]:          8 :                (double)g_tsc_submit_max / divisor);
     506                 :          8 :         printf("complete (in ns) avg, min, max = %8.1f, %8.1f, %8.1f\n",
     507                 :          8 :                (double)g_tsc_complete / g_io_completed / divisor,
     508                 :          8 :                (double)g_tsc_complete_min / divisor,
     509         [ -  + ]:          8 :                (double)g_tsc_complete_max / divisor);
     510                 :            : 
     511   [ -  +  -  + ]:          8 :         if (!g_enable_histogram) {
     512                 :          0 :                 return;
     513                 :            :         }
     514                 :            : 
     515                 :          8 :         printf("\n");
     516         [ -  + ]:          8 :         printf("Submit histogram\n");
     517         [ -  + ]:          8 :         printf("================\n");
     518         [ -  + ]:          8 :         printf("       Range in us     Cumulative     Count\n");
     519                 :          8 :         spdk_histogram_data_iterate(g_ns->submit_histogram, print_bucket, NULL);
     520                 :          8 :         printf("\n");
     521                 :            : 
     522         [ -  + ]:          8 :         printf("Complete histogram\n");
     523         [ -  + ]:          8 :         printf("==================\n");
     524         [ -  + ]:          8 :         printf("       Range in us     Cumulative     Count\n");
     525                 :          8 :         spdk_histogram_data_iterate(g_ns->complete_histogram, print_bucket, NULL);
     526                 :          8 :         printf("\n");
     527                 :            : 
     528                 :            : }
     529                 :            : 
     530                 :            : static int
     531                 :          8 : parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
     532                 :            : {
     533                 :            :         int op, rc;
     534                 :            :         long int val;
     535                 :            : 
     536                 :            :         /* default value */
     537                 :          8 :         g_io_size_bytes = 0;
     538                 :          8 :         g_time_in_sec = 0;
     539                 :            : 
     540                 :          8 :         spdk_nvme_trid_populate_transport(&g_trid, SPDK_NVME_TRANSPORT_PCIE);
     541         [ -  + ]:          8 :         snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
     542                 :            : 
     543   [ +  +  +  +  :         44 :         while ((op = getopt(argc, argv, "d:ghi:o:r:t:HL:")) != -1) {
                   +  + ]
     544   [ -  +  +  +  :         36 :                 switch (op) {
          +  +  +  +  -  
                      - ]
     545                 :          0 :                 case 'h':
     546                 :          0 :                         usage(argv[0]);
     547                 :          0 :                         exit(0);
     548                 :            :                         break;
     549                 :          8 :                 case 'o':
     550                 :          8 :                         val = spdk_strtol(optarg, 10);
     551         [ -  + ]:          8 :                         if (val < 0) {
     552   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Invalid io size\n");
     553                 :          0 :                                 return val;
     554                 :            :                         }
     555                 :          8 :                         g_io_size_bytes = (uint32_t)val;
     556                 :          8 :                         break;
     557                 :          8 :                 case 't':
     558                 :          8 :                         g_time_in_sec = spdk_strtol(optarg, 10);
     559         [ -  + ]:          8 :                         if (g_time_in_sec < 0) {
     560   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Invalid run time\n");
     561                 :          0 :                                 return g_time_in_sec;
     562                 :            :                         }
     563                 :          8 :                         break;
     564                 :          8 :                 case 'H':
     565                 :          8 :                         g_enable_histogram = true;
     566                 :          8 :                         break;
     567                 :          6 :                 case 'i':
     568                 :          6 :                         env_opts->shm_id = spdk_strtol(optarg, 10);
     569         [ -  + ]:          6 :                         if (env_opts->shm_id < 0) {
     570   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Invalid shared memory ID\n");
     571                 :          0 :                                 return env_opts->shm_id;
     572                 :            :                         }
     573                 :          6 :                         break;
     574                 :          2 :                 case 'g':
     575                 :          2 :                         env_opts->hugepage_single_segments = true;
     576                 :          2 :                         break;
     577                 :          2 :                 case 'r':
     578         [ -  + ]:          2 :                         if (spdk_nvme_transport_id_parse(&g_trid, optarg) != 0) {
     579   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Error parsing transport address\n");
     580                 :          0 :                                 return 1;
     581                 :            :                         }
     582                 :          2 :                         break;
     583                 :          2 :                 case 'd':
     584                 :          2 :                         env_opts->mem_size = spdk_strtol(optarg, 10);
     585         [ -  + ]:          2 :                         if (env_opts->mem_size < 0) {
     586   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Invalid DPDK memory size\n");
     587                 :          0 :                                 return env_opts->mem_size;
     588                 :            :                         }
     589                 :          2 :                         break;
     590                 :          0 :                 case 'L':
     591                 :          0 :                         rc = spdk_log_set_flag(optarg);
     592         [ #  # ]:          0 :                         if (rc < 0) {
     593   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "unknown flag\n");
     594                 :          0 :                                 usage(argv[0]);
     595                 :          0 :                                 exit(EXIT_FAILURE);
     596                 :            :                         }
     597                 :            : #ifdef DEBUG
     598                 :          0 :                         spdk_log_set_print_level(SPDK_LOG_DEBUG);
     599                 :            : #endif
     600                 :          0 :                         break;
     601                 :          0 :                 default:
     602                 :          0 :                         usage(argv[0]);
     603                 :          0 :                         return 1;
     604                 :            :                 }
     605                 :            :         }
     606                 :            : 
     607         [ -  + ]:          8 :         if (!g_io_size_bytes) {
     608                 :          0 :                 usage(argv[0]);
     609                 :          0 :                 return 1;
     610                 :            :         }
     611         [ -  + ]:          8 :         if (!g_time_in_sec) {
     612                 :          0 :                 usage(argv[0]);
     613                 :          0 :                 return 1;
     614                 :            :         }
     615                 :            : 
     616                 :          8 :         g_aio_optind = optind;
     617                 :            : 
     618                 :          8 :         return 0;
     619                 :            : }
     620                 :            : 
     621                 :            : static bool
     622                 :          2 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
     623                 :            :          struct spdk_nvme_ctrlr_opts *opts)
     624                 :            : {
     625                 :            :         static uint32_t ctrlr_found = 0;
     626                 :            : 
     627         [ -  + ]:          2 :         if (ctrlr_found == 1) {
     628   [ #  #  #  # ]:          0 :                 fprintf(stderr, "only attaching to one controller, so skipping\n");
     629         [ #  # ]:          0 :                 fprintf(stderr, " controller at PCI address %s\n",
     630         [ #  # ]:          0 :                         trid->traddr);
     631                 :          0 :                 return false;
     632                 :            :         }
     633                 :          2 :         ctrlr_found = 1;
     634                 :            : 
     635         [ -  + ]:          2 :         printf("Attaching to %s\n", trid->traddr);
     636                 :            : 
     637                 :          2 :         return true;
     638                 :            : }
     639                 :            : 
     640                 :            : static void
     641                 :         12 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
     642                 :            :           struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
     643                 :            : {
     644         [ -  + ]:         12 :         printf("Attached to %s\n", trid->traddr);
     645                 :            : 
     646                 :         12 :         register_ctrlr(ctrlr);
     647                 :         12 : }
     648                 :            : 
     649                 :            : static int
     650                 :          8 : register_controllers(void)
     651                 :            : {
     652         [ -  + ]:          8 :         printf("Initializing NVMe Controllers\n");
     653                 :            : 
     654         [ -  + ]:          8 :         if (spdk_nvme_probe(&g_trid, NULL, probe_cb, attach_cb, NULL) != 0) {
     655   [ #  #  #  # ]:          0 :                 fprintf(stderr, "spdk_nvme_probe() failed\n");
     656                 :          0 :                 return 1;
     657                 :            :         }
     658                 :            : 
     659         [ -  + ]:          8 :         if (g_ns == NULL) {
     660   [ #  #  #  # ]:          0 :                 fprintf(stderr, "no NVMe controller found - check that device is bound to uio/vfio\n");
     661                 :          0 :                 return 1;
     662                 :            :         }
     663                 :            : 
     664                 :          8 :         return 0;
     665                 :            : }
     666                 :            : 
     667                 :            : static void
     668                 :          8 : cleanup(void)
     669                 :            : {
     670                 :          8 :         struct ns_entry *ns_entry = g_ns;
     671                 :            :         struct ctrlr_entry *ctrlr_entry, *tmp_ctrlr_entry;
     672                 :          8 :         struct spdk_nvme_detach_ctx *detach_ctx = NULL;
     673                 :            : 
     674         [ +  + ]:         20 :         while (ns_entry) {
     675                 :         12 :                 struct ns_entry *next = ns_entry->next;
     676                 :            : 
     677                 :         12 :                 spdk_histogram_data_free(ns_entry->submit_histogram);
     678                 :         12 :                 spdk_histogram_data_free(ns_entry->complete_histogram);
     679                 :         12 :                 free(ns_entry);
     680                 :         12 :                 ns_entry = next;
     681                 :            :         }
     682                 :            : 
     683         [ +  + ]:         20 :         TAILQ_FOREACH_SAFE(ctrlr_entry, &g_ctrlr, link, tmp_ctrlr_entry) {
     684         [ +  + ]:         12 :                 TAILQ_REMOVE(&g_ctrlr, ctrlr_entry, link);
     685                 :         12 :                 spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx);
     686                 :         12 :                 free(ctrlr_entry);
     687                 :            :         }
     688                 :            : 
     689         [ +  + ]:          8 :         if (detach_ctx) {
     690                 :          2 :                 spdk_nvme_detach_poll(detach_ctx);
     691                 :            :         }
     692                 :          8 : }
     693                 :            : 
     694                 :            : int
     695                 :          8 : main(int argc, char **argv)
     696                 :            : {
     697                 :            :         int                     rc;
     698                 :          3 :         struct spdk_env_opts    opts;
     699                 :            : 
     700                 :          8 :         spdk_env_opts_init(&opts);
     701                 :          8 :         rc = parse_args(argc, argv, &opts);
     702         [ -  + ]:          8 :         if (rc != 0) {
     703                 :          0 :                 return rc;
     704                 :            :         }
     705                 :            : 
     706                 :          8 :         opts.name = "overhead";
     707                 :          8 :         opts.core_mask = "0x1";
     708         [ -  + ]:          8 :         if (spdk_env_init(&opts) < 0) {
     709   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to initialize SPDK env\n");
     710                 :          0 :                 return 1;
     711                 :            :         }
     712                 :            : 
     713                 :          8 :         g_task = spdk_zmalloc(sizeof(struct perf_task), 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     714         [ -  + ]:          8 :         if (g_task == NULL) {
     715   [ #  #  #  # ]:          0 :                 fprintf(stderr, "g_task alloc failed\n");
     716                 :          0 :                 exit(1);
     717                 :            :         }
     718                 :            : 
     719                 :          8 :         g_task->buf = spdk_zmalloc(g_io_size_bytes, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     720         [ -  + ]:          8 :         if (g_task->buf == NULL) {
     721   [ #  #  #  # ]:          0 :                 fprintf(stderr, "g_task->buf spdk_zmalloc failed\n");
     722                 :          0 :                 exit(1);
     723                 :            :         }
     724                 :            : 
     725                 :          8 :         g_tsc_rate = spdk_get_ticks_hz();
     726                 :            : 
     727                 :            : #if HAVE_LIBAIO
     728         [ -  + ]:          8 :         if (g_aio_optind < argc) {
     729         [ #  # ]:          0 :                 printf("Measuring overhead for AIO device %s.\n", argv[g_aio_optind]);
     730         [ #  # ]:          0 :                 if (register_aio_file(argv[g_aio_optind]) != 0) {
     731                 :          0 :                         cleanup();
     732                 :          0 :                         return -1;
     733                 :            :                 }
     734                 :            :         } else
     735                 :            : #endif
     736                 :            :         {
     737         [ -  + ]:          8 :                 if (register_controllers() != 0) {
     738                 :          0 :                         cleanup();
     739                 :          0 :                         return -1;
     740                 :            :                 }
     741                 :            :         }
     742                 :            : 
     743         [ -  + ]:          8 :         printf("Initialization complete. Launching workers.\n");
     744                 :            : 
     745                 :          8 :         rc = work_fn();
     746                 :            : 
     747                 :          8 :         print_stats();
     748                 :            : 
     749                 :          8 :         cleanup();
     750                 :            : 
     751         [ -  + ]:          8 :         if (rc != 0) {
     752   [ #  #  #  # ]:          0 :                 fprintf(stderr, "%s: errors occurred\n", argv[0]);
     753                 :            :         }
     754                 :            : 
     755                 :          8 :         return rc;
     756                 :            : }

Generated by: LCOV version 1.14