LCOV - code coverage report
Current view: top level - spdk/app/spdk_nvme_perf - perf.c (source / functions) Hit Total Coverage
Test: Combined Lines: 850 1673 50.8 %
Date: 2024-08-13 16:37:32 Functions: 48 72 66.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 562 1595 35.2 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2015 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  *
       5                 :            :  *   Copyright (c) 2019-2021 Mellanox Technologies LTD. All rights reserved.
       6                 :            :  *   Copyright (c) 2021, 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       7                 :            :  */
       8                 :            : 
       9                 :            : #include "spdk/stdinc.h"
      10                 :            : 
      11                 :            : #include "spdk/config.h"
      12                 :            : #include "spdk/env.h"
      13                 :            : #include "spdk/fd.h"
      14                 :            : #include "spdk/nvme.h"
      15                 :            : #include "spdk/vmd.h"
      16                 :            : #include "spdk/queue.h"
      17                 :            : #include "spdk/string.h"
      18                 :            : #include "spdk/nvme_intel.h"
      19                 :            : #include "spdk/histogram_data.h"
      20                 :            : #include "spdk/endian.h"
      21                 :            : #include "spdk/dif.h"
      22                 :            : #include "spdk/util.h"
      23                 :            : #include "spdk/log.h"
      24                 :            : #include "spdk/likely.h"
      25                 :            : #include "spdk/sock.h"
      26                 :            : #include "spdk/zipf.h"
      27                 :            : #include "spdk/nvmf.h"
      28                 :            : 
      29                 :            : #ifdef SPDK_CONFIG_URING
      30                 :            : #include <liburing.h>
      31                 :            : #endif
      32                 :            : 
      33                 :            : #if HAVE_LIBAIO
      34                 :            : #include <libaio.h>
      35                 :            : #endif
      36                 :            : 
      37                 :            : #define HELP_RETURN_CODE UINT16_MAX
      38                 :            : 
      39                 :            : struct ctrlr_entry {
      40                 :            :         struct spdk_nvme_ctrlr                  *ctrlr;
      41                 :            :         enum spdk_nvme_transport_type           trtype;
      42                 :            :         struct spdk_nvme_intel_rw_latency_page  *latency_page;
      43                 :            : 
      44                 :            :         struct spdk_nvme_qpair                  **unused_qpairs;
      45                 :            : 
      46                 :            :         TAILQ_ENTRY(ctrlr_entry)                link;
      47                 :            :         char                                    name[1024];
      48                 :            : };
      49                 :            : 
      50                 :            : enum entry_type {
      51                 :            :         ENTRY_TYPE_NVME_NS,
      52                 :            :         ENTRY_TYPE_AIO_FILE,
      53                 :            :         ENTRY_TYPE_URING_FILE,
      54                 :            : };
      55                 :            : 
      56                 :            : struct ns_fn_table;
      57                 :            : 
      58                 :            : struct ns_entry {
      59                 :            :         enum entry_type         type;
      60                 :            :         const struct ns_fn_table        *fn_table;
      61                 :            : 
      62                 :            :         union {
      63                 :            :                 struct {
      64                 :            :                         struct spdk_nvme_ctrlr  *ctrlr;
      65                 :            :                         struct spdk_nvme_ns     *ns;
      66                 :            :                 } nvme;
      67                 :            : #ifdef SPDK_CONFIG_URING
      68                 :            :                 struct {
      69                 :            :                         int                     fd;
      70                 :            :                 } uring;
      71                 :            : #endif
      72                 :            : #if HAVE_LIBAIO
      73                 :            :                 struct {
      74                 :            :                         int                     fd;
      75                 :            :                 } aio;
      76                 :            : #endif
      77                 :            :         } u;
      78                 :            : 
      79                 :            :         TAILQ_ENTRY(ns_entry)   link;
      80                 :            :         uint32_t                io_size_blocks;
      81                 :            :         uint32_t                num_io_requests;
      82                 :            :         uint64_t                size_in_ios;
      83                 :            :         uint32_t                block_size;
      84                 :            :         uint32_t                md_size;
      85                 :            :         bool                    md_interleave;
      86                 :            :         unsigned int            seed;
      87                 :            :         struct spdk_zipf        *zipf;
      88                 :            :         bool                    pi_loc;
      89                 :            :         enum spdk_nvme_pi_type  pi_type;
      90                 :            :         uint32_t                io_flags;
      91                 :            :         char                    name[1024];
      92                 :            : };
      93                 :            : 
      94                 :            : static const double g_latency_cutoffs[] = {
      95                 :            :         0.01,
      96                 :            :         0.10,
      97                 :            :         0.25,
      98                 :            :         0.50,
      99                 :            :         0.75,
     100                 :            :         0.90,
     101                 :            :         0.95,
     102                 :            :         0.98,
     103                 :            :         0.99,
     104                 :            :         0.995,
     105                 :            :         0.999,
     106                 :            :         0.9999,
     107                 :            :         0.99999,
     108                 :            :         0.999999,
     109                 :            :         0.9999999,
     110                 :            :         -1,
     111                 :            : };
     112                 :            : 
     113                 :            : struct ns_worker_stats {
     114                 :            :         uint64_t                io_submitted;
     115                 :            :         uint64_t                io_completed;
     116                 :            :         uint64_t                last_io_completed;
     117                 :            :         uint64_t                total_tsc;
     118                 :            :         uint64_t                min_tsc;
     119                 :            :         uint64_t                max_tsc;
     120                 :            :         uint64_t                last_tsc;
     121                 :            :         uint64_t                busy_tsc;
     122                 :            :         uint64_t                idle_tsc;
     123                 :            :         uint64_t                last_busy_tsc;
     124                 :            :         uint64_t                last_idle_tsc;
     125                 :            : };
     126                 :            : 
     127                 :            : struct ns_worker_ctx {
     128                 :            :         struct ns_entry         *entry;
     129                 :            :         struct ns_worker_stats  stats;
     130                 :            :         uint64_t                current_queue_depth;
     131                 :            :         uint64_t                offset_in_ios;
     132                 :            :         bool                    is_draining;
     133                 :            : 
     134                 :            :         union {
     135                 :            :                 struct {
     136                 :            :                         int                             num_active_qpairs;
     137                 :            :                         int                             num_all_qpairs;
     138                 :            :                         struct spdk_nvme_qpair          **qpair;
     139                 :            :                         struct spdk_nvme_poll_group     *group;
     140                 :            :                         int                             last_qpair;
     141                 :            :                 } nvme;
     142                 :            : 
     143                 :            : #ifdef SPDK_CONFIG_URING
     144                 :            :                 struct {
     145                 :            :                         struct io_uring         ring;
     146                 :            :                         uint64_t                io_inflight;
     147                 :            :                         uint64_t                io_pending;
     148                 :            :                         struct io_uring_cqe     **cqes;
     149                 :            : 
     150                 :            :                 } uring;
     151                 :            : #endif
     152                 :            : #if HAVE_LIBAIO
     153                 :            :                 struct {
     154                 :            :                         struct io_event         *events;
     155                 :            :                         io_context_t            ctx;
     156                 :            :                 } aio;
     157                 :            : #endif
     158                 :            :         } u;
     159                 :            : 
     160                 :            :         TAILQ_ENTRY(ns_worker_ctx)      link;
     161                 :            : 
     162                 :            :         TAILQ_HEAD(, perf_task)         queued_tasks;
     163                 :            : 
     164                 :            :         struct spdk_histogram_data      *histogram;
     165                 :            :         int                             status;
     166                 :            : };
     167                 :            : 
     168                 :            : struct perf_task {
     169                 :            :         struct ns_worker_ctx    *ns_ctx;
     170                 :            :         struct iovec            *iovs; /* array of iovecs to transfer. */
     171                 :            :         int                     iovcnt; /* Number of iovecs in iovs array. */
     172                 :            :         int                     iovpos; /* Current iovec position. */
     173                 :            :         uint32_t                iov_offset; /* Offset in current iovec. */
     174                 :            :         struct iovec            md_iov;
     175                 :            :         uint64_t                submit_tsc;
     176                 :            :         bool                    is_read;
     177                 :            :         struct spdk_dif_ctx     dif_ctx;
     178                 :            : #if HAVE_LIBAIO
     179                 :            :         struct iocb             iocb;
     180                 :            : #endif
     181                 :            :         TAILQ_ENTRY(perf_task)  link;
     182                 :            : };
     183                 :            : 
     184                 :            : struct worker_thread {
     185                 :            :         TAILQ_HEAD(, ns_worker_ctx)     ns_ctx;
     186                 :            :         TAILQ_ENTRY(worker_thread)      link;
     187                 :            :         unsigned                        lcore;
     188                 :            : };
     189                 :            : 
     190                 :            : struct ns_fn_table {
     191                 :            :         void    (*setup_payload)(struct perf_task *task, uint8_t pattern);
     192                 :            : 
     193                 :            :         int     (*submit_io)(struct perf_task *task, struct ns_worker_ctx *ns_ctx,
     194                 :            :                              struct ns_entry *entry, uint64_t offset_in_ios);
     195                 :            : 
     196                 :            :         int64_t (*check_io)(struct ns_worker_ctx *ns_ctx);
     197                 :            : 
     198                 :            :         void    (*verify_io)(struct perf_task *task, struct ns_entry *entry);
     199                 :            : 
     200                 :            :         int     (*init_ns_worker_ctx)(struct ns_worker_ctx *ns_ctx);
     201                 :            : 
     202                 :            :         void    (*cleanup_ns_worker_ctx)(struct ns_worker_ctx *ns_ctx);
     203                 :            :         void    (*dump_transport_stats)(uint32_t lcore, struct ns_worker_ctx *ns_ctx);
     204                 :            : };
     205                 :            : 
     206                 :            : static uint32_t g_io_unit_size = (UINT32_MAX & (~0x03));
     207                 :            : 
     208                 :            : static int g_outstanding_commands;
     209                 :            : 
     210                 :            : static bool g_latency_ssd_tracking_enable;
     211                 :            : static int g_latency_sw_tracking_level;
     212                 :            : 
     213                 :            : static bool g_vmd;
     214                 :            : static const char *g_workload_type;
     215                 :            : static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers);
     216                 :            : static TAILQ_HEAD(, ns_entry) g_namespaces = TAILQ_HEAD_INITIALIZER(g_namespaces);
     217                 :            : static uint32_t g_num_namespaces;
     218                 :            : static TAILQ_HEAD(, worker_thread) g_workers = TAILQ_HEAD_INITIALIZER(g_workers);
     219                 :            : static uint32_t g_num_workers = 0;
     220                 :            : static bool g_use_every_core = false;
     221                 :            : static uint32_t g_main_core;
     222                 :            : static pthread_barrier_t g_worker_sync_barrier;
     223                 :            : 
     224                 :            : static uint64_t g_tsc_rate;
     225                 :            : 
     226                 :            : static bool g_monitor_perf_cores = false;
     227                 :            : 
     228                 :            : static uint32_t g_io_align = 0x200;
     229                 :            : static bool g_io_align_specified;
     230                 :            : static uint32_t g_io_size_bytes;
     231                 :            : static uint32_t g_max_io_md_size;
     232                 :            : static uint32_t g_max_io_size_blocks;
     233                 :            : static uint32_t g_metacfg_pract_flag;
     234                 :            : static uint32_t g_metacfg_prchk_flags;
     235                 :            : static int g_rw_percentage = -1;
     236                 :            : static int g_is_random;
     237                 :            : static uint32_t g_queue_depth;
     238                 :            : static int g_nr_io_queues_per_ns = 1;
     239                 :            : static int g_nr_unused_io_queues;
     240                 :            : static int g_time_in_sec;
     241                 :            : static uint64_t g_number_ios;
     242                 :            : static uint64_t g_elapsed_time_in_usec;
     243                 :            : static int g_warmup_time_in_sec;
     244                 :            : static uint32_t g_max_completions;
     245                 :            : static uint32_t g_disable_sq_cmb;
     246                 :            : static bool g_use_uring;
     247                 :            : static bool g_warn;
     248                 :            : static bool g_header_digest;
     249                 :            : static bool g_data_digest;
     250                 :            : static bool g_no_shn_notification;
     251                 :            : static bool g_mix_specified;
     252                 :            : /* The flag is used to exit the program while keep alive fails on the transport */
     253                 :            : static bool g_exit;
     254                 :            : /* Default to 10 seconds for the keep alive value. This value is arbitrary. */
     255                 :            : static uint32_t g_keep_alive_timeout_in_ms = 10000;
     256                 :            : static bool g_continue_on_error = false;
     257                 :            : static uint32_t g_quiet_count = 1;
     258                 :            : static double g_zipf_theta;
     259                 :            : /* Set default io_queue_size to UINT16_MAX, NVMe driver will then reduce this
     260                 :            :  * to MQES to maximize the io_queue_size as much as possible.
     261                 :            :  */
     262                 :            : static uint32_t g_io_queue_size = UINT16_MAX;
     263                 :            : 
     264                 :            : static uint32_t g_sock_zcopy_threshold;
     265                 :            : static char *g_sock_threshold_impl;
     266                 :            : 
     267                 :            : static uint8_t g_transport_tos = 0;
     268                 :            : 
     269                 :            : static uint32_t g_rdma_srq_size;
     270                 :            : uint8_t *g_psk = NULL;
     271                 :            : 
     272                 :            : /* When user specifies -Q, some error messages are rate limited.  When rate
     273                 :            :  * limited, we only print the error message every g_quiet_count times the
     274                 :            :  * error occurs.
     275                 :            :  *
     276                 :            :  * Note: the __count is not thread safe, meaning the rate limiting will not
     277                 :            :  * be exact when running perf with multiple thread with lots of errors.
     278                 :            :  * Thread-local __count would mean rate-limiting per thread which doesn't
     279                 :            :  * seem as useful.
     280                 :            :  */
     281                 :            : #define RATELIMIT_LOG(...) \
     282                 :            :         {                                                               \
     283                 :            :                 static uint64_t __count = 0;                            \
     284                 :            :                 if ((__count % g_quiet_count) == 0) {                   \
     285                 :            :                         if (__count > 0 && g_quiet_count > 1) {           \
     286                 :            :                                 fprintf(stderr, "Message suppressed %" PRIu32 " times: ",   \
     287                 :            :                                         g_quiet_count - 1);             \
     288                 :            :                         }                                               \
     289                 :            :                         fprintf(stderr, __VA_ARGS__);                   \
     290                 :            :                 }                                                       \
     291                 :            :                 __count++;                                              \
     292                 :            :         }
     293                 :            : 
     294                 :            : static bool g_dump_transport_stats;
     295                 :            : static pthread_mutex_t g_stats_mutex;
     296                 :            : 
     297                 :            : #define MAX_ALLOWED_PCI_DEVICE_NUM 128
     298                 :            : static struct spdk_pci_addr g_allowed_pci_addr[MAX_ALLOWED_PCI_DEVICE_NUM];
     299                 :            : 
     300                 :            : struct trid_entry {
     301                 :            :         struct spdk_nvme_transport_id   trid;
     302                 :            :         uint16_t                        nsid;
     303                 :            :         char                            hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
     304                 :            :         TAILQ_ENTRY(trid_entry)         tailq;
     305                 :            : };
     306                 :            : 
     307                 :            : static TAILQ_HEAD(, trid_entry) g_trid_list = TAILQ_HEAD_INITIALIZER(g_trid_list);
     308                 :            : 
     309                 :            : static int g_file_optind; /* Index of first filename in argv */
     310                 :            : 
     311                 :            : static inline void task_complete(struct perf_task *task);
     312                 :            : 
     313                 :            : static void
     314                 :          3 : perf_set_sock_opts(const char *impl_name, const char *field, uint32_t val, const char *valstr)
     315                 :            : {
     316                 :          3 :         struct spdk_sock_impl_opts sock_opts = {};
     317                 :          3 :         size_t opts_size = sizeof(sock_opts);
     318                 :            :         int rc;
     319                 :            : 
     320                 :          3 :         rc = spdk_sock_impl_get_opts(impl_name, &sock_opts, &opts_size);
     321         [ -  + ]:          3 :         if (rc != 0) {
     322         [ #  # ]:          0 :                 if (errno == EINVAL) {
     323         [ #  # ]:          0 :                         fprintf(stderr, "Unknown sock impl %s\n", impl_name);
     324                 :            :                 } else {
     325         [ #  # ]:          0 :                         fprintf(stderr, "Failed to get opts for sock impl %s: error %d (%s)\n", impl_name, errno,
     326                 :          0 :                                 strerror(errno));
     327                 :            :                 }
     328                 :          0 :                 return;
     329                 :            :         }
     330                 :            : 
     331         [ -  + ]:          3 :         if (opts_size != sizeof(sock_opts)) {
     332         [ #  # ]:          0 :                 fprintf(stderr, "Warning: sock_opts size mismatch. Expected %zu, received %zu\n",
     333                 :            :                         sizeof(sock_opts), opts_size);
     334                 :          0 :                 opts_size = sizeof(sock_opts);
     335                 :            :         }
     336                 :            : 
     337         [ -  + ]:          3 :         if (!field) {
     338         [ #  # ]:          0 :                 fprintf(stderr, "Warning: no socket opts field specified\n");
     339                 :          0 :                 return;
     340   [ -  +  -  + ]:          3 :         } else if (strcmp(field, "enable_zerocopy_send_client") == 0) {
     341                 :          0 :                 sock_opts.enable_zerocopy_send_client = val;
     342   [ -  +  -  + ]:          3 :         } else if (strcmp(field, "tls_version") == 0) {
     343                 :          0 :                 sock_opts.tls_version = val;
     344   [ -  +  -  + ]:          3 :         } else if (strcmp(field, "ktls") == 0) {
     345                 :          0 :                 sock_opts.enable_ktls = val;
     346   [ -  +  +  - ]:          3 :         } else if (strcmp(field, "psk_path") == 0) {
     347         [ -  + ]:          3 :                 if (!valstr) {
     348         [ #  # ]:          0 :                         fprintf(stderr, "No socket opts value specified\n");
     349                 :          0 :                         return;
     350                 :            :                 }
     351                 :          3 :                 g_psk = calloc(1, SPDK_TLS_PSK_MAX_LEN + 1);
     352         [ -  + ]:          3 :                 if (g_psk == NULL) {
     353         [ #  # ]:          0 :                         fprintf(stderr, "Failed to allocate memory for psk\n");
     354                 :          0 :                         return;
     355                 :            :                 }
     356                 :          3 :                 FILE *psk_file = fopen(valstr, "r");
     357         [ -  + ]:          3 :                 if (psk_file == NULL) {
     358         [ #  # ]:          0 :                         fprintf(stderr, "Could not open PSK file\n");
     359                 :          0 :                         return;
     360                 :            :                 }
     361   [ -  +  #  # ]:          3 :                 if (fscanf(psk_file, "%" SPDK_STRINGIFY(SPDK_TLS_PSK_MAX_LEN) "s", g_psk) != 1) {
     362         [ #  # ]:          0 :                         fprintf(stderr, "Could not retrieve PSK from file\n");
     363         [ #  # ]:          0 :                         fclose(psk_file);
     364                 :          0 :                         return;
     365                 :            :                 }
     366   [ -  +  -  + ]:          3 :                 if (fclose(psk_file)) {
     367         [ #  # ]:          0 :                         fprintf(stderr, "Failed to close PSK file\n");
     368                 :          0 :                         return;
     369                 :            :                 }
     370   [ #  #  #  # ]:          0 :         } else if (strcmp(field, "zerocopy_threshold") == 0) {
     371                 :          0 :                 sock_opts.zerocopy_threshold = val;
     372                 :            :         } else {
     373         [ #  # ]:          0 :                 fprintf(stderr, "Warning: invalid or unprocessed socket opts field: %s\n", field);
     374                 :          0 :                 return;
     375                 :            :         }
     376                 :            : 
     377         [ -  + ]:          3 :         if (spdk_sock_impl_set_opts(impl_name, &sock_opts, opts_size)) {
     378         [ #  # ]:          0 :                 fprintf(stderr, "Failed to set %s: %d for sock impl %s : error %d (%s)\n", field, val, impl_name,
     379                 :          0 :                         errno, strerror(errno));
     380                 :            :         }
     381                 :            : }
     382                 :            : 
     383                 :            : static void
     384                 :     117396 : nvme_perf_reset_sgl(void *ref, uint32_t sgl_offset)
     385                 :            : {
     386                 :            :         struct iovec *iov;
     387                 :     117396 :         struct perf_task *task = (struct perf_task *)ref;
     388                 :            : 
     389                 :     117396 :         task->iov_offset = sgl_offset;
     390         [ +  - ]:     586980 :         for (task->iovpos = 0; task->iovpos < task->iovcnt; task->iovpos++) {
     391                 :     586980 :                 iov = &task->iovs[task->iovpos];
     392         [ +  + ]:     586980 :                 if (task->iov_offset < iov->iov_len) {
     393                 :     117396 :                         break;
     394                 :            :                 }
     395                 :            : 
     396                 :     469584 :                 task->iov_offset -= iov->iov_len;
     397                 :            :         }
     398                 :     117396 : }
     399                 :            : 
     400                 :            : static int
     401                 :     939168 : nvme_perf_next_sge(void *ref, void **address, uint32_t *length)
     402                 :            : {
     403                 :            :         struct iovec *iov;
     404                 :     939168 :         struct perf_task *task = (struct perf_task *)ref;
     405                 :            : 
     406         [ -  + ]:     939168 :         assert(task->iovpos < task->iovcnt);
     407                 :            : 
     408                 :     939168 :         iov = &task->iovs[task->iovpos];
     409         [ -  + ]:     939168 :         assert(task->iov_offset <= iov->iov_len);
     410                 :            : 
     411                 :     939168 :         *address = iov->iov_base + task->iov_offset;
     412                 :     939168 :         *length = iov->iov_len - task->iov_offset;
     413                 :     939168 :         task->iovpos++;
     414                 :     939168 :         task->iov_offset = 0;
     415                 :            : 
     416                 :     939168 :         return 0;
     417                 :            : }
     418                 :            : 
     419                 :            : static int
     420                 :      12787 : nvme_perf_allocate_iovs(struct perf_task *task, void *buf, uint32_t length)
     421                 :            : {
     422                 :      12787 :         int iovpos = 0;
     423                 :            :         struct iovec *iov;
     424                 :      12787 :         uint32_t offset = 0;
     425                 :            : 
     426         [ -  + ]:      12787 :         task->iovcnt = SPDK_CEIL_DIV(length, (uint64_t)g_io_unit_size);
     427                 :      12787 :         task->iovs = calloc(task->iovcnt, sizeof(struct iovec));
     428         [ -  + ]:      12787 :         if (!task->iovs) {
     429                 :          0 :                 return -1;
     430                 :            :         }
     431                 :            : 
     432         [ +  + ]:      40934 :         while (length > 0) {
     433                 :      28147 :                 iov = &task->iovs[iovpos];
     434                 :      28147 :                 iov->iov_len = spdk_min(length, g_io_unit_size);
     435                 :      28147 :                 iov->iov_base = buf + offset;
     436                 :      28147 :                 length -= iov->iov_len;
     437                 :      28147 :                 offset += iov->iov_len;
     438                 :      28147 :                 iovpos++;
     439                 :            :         }
     440                 :            : 
     441                 :      12787 :         return 0;
     442                 :            : }
     443                 :            : 
     444                 :            : #ifdef SPDK_CONFIG_URING
     445                 :            : 
     446                 :            : static void
     447                 :          0 : uring_setup_payload(struct perf_task *task, uint8_t pattern)
     448                 :            : {
     449                 :            :         struct iovec *iov;
     450                 :            : 
     451                 :          0 :         task->iovs = calloc(1, sizeof(struct iovec));
     452         [ #  # ]:          0 :         if (!task->iovs) {
     453   [ #  #  #  # ]:          0 :                 fprintf(stderr, "perf task failed to allocate iovs\n");
     454                 :          0 :                 exit(1);
     455                 :            :         }
     456                 :          0 :         task->iovcnt = 1;
     457                 :            : 
     458                 :          0 :         iov = &task->iovs[0];
     459                 :          0 :         iov->iov_base = spdk_dma_zmalloc(g_io_size_bytes, g_io_align, NULL);
     460                 :          0 :         iov->iov_len = g_io_size_bytes;
     461         [ #  # ]:          0 :         if (iov->iov_base == NULL) {
     462   [ #  #  #  # ]:          0 :                 fprintf(stderr, "spdk_dma_zmalloc() for task->iovs[0].iov_base failed\n");
     463                 :          0 :                 free(task->iovs);
     464                 :          0 :                 exit(1);
     465                 :            :         }
     466         [ #  # ]:          0 :         memset(iov->iov_base, pattern, iov->iov_len);
     467                 :          0 : }
     468                 :            : 
     469                 :            : static int
     470                 :          0 : uring_submit_io(struct perf_task *task, struct ns_worker_ctx *ns_ctx,
     471                 :            :                 struct ns_entry *entry, uint64_t offset_in_ios)
     472                 :            : {
     473                 :            :         struct io_uring_sqe *sqe;
     474                 :            : 
     475                 :          0 :         sqe = io_uring_get_sqe(&ns_ctx->u.uring.ring);
     476         [ #  # ]:          0 :         if (!sqe) {
     477   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Cannot get sqe\n");
     478                 :          0 :                 return -1;
     479                 :            :         }
     480                 :            : 
     481   [ #  #  #  # ]:          0 :         if (task->is_read) {
     482                 :          0 :                 io_uring_prep_readv(sqe, entry->u.uring.fd, task->iovs, 1, offset_in_ios * task->iovs[0].iov_len);
     483                 :            :         } else {
     484                 :          0 :                 io_uring_prep_writev(sqe, entry->u.uring.fd, task->iovs, 1, offset_in_ios * task->iovs[0].iov_len);
     485                 :            :         }
     486                 :            : 
     487                 :          0 :         io_uring_sqe_set_data(sqe, task);
     488                 :          0 :         ns_ctx->u.uring.io_pending++;
     489                 :            : 
     490                 :          0 :         return 0;
     491                 :            : }
     492                 :            : 
     493                 :            : static int64_t
     494                 :          0 : uring_check_io(struct ns_worker_ctx *ns_ctx)
     495                 :            : {
     496                 :          0 :         int i, to_complete, to_submit, count = 0, ret = 0;
     497                 :            :         struct perf_task *task;
     498                 :            : 
     499                 :          0 :         to_submit = ns_ctx->u.uring.io_pending;
     500                 :            : 
     501         [ #  # ]:          0 :         if (to_submit > 0) {
     502                 :            :                 /* If there are I/O to submit, use io_uring_submit here.
     503                 :            :                  * It will automatically call spdk_io_uring_enter appropriately. */
     504                 :          0 :                 ret = io_uring_submit(&ns_ctx->u.uring.ring);
     505         [ #  # ]:          0 :                 if (ret < 0) {
     506                 :          0 :                         ns_ctx->status = 1;
     507                 :          0 :                         return -1;
     508                 :            :                 }
     509                 :          0 :                 ns_ctx->u.uring.io_pending = 0;
     510                 :          0 :                 ns_ctx->u.uring.io_inflight += to_submit;
     511                 :            :         }
     512                 :            : 
     513                 :          0 :         to_complete = ns_ctx->u.uring.io_inflight;
     514         [ #  # ]:          0 :         if (to_complete > 0) {
     515                 :          0 :                 count = io_uring_peek_batch_cqe(&ns_ctx->u.uring.ring, ns_ctx->u.uring.cqes, to_complete);
     516                 :          0 :                 ns_ctx->u.uring.io_inflight -= count;
     517         [ #  # ]:          0 :                 for (i = 0; i < count; i++) {
     518                 :            :                         int res;
     519                 :            : 
     520         [ #  # ]:          0 :                         assert(ns_ctx->u.uring.cqes[i] != NULL);
     521                 :          0 :                         task = (struct perf_task *)ns_ctx->u.uring.cqes[i]->user_data;
     522                 :          0 :                         res = ns_ctx->u.uring.cqes[i]->res;
     523         [ #  # ]:          0 :                         if (res != (int)task->iovs[0].iov_len) {
     524         [ #  # ]:          0 :                                 fprintf(stderr, "cqe->status=%d, iov_len=%d\n", res,
     525         [ #  # ]:          0 :                                         (int)task->iovs[0].iov_len);
     526                 :          0 :                                 ns_ctx->status = 1;
     527         [ #  # ]:          0 :                                 if (res == -EIO) {
     528                 :            :                                         /* The block device has been removed.
     529                 :            :                                          * Stop trying to send I/O to it.
     530                 :            :                                          */
     531                 :          0 :                                         ns_ctx->is_draining = true;
     532                 :            :                                 }
     533                 :            :                         }
     534                 :          0 :                         io_uring_cqe_seen(&ns_ctx->u.uring.ring, ns_ctx->u.uring.cqes[i]);
     535                 :          0 :                         task_complete(task);
     536                 :            :                 }
     537                 :            :         }
     538                 :          0 :         return count;
     539                 :            : }
     540                 :            : 
     541                 :            : static void
     542                 :          0 : uring_verify_io(struct perf_task *task, struct ns_entry *entry)
     543                 :            : {
     544                 :          0 : }
     545                 :            : 
     546                 :            : static int
     547                 :          0 : uring_init_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
     548                 :            : {
     549         [ #  # ]:          0 :         if (io_uring_queue_init(g_queue_depth, &ns_ctx->u.uring.ring, 0) < 0) {
     550                 :          0 :                 SPDK_ERRLOG("uring I/O context setup failure\n");
     551                 :          0 :                 return -1;
     552                 :            :         }
     553                 :            : 
     554                 :          0 :         ns_ctx->u.uring.cqes = calloc(g_queue_depth, sizeof(struct io_uring_cqe *));
     555         [ #  # ]:          0 :         if (!ns_ctx->u.uring.cqes) {
     556                 :          0 :                 io_uring_queue_exit(&ns_ctx->u.uring.ring);
     557                 :          0 :                 return -1;
     558                 :            :         }
     559                 :            : 
     560                 :          0 :         return 0;
     561                 :            : }
     562                 :            : 
     563                 :            : static void
     564                 :          0 : uring_cleanup_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
     565                 :            : {
     566                 :          0 :         io_uring_queue_exit(&ns_ctx->u.uring.ring);
     567                 :          0 :         free(ns_ctx->u.uring.cqes);
     568                 :          0 : }
     569                 :            : 
     570                 :            : static const struct ns_fn_table uring_fn_table = {
     571                 :            :         .setup_payload          = uring_setup_payload,
     572                 :            :         .submit_io              = uring_submit_io,
     573                 :            :         .check_io               = uring_check_io,
     574                 :            :         .verify_io              = uring_verify_io,
     575                 :            :         .init_ns_worker_ctx     = uring_init_ns_worker_ctx,
     576                 :            :         .cleanup_ns_worker_ctx  = uring_cleanup_ns_worker_ctx,
     577                 :            : };
     578                 :            : 
     579                 :            : #endif
     580                 :            : 
     581                 :            : #ifdef HAVE_LIBAIO
     582                 :            : static void
     583                 :          0 : aio_setup_payload(struct perf_task *task, uint8_t pattern)
     584                 :            : {
     585                 :            :         struct iovec *iov;
     586                 :            : 
     587                 :          0 :         task->iovs = calloc(1, sizeof(struct iovec));
     588         [ #  # ]:          0 :         if (!task->iovs) {
     589   [ #  #  #  # ]:          0 :                 fprintf(stderr, "perf task failed to allocate iovs\n");
     590                 :          0 :                 exit(1);
     591                 :            :         }
     592                 :          0 :         task->iovcnt = 1;
     593                 :            : 
     594                 :          0 :         iov = &task->iovs[0];
     595                 :          0 :         iov->iov_base = spdk_dma_zmalloc(g_io_size_bytes, g_io_align, NULL);
     596                 :          0 :         iov->iov_len = g_io_size_bytes;
     597         [ #  # ]:          0 :         if (iov->iov_base == NULL) {
     598   [ #  #  #  # ]:          0 :                 fprintf(stderr, "spdk_dma_zmalloc() for task->iovs[0].iov_base failed\n");
     599                 :          0 :                 free(task->iovs);
     600                 :          0 :                 exit(1);
     601                 :            :         }
     602         [ #  # ]:          0 :         memset(iov->iov_base, pattern, iov->iov_len);
     603                 :          0 : }
     604                 :            : 
     605                 :            : static int
     606                 :          0 : aio_submit(io_context_t aio_ctx, struct iocb *iocb, int fd, enum io_iocb_cmd cmd,
     607                 :            :            struct iovec *iov, uint64_t offset, void *cb_ctx)
     608                 :            : {
     609                 :          0 :         iocb->aio_fildes = fd;
     610                 :          0 :         iocb->aio_reqprio = 0;
     611                 :          0 :         iocb->aio_lio_opcode = cmd;
     612                 :          0 :         iocb->u.c.buf = iov->iov_base;
     613                 :          0 :         iocb->u.c.nbytes = iov->iov_len;
     614                 :          0 :         iocb->u.c.offset = offset * iov->iov_len;
     615                 :          0 :         iocb->data = cb_ctx;
     616                 :            : 
     617         [ #  # ]:          0 :         if (io_submit(aio_ctx, 1, &iocb) < 0) {
     618         [ #  # ]:          0 :                 printf("io_submit");
     619                 :          0 :                 return -1;
     620                 :            :         }
     621                 :            : 
     622                 :          0 :         return 0;
     623                 :            : }
     624                 :            : 
     625                 :            : static int
     626                 :          0 : aio_submit_io(struct perf_task *task, struct ns_worker_ctx *ns_ctx,
     627                 :            :               struct ns_entry *entry, uint64_t offset_in_ios)
     628                 :            : {
     629   [ #  #  #  # ]:          0 :         if (task->is_read) {
     630                 :          0 :                 return aio_submit(ns_ctx->u.aio.ctx, &task->iocb, entry->u.aio.fd, IO_CMD_PREAD,
     631                 :            :                                   task->iovs, offset_in_ios, task);
     632                 :            :         } else {
     633                 :          0 :                 return aio_submit(ns_ctx->u.aio.ctx, &task->iocb, entry->u.aio.fd, IO_CMD_PWRITE,
     634                 :            :                                   task->iovs, offset_in_ios, task);
     635                 :            :         }
     636                 :            : }
     637                 :            : 
     638                 :            : static int64_t
     639                 :          0 : aio_check_io(struct ns_worker_ctx *ns_ctx)
     640                 :            : {
     641                 :            :         int count, i;
     642                 :          0 :         struct timespec timeout;
     643                 :            :         struct perf_task *task;
     644                 :            : 
     645                 :          0 :         timeout.tv_sec = 0;
     646                 :          0 :         timeout.tv_nsec = 0;
     647                 :            : 
     648                 :          0 :         count = io_getevents(ns_ctx->u.aio.ctx, 1, g_queue_depth, ns_ctx->u.aio.events, &timeout);
     649         [ #  # ]:          0 :         if (count < 0) {
     650   [ #  #  #  # ]:          0 :                 fprintf(stderr, "io_getevents error\n");
     651                 :          0 :                 ns_ctx->status = 1;
     652                 :          0 :                 return -1;
     653                 :            :         }
     654                 :            : 
     655         [ #  # ]:          0 :         for (i = 0; i < count; i++) {
     656                 :            :                 unsigned long res;
     657                 :            : 
     658                 :          0 :                 task = (struct perf_task *)ns_ctx->u.aio.events[i].data;
     659                 :          0 :                 res = ns_ctx->u.aio.events[i].res;
     660         [ #  # ]:          0 :                 if (res != (uint64_t)task->iovs[0].iov_len) {
     661         [ #  # ]:          0 :                         fprintf(stderr, "event->res=%ld, iov_len=%lu\n", (long)res,
     662         [ #  # ]:          0 :                                 (uint64_t)task->iovs[0].iov_len);
     663                 :          0 :                         ns_ctx->status = 1;
     664         [ #  # ]:          0 :                         if ((long)res == -EIO) {
     665                 :            :                                 /* The block device has been removed.  Stop trying to send I/O to it. */
     666                 :          0 :                                 ns_ctx->is_draining = true;
     667                 :            :                         }
     668                 :            :                 }
     669                 :          0 :                 task_complete(ns_ctx->u.aio.events[i].data);
     670                 :            :         }
     671                 :          0 :         return count;
     672                 :            : }
     673                 :            : 
     674                 :            : static void
     675                 :          0 : aio_verify_io(struct perf_task *task, struct ns_entry *entry)
     676                 :            : {
     677                 :          0 : }
     678                 :            : 
     679                 :            : static int
     680                 :          0 : aio_init_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
     681                 :            : {
     682                 :          0 :         ns_ctx->u.aio.events = calloc(g_queue_depth, sizeof(struct io_event));
     683         [ #  # ]:          0 :         if (!ns_ctx->u.aio.events) {
     684                 :          0 :                 return -1;
     685                 :            :         }
     686                 :          0 :         ns_ctx->u.aio.ctx = 0;
     687         [ #  # ]:          0 :         if (io_setup(g_queue_depth, &ns_ctx->u.aio.ctx) < 0) {
     688                 :          0 :                 free(ns_ctx->u.aio.events);
     689                 :          0 :                 perror("io_setup");
     690                 :          0 :                 return -1;
     691                 :            :         }
     692                 :          0 :         return 0;
     693                 :            : }
     694                 :            : 
     695                 :            : static void
     696                 :          0 : aio_cleanup_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
     697                 :            : {
     698                 :          0 :         io_destroy(ns_ctx->u.aio.ctx);
     699                 :          0 :         free(ns_ctx->u.aio.events);
     700                 :          0 : }
     701                 :            : 
     702                 :            : static const struct ns_fn_table aio_fn_table = {
     703                 :            :         .setup_payload          = aio_setup_payload,
     704                 :            :         .submit_io              = aio_submit_io,
     705                 :            :         .check_io               = aio_check_io,
     706                 :            :         .verify_io              = aio_verify_io,
     707                 :            :         .init_ns_worker_ctx     = aio_init_ns_worker_ctx,
     708                 :            :         .cleanup_ns_worker_ctx  = aio_cleanup_ns_worker_ctx,
     709                 :            : };
     710                 :            : 
     711                 :            : #endif /* HAVE_LIBAIO */
     712                 :            : 
     713                 :            : #if defined(HAVE_LIBAIO) || defined(SPDK_CONFIG_URING)
     714                 :            : 
     715                 :            : static int
     716                 :          0 : register_file(const char *path)
     717                 :            : {
     718                 :            :         struct ns_entry *entry;
     719                 :            : 
     720                 :            :         int flags, fd;
     721                 :            :         uint64_t size;
     722                 :            :         uint32_t blklen;
     723                 :            : 
     724         [ #  # ]:          0 :         if (g_rw_percentage == 100) {
     725                 :          0 :                 flags = O_RDONLY;
     726         [ #  # ]:          0 :         } else if (g_rw_percentage == 0) {
     727                 :          0 :                 flags = O_WRONLY;
     728                 :            :         } else {
     729                 :          0 :                 flags = O_RDWR;
     730                 :            :         }
     731                 :            : 
     732                 :          0 :         flags |= O_DIRECT;
     733                 :            : 
     734         [ #  # ]:          0 :         fd = open(path, flags);
     735         [ #  # ]:          0 :         if (fd < 0) {
     736         [ #  # ]:          0 :                 fprintf(stderr, "Could not open device %s: %s\n", path, strerror(errno));
     737                 :          0 :                 return -1;
     738                 :            :         }
     739                 :            : 
     740                 :          0 :         size = spdk_fd_get_size(fd);
     741         [ #  # ]:          0 :         if (size == 0) {
     742         [ #  # ]:          0 :                 fprintf(stderr, "Could not determine size of device %s\n", path);
     743                 :          0 :                 close(fd);
     744                 :          0 :                 return -1;
     745                 :            :         }
     746                 :            : 
     747                 :          0 :         blklen = spdk_fd_get_blocklen(fd);
     748         [ #  # ]:          0 :         if (blklen == 0) {
     749         [ #  # ]:          0 :                 fprintf(stderr, "Could not determine block size of device %s\n", path);
     750                 :          0 :                 close(fd);
     751                 :          0 :                 return -1;
     752                 :            :         }
     753                 :            : 
     754                 :            :         /*
     755                 :            :          * TODO: This should really calculate the LCM of the current g_io_align and blklen.
     756                 :            :          * For now, it's fairly safe to just assume all block sizes are powers of 2.
     757                 :            :          */
     758         [ #  # ]:          0 :         if (g_io_align < blklen) {
     759   [ #  #  #  # ]:          0 :                 if (g_io_align_specified) {
     760         [ #  # ]:          0 :                         fprintf(stderr, "Wrong IO alignment (%u). aio requires block-sized alignment (%u)\n", g_io_align,
     761                 :            :                                 blklen);
     762                 :          0 :                         close(fd);
     763                 :          0 :                         return -1;
     764                 :            :                 }
     765                 :            : 
     766                 :          0 :                 g_io_align = blklen;
     767                 :            :         }
     768                 :            : 
     769                 :          0 :         entry = calloc(1, sizeof(struct ns_entry));
     770         [ #  # ]:          0 :         if (entry == NULL) {
     771                 :          0 :                 close(fd);
     772                 :          0 :                 perror("ns_entry malloc");
     773                 :          0 :                 return -1;
     774                 :            :         }
     775                 :            : 
     776   [ #  #  #  # ]:          0 :         if (g_use_uring) {
     777                 :            : #ifdef SPDK_CONFIG_URING
     778                 :          0 :                 entry->type = ENTRY_TYPE_URING_FILE;
     779                 :          0 :                 entry->fn_table = &uring_fn_table;
     780                 :          0 :                 entry->u.uring.fd = fd;
     781                 :            : #endif
     782                 :            :         } else {
     783                 :            : #if HAVE_LIBAIO
     784                 :          0 :                 entry->type = ENTRY_TYPE_AIO_FILE;
     785                 :          0 :                 entry->fn_table = &aio_fn_table;
     786                 :          0 :                 entry->u.aio.fd = fd;
     787                 :            : #endif
     788                 :            :         }
     789         [ #  # ]:          0 :         entry->size_in_ios = size / g_io_size_bytes;
     790         [ #  # ]:          0 :         entry->io_size_blocks = g_io_size_bytes / blklen;
     791                 :            : 
     792         [ #  # ]:          0 :         if (g_is_random) {
     793                 :          0 :                 entry->seed = rand();
     794         [ #  # ]:          0 :                 if (g_zipf_theta > 0) {
     795                 :          0 :                         entry->zipf = spdk_zipf_create(entry->size_in_ios, g_zipf_theta, 0);
     796                 :            :                 }
     797                 :            :         }
     798                 :            : 
     799                 :          0 :         snprintf(entry->name, sizeof(entry->name), "%s", path);
     800                 :            : 
     801                 :          0 :         g_num_namespaces++;
     802                 :          0 :         TAILQ_INSERT_TAIL(&g_namespaces, entry, link);
     803                 :            : 
     804                 :          0 :         return 0;
     805                 :            : }
     806                 :            : 
     807                 :            : static int
     808                 :        137 : register_files(int argc, char **argv)
     809                 :            : {
     810                 :            :         int i;
     811                 :            : 
     812                 :            :         /* Treat everything after the options as files for AIO/URING */
     813         [ -  + ]:        137 :         for (i = g_file_optind; i < argc; i++) {
     814         [ #  # ]:          0 :                 if (register_file(argv[i]) != 0) {
     815                 :          0 :                         return 1;
     816                 :            :                 }
     817                 :            :         }
     818                 :            : 
     819                 :        137 :         return 0;
     820                 :            : }
     821                 :            : #endif
     822                 :            : 
     823                 :            : static void io_complete(void *ctx, const struct spdk_nvme_cpl *cpl);
     824                 :            : 
     825                 :            : static void
     826                 :      12787 : nvme_setup_payload(struct perf_task *task, uint8_t pattern)
     827                 :            : {
     828                 :            :         uint32_t max_io_size_bytes, max_io_md_size;
     829                 :            :         void *buf;
     830                 :            :         int rc;
     831                 :            : 
     832                 :            :         /* maximum extended lba format size from all active namespace,
     833                 :            :          * it's same with g_io_size_bytes for namespace without metadata.
     834                 :            :          */
     835                 :      12787 :         max_io_size_bytes = g_io_size_bytes + g_max_io_md_size * g_max_io_size_blocks;
     836                 :      12787 :         buf = spdk_dma_zmalloc(max_io_size_bytes, g_io_align, NULL);
     837         [ -  + ]:      12787 :         if (buf == NULL) {
     838   [ #  #  #  # ]:          0 :                 fprintf(stderr, "task->buf spdk_dma_zmalloc failed\n");
     839                 :          0 :                 exit(1);
     840                 :            :         }
     841         [ -  + ]:      12787 :         memset(buf, pattern, max_io_size_bytes);
     842                 :            : 
     843                 :      12787 :         rc = nvme_perf_allocate_iovs(task, buf, max_io_size_bytes);
     844         [ -  + ]:      12787 :         if (rc < 0) {
     845   [ #  #  #  # ]:          0 :                 fprintf(stderr, "perf task failed to allocate iovs\n");
     846                 :          0 :                 spdk_dma_free(buf);
     847                 :          0 :                 exit(1);
     848                 :            :         }
     849                 :            : 
     850                 :      12787 :         max_io_md_size = g_max_io_md_size * g_max_io_size_blocks;
     851         [ +  + ]:      12787 :         if (max_io_md_size != 0) {
     852                 :       2112 :                 task->md_iov.iov_base = spdk_dma_zmalloc(max_io_md_size, g_io_align, NULL);
     853                 :       2112 :                 task->md_iov.iov_len = max_io_md_size;
     854         [ -  + ]:       2112 :                 if (task->md_iov.iov_base == NULL) {
     855   [ #  #  #  # ]:          0 :                         fprintf(stderr, "task->md_buf spdk_dma_zmalloc failed\n");
     856                 :          0 :                         spdk_dma_free(task->iovs[0].iov_base);
     857                 :          0 :                         free(task->iovs);
     858                 :          0 :                         exit(1);
     859                 :            :                 }
     860                 :            :         }
     861                 :      12787 : }
     862                 :            : 
     863                 :            : static int
     864                 :   12467069 : nvme_submit_io(struct perf_task *task, struct ns_worker_ctx *ns_ctx,
     865                 :            :                struct ns_entry *entry, uint64_t offset_in_ios)
     866                 :            : {
     867                 :            :         uint64_t lba;
     868                 :            :         int rc;
     869                 :            :         int qp_num;
     870                 :    2647623 :         struct spdk_dif_ctx_init_ext_opts dif_opts;
     871                 :            : 
     872                 :            :         enum dif_mode {
     873                 :            :                 DIF_MODE_NONE = 0,
     874                 :            :                 DIF_MODE_DIF = 1,
     875                 :            :                 DIF_MODE_DIX = 2,
     876                 :   12467069 :         }  mode = DIF_MODE_NONE;
     877                 :            : 
     878                 :   12467069 :         lba = offset_in_ios * entry->io_size_blocks;
     879                 :            : 
     880   [ +  +  +  - ]:   12467069 :         if (entry->md_size != 0 && !(entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) {
     881   [ -  +  -  + ]:     149248 :                 if (entry->md_interleave) {
     882                 :          0 :                         mode = DIF_MODE_DIF;
     883                 :            :                 } else {
     884                 :     149248 :                         mode = DIF_MODE_DIX;
     885                 :            :                 }
     886                 :            :         }
     887                 :            : 
     888                 :   12467069 :         qp_num = ns_ctx->u.nvme.last_qpair;
     889                 :   12467069 :         ns_ctx->u.nvme.last_qpair++;
     890         [ +  + ]:   12467069 :         if (ns_ctx->u.nvme.last_qpair == ns_ctx->u.nvme.num_active_qpairs) {
     891                 :   12463742 :                 ns_ctx->u.nvme.last_qpair = 0;
     892                 :            :         }
     893                 :            : 
     894         [ +  + ]:   12467069 :         if (mode != DIF_MODE_NONE) {
     895                 :     149248 :                 dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
     896                 :     149248 :                 dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
     897                 :     298496 :                 rc = spdk_dif_ctx_init(&task->dif_ctx, entry->block_size, entry->md_size,
     898   [ -  +  -  + ]:     149248 :                                        entry->md_interleave, entry->pi_loc,
     899                 :     149248 :                                        (enum spdk_dif_type)entry->pi_type, entry->io_flags,
     900                 :     149248 :                                        lba, 0xFFFF, (uint16_t)entry->io_size_blocks, 0, 0, &dif_opts);
     901         [ -  + ]:     149248 :                 if (rc != 0) {
     902   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Initialization of DIF context failed\n");
     903                 :          0 :                         exit(1);
     904                 :            :                 }
     905                 :            :         }
     906                 :            : 
     907   [ +  +  +  + ]:   12467069 :         if (task->is_read) {
     908         [ +  + ]:    9284490 :                 if (task->iovcnt == 1) {
     909                 :   16953618 :                         return spdk_nvme_ns_cmd_read_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair[qp_num],
     910                 :    9269952 :                                                              task->iovs[0].iov_base, task->md_iov.iov_base,
     911                 :            :                                                              lba,
     912                 :            :                                                              entry->io_size_blocks, io_complete,
     913                 :            :                                                              task, entry->io_flags,
     914                 :    9269952 :                                                              task->dif_ctx.apptag_mask, task->dif_ctx.app_tag);
     915                 :            :                 } else {
     916                 :      14538 :                         return spdk_nvme_ns_cmd_readv_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair[qp_num],
     917                 :            :                                                               lba, entry->io_size_blocks,
     918                 :            :                                                               io_complete, task, entry->io_flags,
     919                 :            :                                                               nvme_perf_reset_sgl, nvme_perf_next_sge,
     920                 :            :                                                               task->md_iov.iov_base,
     921                 :      14538 :                                                               task->dif_ctx.apptag_mask, task->dif_ctx.app_tag);
     922                 :            :                 }
     923                 :            :         } else {
     924      [ -  +  + ]:    3182579 :                 switch (mode) {
     925                 :          0 :                 case DIF_MODE_DIF:
     926                 :          0 :                         rc = spdk_dif_generate(task->iovs, task->iovcnt, entry->io_size_blocks, &task->dif_ctx);
     927         [ #  # ]:          0 :                         if (rc != 0) {
     928   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Generation of DIF failed\n");
     929                 :          0 :                                 return rc;
     930                 :            :                         }
     931                 :          0 :                         break;
     932                 :      12032 :                 case DIF_MODE_DIX:
     933                 :      12032 :                         rc = spdk_dix_generate(task->iovs, task->iovcnt, &task->md_iov, entry->io_size_blocks,
     934                 :      12032 :                                                &task->dif_ctx);
     935         [ -  + ]:      12032 :                         if (rc != 0) {
     936   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Generation of DIX failed\n");
     937                 :          0 :                                 return rc;
     938                 :            :                         }
     939                 :      12032 :                         break;
     940                 :    3170547 :                 default:
     941                 :    3170547 :                         break;
     942                 :            :                 }
     943                 :            : 
     944         [ +  + ]:    3182579 :                 if (task->iovcnt == 1) {
     945                 :    6166018 :                         return spdk_nvme_ns_cmd_write_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair[qp_num],
     946                 :    3167768 :                                                               task->iovs[0].iov_base, task->md_iov.iov_base,
     947                 :            :                                                               lba,
     948                 :            :                                                               entry->io_size_blocks, io_complete,
     949                 :            :                                                               task, entry->io_flags,
     950                 :    3167768 :                                                               task->dif_ctx.apptag_mask, task->dif_ctx.app_tag);
     951                 :            :                 } else {
     952                 :      14811 :                         return spdk_nvme_ns_cmd_writev_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair[qp_num],
     953                 :            :                                                                lba, entry->io_size_blocks,
     954                 :            :                                                                io_complete, task, entry->io_flags,
     955                 :            :                                                                nvme_perf_reset_sgl, nvme_perf_next_sge,
     956                 :            :                                                                task->md_iov.iov_base,
     957                 :      14811 :                                                                task->dif_ctx.apptag_mask, task->dif_ctx.app_tag);
     958                 :            :                 }
     959                 :            :         }
     960                 :            : }
     961                 :            : 
     962                 :            : static void
     963                 :    2322842 : perf_disconnect_cb(struct spdk_nvme_qpair *qpair, void *ctx)
     964                 :            : {
     965                 :    2322842 :         struct ns_worker_ctx *ns_ctx = ctx;
     966                 :            : 
     967                 :    2322842 :         ns_ctx->is_draining = true;
     968                 :    2322842 :         ns_ctx->status = 1;
     969                 :    2322842 : }
     970                 :            : 
     971                 :            : static int64_t
     972                 :  215640396 : nvme_check_io(struct ns_worker_ctx *ns_ctx)
     973                 :            : {
     974                 :            :         int64_t rc;
     975                 :            : 
     976                 :  215640396 :         rc = spdk_nvme_poll_group_process_completions(ns_ctx->u.nvme.group, g_max_completions,
     977                 :            :                         perf_disconnect_cb);
     978         [ +  + ]:  215640396 :         if (rc < 0) {
     979   [ -  +  -  + ]:          6 :                 fprintf(stderr, "NVMe io qpair process completion error\n");
     980                 :          6 :                 ns_ctx->status = 1;
     981                 :          6 :                 return -1;
     982                 :            :         }
     983                 :  215640390 :         return rc;
     984                 :            : }
     985                 :            : 
     986                 :            : static void
     987                 :     149248 : nvme_verify_io(struct perf_task *task, struct ns_entry *entry)
     988                 :            : {
     989                 :     149248 :         struct spdk_dif_error err_blk = {};
     990                 :            :         int rc;
     991                 :            : 
     992   [ -  +  +  +  :     149248 :         if (!task->is_read || (entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) {
                   -  + ]
     993                 :      12032 :                 return;
     994                 :            :         }
     995                 :            : 
     996   [ -  +  -  + ]:     137216 :         if (entry->md_interleave) {
     997                 :          0 :                 rc = spdk_dif_verify(task->iovs, task->iovcnt, entry->io_size_blocks, &task->dif_ctx,
     998                 :            :                                      &err_blk);
     999         [ #  # ]:          0 :                 if (rc != 0) {
    1000         [ #  # ]:          0 :                         fprintf(stderr, "DIF error detected. type=%d, offset=%" PRIu32 "\n",
    1001         [ #  # ]:          0 :                                 err_blk.err_type, err_blk.err_offset);
    1002                 :            :                 }
    1003                 :            :         } else {
    1004                 :     137216 :                 rc = spdk_dix_verify(task->iovs, task->iovcnt, &task->md_iov, entry->io_size_blocks,
    1005                 :     137216 :                                      &task->dif_ctx, &err_blk);
    1006         [ -  + ]:     137216 :                 if (rc != 0) {
    1007         [ #  # ]:          0 :                         fprintf(stderr, "DIX error detected. type=%d, offset=%" PRIu32 "\n",
    1008         [ #  # ]:          0 :                                 err_blk.err_type, err_blk.err_offset);
    1009                 :            :                 }
    1010                 :            :         }
    1011                 :            : }
    1012                 :            : 
    1013                 :            : /*
    1014                 :            :  * TODO: If a controller has multiple namespaces, they could all use the same queue.
    1015                 :            :  *  For now, give each namespace/thread combination its own queue.
    1016                 :            :  */
    1017                 :            : static int
    1018                 :        212 : nvme_init_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
    1019                 :            : {
    1020                 :            :         const struct spdk_nvme_ctrlr_opts *ctrlr_opts;
    1021                 :         65 :         struct spdk_nvme_io_qpair_opts opts;
    1022                 :        212 :         struct ns_entry *entry = ns_ctx->entry;
    1023                 :            :         struct spdk_nvme_poll_group *group;
    1024                 :            :         struct spdk_nvme_qpair *qpair;
    1025                 :            :         uint64_t poll_timeout_tsc;
    1026                 :            :         int i, rc;
    1027                 :            : 
    1028                 :        212 :         ns_ctx->u.nvme.num_active_qpairs = g_nr_io_queues_per_ns;
    1029                 :        212 :         ns_ctx->u.nvme.num_all_qpairs = g_nr_io_queues_per_ns + g_nr_unused_io_queues;
    1030                 :        212 :         ns_ctx->u.nvme.qpair = calloc(ns_ctx->u.nvme.num_all_qpairs, sizeof(struct spdk_nvme_qpair *));
    1031         [ -  + ]:        212 :         if (!ns_ctx->u.nvme.qpair) {
    1032                 :          0 :                 return -1;
    1033                 :            :         }
    1034                 :            : 
    1035                 :        212 :         spdk_nvme_ctrlr_get_default_io_qpair_opts(entry->u.nvme.ctrlr, &opts, sizeof(opts));
    1036         [ -  + ]:        212 :         if (opts.io_queue_requests < entry->num_io_requests) {
    1037                 :          0 :                 opts.io_queue_requests = entry->num_io_requests;
    1038                 :            :         }
    1039                 :        212 :         opts.delay_cmd_submit = true;
    1040                 :        212 :         opts.create_only = true;
    1041                 :            : 
    1042                 :        212 :         ctrlr_opts = spdk_nvme_ctrlr_get_opts(entry->u.nvme.ctrlr);
    1043         [ +  + ]:        313 :         opts.async_mode = !(spdk_nvme_ctrlr_get_transport_id(entry->u.nvme.ctrlr)->trtype ==
    1044                 :            :                             SPDK_NVME_TRANSPORT_PCIE
    1045         [ +  - ]:        101 :                             && ns_ctx->u.nvme.num_all_qpairs > ctrlr_opts->admin_queue_size);
    1046                 :            : 
    1047                 :        212 :         ns_ctx->u.nvme.group = spdk_nvme_poll_group_create(ns_ctx, NULL);
    1048         [ -  + ]:        212 :         if (ns_ctx->u.nvme.group == NULL) {
    1049                 :          0 :                 goto poll_group_failed;
    1050                 :            :         }
    1051                 :            : 
    1052                 :        212 :         group = ns_ctx->u.nvme.group;
    1053         [ +  + ]:        460 :         for (i = 0; i < ns_ctx->u.nvme.num_all_qpairs; i++) {
    1054                 :        248 :                 ns_ctx->u.nvme.qpair[i] = spdk_nvme_ctrlr_alloc_io_qpair(entry->u.nvme.ctrlr, &opts,
    1055                 :            :                                           sizeof(opts));
    1056                 :        248 :                 qpair = ns_ctx->u.nvme.qpair[i];
    1057         [ -  + ]:        248 :                 if (!qpair) {
    1058         [ #  # ]:          0 :                         printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair failed\n");
    1059                 :          0 :                         goto qpair_failed;
    1060                 :            :                 }
    1061                 :            : 
    1062         [ -  + ]:        248 :                 if (spdk_nvme_poll_group_add(group, qpair)) {
    1063         [ #  # ]:          0 :                         printf("ERROR: unable to add I/O qpair to poll group.\n");
    1064                 :          0 :                         spdk_nvme_ctrlr_free_io_qpair(qpair);
    1065                 :          0 :                         goto qpair_failed;
    1066                 :            :                 }
    1067                 :            : 
    1068         [ -  + ]:        248 :                 if (spdk_nvme_ctrlr_connect_io_qpair(entry->u.nvme.ctrlr, qpair)) {
    1069         [ #  # ]:          0 :                         printf("ERROR: unable to connect I/O qpair.\n");
    1070                 :          0 :                         spdk_nvme_ctrlr_free_io_qpair(qpair);
    1071                 :          0 :                         goto qpair_failed;
    1072                 :            :                 }
    1073                 :            :         }
    1074                 :            : 
    1075                 :            :         /* Busy poll here until all qpairs are connected - this ensures once we start
    1076                 :            :          * I/O we aren't still waiting for some qpairs to connect. Limit the poll to
    1077                 :            :          * 10 seconds though.
    1078                 :            :          */
    1079                 :        212 :         poll_timeout_tsc = spdk_get_ticks() + 10 * spdk_get_ticks_hz();
    1080                 :        212 :         rc = -EAGAIN;
    1081   [ +  -  +  - ]:     422806 :         while (spdk_get_ticks() < poll_timeout_tsc && rc == -EAGAIN) {
    1082                 :     422806 :                 spdk_nvme_poll_group_process_completions(group, 0, perf_disconnect_cb);
    1083                 :     422806 :                 rc = spdk_nvme_poll_group_all_connected(group);
    1084         [ +  + ]:     422806 :                 if (rc == 0) {
    1085                 :        212 :                         return 0;
    1086                 :            :                 }
    1087                 :            :         }
    1088                 :            : 
    1089                 :            :         /* If we reach here, it means we either timed out, or some connection failed. */
    1090   [ #  #  #  # ]:          0 :         assert(spdk_get_ticks() > poll_timeout_tsc || rc == -EIO);
    1091                 :            : 
    1092                 :          0 : qpair_failed:
    1093         [ #  # ]:          0 :         for (; i > 0; --i) {
    1094                 :          0 :                 spdk_nvme_ctrlr_free_io_qpair(ns_ctx->u.nvme.qpair[i - 1]);
    1095                 :            :         }
    1096                 :            : 
    1097                 :          0 :         spdk_nvme_poll_group_destroy(ns_ctx->u.nvme.group);
    1098                 :          0 : poll_group_failed:
    1099                 :          0 :         free(ns_ctx->u.nvme.qpair);
    1100                 :          0 :         return -1;
    1101                 :            : }
    1102                 :            : 
    1103                 :            : static void
    1104                 :        212 : nvme_cleanup_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
    1105                 :            : {
    1106                 :            :         int i;
    1107                 :            : 
    1108         [ +  + ]:        460 :         for (i = 0; i < ns_ctx->u.nvme.num_all_qpairs; i++) {
    1109                 :        248 :                 spdk_nvme_ctrlr_free_io_qpair(ns_ctx->u.nvme.qpair[i]);
    1110                 :            :         }
    1111                 :            : 
    1112                 :        212 :         spdk_nvme_poll_group_destroy(ns_ctx->u.nvme.group);
    1113                 :        212 :         free(ns_ctx->u.nvme.qpair);
    1114                 :        212 : }
    1115                 :            : 
    1116                 :            : static void
    1117                 :          2 : nvme_dump_rdma_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
    1118                 :            : {
    1119                 :            :         struct spdk_nvme_rdma_device_stat *device_stats;
    1120                 :            :         uint32_t i;
    1121                 :            : 
    1122         [ -  + ]:          2 :         printf("RDMA transport:\n");
    1123         [ +  + ]:          4 :         for (i = 0; i < stat->rdma.num_devices; i++) {
    1124                 :          2 :                 device_stats = &stat->rdma.device_stats[i];
    1125         [ -  + ]:          2 :                 printf("\tdev name:              %s\n", device_stats->name);
    1126         [ -  + ]:          2 :                 printf("\tpolls:                 %"PRIu64"\n", device_stats->polls);
    1127         [ -  + ]:          2 :                 printf("\tidle_polls:            %"PRIu64"\n", device_stats->idle_polls);
    1128         [ -  + ]:          2 :                 printf("\tcompletions:           %"PRIu64"\n", device_stats->completions);
    1129         [ -  + ]:          2 :                 printf("\tqueued_requests:       %"PRIu64"\n", device_stats->queued_requests);
    1130         [ -  + ]:          2 :                 printf("\ttotal_send_wrs:        %"PRIu64"\n", device_stats->total_send_wrs);
    1131         [ -  + ]:          2 :                 printf("\tsend_doorbell_updates: %"PRIu64"\n", device_stats->send_doorbell_updates);
    1132         [ -  + ]:          2 :                 printf("\ttotal_recv_wrs:        %"PRIu64"\n", device_stats->total_recv_wrs);
    1133         [ -  + ]:          2 :                 printf("\trecv_doorbell_updates: %"PRIu64"\n", device_stats->recv_doorbell_updates);
    1134         [ -  + ]:          2 :                 printf("\t---------------------------------\n");
    1135                 :            :         }
    1136                 :          2 : }
    1137                 :            : 
    1138                 :            : static void
    1139                 :          0 : nvme_dump_pcie_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
    1140                 :            : {
    1141                 :            :         struct spdk_nvme_pcie_stat *pcie_stat;
    1142                 :            : 
    1143                 :          0 :         pcie_stat = &stat->pcie;
    1144                 :            : 
    1145         [ #  # ]:          0 :         printf("PCIE transport:\n");
    1146         [ #  # ]:          0 :         printf("\tpolls:               %"PRIu64"\n", pcie_stat->polls);
    1147         [ #  # ]:          0 :         printf("\tidle_polls:          %"PRIu64"\n", pcie_stat->idle_polls);
    1148         [ #  # ]:          0 :         printf("\tcompletions:         %"PRIu64"\n", pcie_stat->completions);
    1149         [ #  # ]:          0 :         printf("\tcq_mmio_doorbell_updates: %"PRIu64"\n", pcie_stat->cq_mmio_doorbell_updates);
    1150         [ #  # ]:          0 :         printf("\tcq_shadow_doorbell_updates: %"PRIu64"\n", pcie_stat->cq_shadow_doorbell_updates);
    1151         [ #  # ]:          0 :         printf("\tsubmitted_requests:  %"PRIu64"\n", pcie_stat->submitted_requests);
    1152         [ #  # ]:          0 :         printf("\tsq_mmio_doorbell_updates:  %"PRIu64"\n", pcie_stat->sq_mmio_doorbell_updates);
    1153         [ #  # ]:          0 :         printf("\tsq_shadow_doorbell_updates:  %"PRIu64"\n", pcie_stat->sq_shadow_doorbell_updates);
    1154         [ #  # ]:          0 :         printf("\tqueued_requests:     %"PRIu64"\n", pcie_stat->queued_requests);
    1155                 :          0 : }
    1156                 :            : 
    1157                 :            : static void
    1158                 :          6 : nvme_dump_tcp_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
    1159                 :            : {
    1160                 :            :         struct spdk_nvme_tcp_stat *tcp_stat;
    1161                 :            : 
    1162                 :          6 :         tcp_stat = &stat->tcp;
    1163                 :            : 
    1164         [ -  + ]:          6 :         printf("TCP transport:\n");
    1165         [ -  + ]:          6 :         printf("\tpolls:              %"PRIu64"\n", tcp_stat->polls);
    1166         [ -  + ]:          6 :         printf("\tidle_polls:         %"PRIu64"\n", tcp_stat->idle_polls);
    1167         [ -  + ]:          6 :         printf("\tsock_completions:   %"PRIu64"\n", tcp_stat->socket_completions);
    1168         [ -  + ]:          6 :         printf("\tnvme_completions:   %"PRIu64"\n", tcp_stat->nvme_completions);
    1169         [ -  + ]:          6 :         printf("\tsubmitted_requests: %"PRIu64"\n", tcp_stat->submitted_requests);
    1170         [ -  + ]:          6 :         printf("\tqueued_requests:    %"PRIu64"\n", tcp_stat->queued_requests);
    1171                 :          6 : }
    1172                 :            : 
    1173                 :            : static void
    1174                 :          8 : nvme_dump_transport_stats(uint32_t lcore, struct ns_worker_ctx *ns_ctx)
    1175                 :            : {
    1176                 :            :         struct spdk_nvme_poll_group *group;
    1177                 :          8 :         struct spdk_nvme_poll_group_stat *stat = NULL;
    1178                 :            :         uint32_t i;
    1179                 :            :         int rc;
    1180                 :            : 
    1181                 :          8 :         group = ns_ctx->u.nvme.group;
    1182         [ -  + ]:          8 :         if (group == NULL) {
    1183                 :          0 :                 return;
    1184                 :            :         }
    1185                 :            : 
    1186                 :          8 :         rc = spdk_nvme_poll_group_get_stats(group, &stat);
    1187         [ -  + ]:          8 :         if (rc) {
    1188   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Can't get transport stats, error %d\n", rc);
    1189                 :          0 :                 return;
    1190                 :            :         }
    1191                 :            : 
    1192         [ -  + ]:          8 :         printf("\n====================\n");
    1193         [ -  + ]:          8 :         printf("lcore %u, ns %s statistics:\n", lcore, ns_ctx->entry->name);
    1194                 :            : 
    1195         [ +  + ]:         16 :         for (i = 0; i < stat->num_transports; i++) {
    1196   [ +  -  +  - ]:          8 :                 switch (stat->transport_stat[i]->trtype) {
    1197                 :          2 :                 case SPDK_NVME_TRANSPORT_RDMA:
    1198                 :          2 :                         nvme_dump_rdma_statistics(stat->transport_stat[i]);
    1199                 :          2 :                         break;
    1200                 :          0 :                 case SPDK_NVME_TRANSPORT_PCIE:
    1201                 :          0 :                         nvme_dump_pcie_statistics(stat->transport_stat[i]);
    1202                 :          0 :                         break;
    1203                 :          6 :                 case SPDK_NVME_TRANSPORT_TCP:
    1204                 :          6 :                         nvme_dump_tcp_statistics(stat->transport_stat[i]);
    1205                 :          6 :                         break;
    1206                 :          0 :                 default:
    1207   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unknown transport statistics %d %s\n", stat->transport_stat[i]->trtype,
    1208                 :          0 :                                 spdk_nvme_transport_id_trtype_str(stat->transport_stat[i]->trtype));
    1209                 :            :                 }
    1210                 :            :         }
    1211                 :            : 
    1212                 :          8 :         spdk_nvme_poll_group_free_stats(group, stat);
    1213                 :            : }
    1214                 :            : 
    1215                 :            : static const struct ns_fn_table nvme_fn_table = {
    1216                 :            :         .setup_payload          = nvme_setup_payload,
    1217                 :            :         .submit_io              = nvme_submit_io,
    1218                 :            :         .check_io               = nvme_check_io,
    1219                 :            :         .verify_io              = nvme_verify_io,
    1220                 :            :         .init_ns_worker_ctx     = nvme_init_ns_worker_ctx,
    1221                 :            :         .cleanup_ns_worker_ctx  = nvme_cleanup_ns_worker_ctx,
    1222                 :            :         .dump_transport_stats   = nvme_dump_transport_stats
    1223                 :            : };
    1224                 :            : 
    1225                 :            : static int
    1226                 :        363 : build_nvme_name(char *name, size_t length, struct spdk_nvme_ctrlr *ctrlr)
    1227                 :            : {
    1228                 :            :         const struct spdk_nvme_transport_id *trid;
    1229                 :        363 :         int res = 0;
    1230                 :            : 
    1231                 :        363 :         trid = spdk_nvme_ctrlr_get_transport_id(ctrlr);
    1232                 :            : 
    1233   [ +  +  +  +  :        363 :         switch (trid->trtype) {
                   -  - ]
    1234                 :        186 :         case SPDK_NVME_TRANSPORT_PCIE:
    1235         [ -  + ]:        186 :                 res = snprintf(name, length, "PCIE (%s)", trid->traddr);
    1236                 :        186 :                 break;
    1237                 :         38 :         case SPDK_NVME_TRANSPORT_RDMA:
    1238         [ -  + ]:         38 :                 res = snprintf(name, length, "RDMA (addr:%s subnqn:%s)", trid->traddr, trid->subnqn);
    1239                 :         38 :                 break;
    1240                 :        131 :         case SPDK_NVME_TRANSPORT_TCP:
    1241         [ -  + ]:        131 :                 res = snprintf(name, length, "TCP (addr:%s subnqn:%s)", trid->traddr, trid->subnqn);
    1242                 :        131 :                 break;
    1243                 :          8 :         case SPDK_NVME_TRANSPORT_VFIOUSER:
    1244         [ -  + ]:          8 :                 res = snprintf(name, length, "VFIOUSER (%s)", trid->traddr);
    1245                 :          8 :                 break;
    1246                 :          0 :         case SPDK_NVME_TRANSPORT_CUSTOM:
    1247         [ #  # ]:          0 :                 res = snprintf(name, length, "CUSTOM (%s)", trid->traddr);
    1248                 :          0 :                 break;
    1249                 :            : 
    1250                 :          0 :         default:
    1251   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unknown transport type %d\n", trid->trtype);
    1252                 :          0 :                 break;
    1253                 :            :         }
    1254                 :        363 :         return res;
    1255                 :            : }
    1256                 :            : 
    1257                 :            : static void
    1258                 :        194 : build_nvme_ns_name(char *name, size_t length, struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid)
    1259                 :            : {
    1260                 :        194 :         int res = 0;
    1261                 :            : 
    1262                 :        194 :         res = build_nvme_name(name, length, ctrlr);
    1263         [ +  - ]:        194 :         if (res > 0) {
    1264         [ -  + ]:        194 :                 snprintf(name + res, length - res, " NSID %u", nsid);
    1265                 :            :         }
    1266                 :            : 
    1267                 :        194 : }
    1268                 :            : 
    1269                 :            : static void
    1270                 :        208 : register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
    1271                 :            : {
    1272                 :            :         struct ns_entry *entry;
    1273                 :            :         const struct spdk_nvme_ctrlr_data *cdata;
    1274                 :            :         uint32_t max_xfer_size, entries, sector_size;
    1275                 :            :         uint64_t ns_size;
    1276                 :         65 :         struct spdk_nvme_io_qpair_opts opts;
    1277                 :            : 
    1278                 :        208 :         cdata = spdk_nvme_ctrlr_get_data(ctrlr);
    1279                 :            : 
    1280         [ -  + ]:        208 :         if (!spdk_nvme_ns_is_active(ns)) {
    1281                 :          0 :                 printf("Controller %-20.20s (%-20.20s): Skipping inactive NS %u\n",
    1282         [ #  # ]:          0 :                        cdata->mn, cdata->sn,
    1283                 :            :                        spdk_nvme_ns_get_id(ns));
    1284                 :          0 :                 g_warn = true;
    1285                 :         14 :                 return;
    1286                 :            :         }
    1287                 :            : 
    1288                 :        208 :         ns_size = spdk_nvme_ns_get_size(ns);
    1289                 :        208 :         sector_size = spdk_nvme_ns_get_sector_size(ns);
    1290                 :            : 
    1291   [ +  -  +  + ]:        208 :         if (ns_size < g_io_size_bytes || sector_size > g_io_size_bytes) {
    1292                 :         12 :                 printf("WARNING: controller %-20.20s (%-20.20s) ns %u has invalid "
    1293                 :            :                        "ns size %" PRIu64 " / block size %u for I/O size %u\n",
    1294         [ -  + ]:          6 :                        cdata->mn, cdata->sn, spdk_nvme_ns_get_id(ns),
    1295                 :            :                        ns_size, spdk_nvme_ns_get_sector_size(ns), g_io_size_bytes);
    1296                 :          6 :                 g_warn = true;
    1297                 :          6 :                 return;
    1298                 :            :         }
    1299                 :            : 
    1300                 :        202 :         max_xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
    1301                 :        202 :         spdk_nvme_ctrlr_get_default_io_qpair_opts(ctrlr, &opts, sizeof(opts));
    1302                 :            :         /* NVMe driver may add additional entries based on
    1303                 :            :          * stripe size and maximum transfer size, we assume
    1304                 :            :          * 1 more entry be used for stripe.
    1305                 :            :          */
    1306         [ -  + ]:        202 :         entries = (g_io_size_bytes - 1) / max_xfer_size + 2;
    1307         [ +  + ]:        202 :         if ((g_queue_depth * entries) > opts.io_queue_size) {
    1308         [ -  + ]:         46 :                 printf("Controller IO queue size %u, less than required.\n",
    1309                 :            :                        opts.io_queue_size);
    1310         [ -  + ]:         46 :                 printf("Consider using lower queue depth or smaller IO size, because "
    1311                 :            :                        "IO requests may be queued at the NVMe driver.\n");
    1312                 :            :         }
    1313                 :            :         /* For requests which have children requests, parent request itself
    1314                 :            :          * will also occupy 1 entry.
    1315                 :            :          */
    1316                 :        202 :         entries += 1;
    1317                 :            : 
    1318                 :        202 :         entry = calloc(1, sizeof(struct ns_entry));
    1319         [ -  + ]:        202 :         if (entry == NULL) {
    1320                 :          0 :                 perror("ns_entry malloc");
    1321                 :          0 :                 exit(1);
    1322                 :            :         }
    1323                 :            : 
    1324                 :        202 :         entry->type = ENTRY_TYPE_NVME_NS;
    1325                 :        202 :         entry->fn_table = &nvme_fn_table;
    1326                 :        202 :         entry->u.nvme.ctrlr = ctrlr;
    1327                 :        202 :         entry->u.nvme.ns = ns;
    1328                 :        202 :         entry->num_io_requests = entries * spdk_divide_round_up(g_queue_depth, g_nr_io_queues_per_ns);
    1329                 :            : 
    1330         [ -  + ]:        202 :         entry->size_in_ios = ns_size / g_io_size_bytes;
    1331         [ -  + ]:        202 :         entry->io_size_blocks = g_io_size_bytes / sector_size;
    1332                 :            : 
    1333         [ +  + ]:        202 :         if (g_is_random) {
    1334                 :        100 :                 entry->seed = rand();
    1335         [ -  + ]:        100 :                 if (g_zipf_theta > 0) {
    1336                 :          0 :                         entry->zipf = spdk_zipf_create(entry->size_in_ios, g_zipf_theta, 0);
    1337                 :            :                 }
    1338                 :            :         }
    1339                 :            : 
    1340                 :        202 :         entry->block_size = spdk_nvme_ns_get_extended_sector_size(ns);
    1341                 :        202 :         entry->md_size = spdk_nvme_ns_get_md_size(ns);
    1342                 :        202 :         entry->md_interleave = spdk_nvme_ns_supports_extended_lba(ns);
    1343                 :        202 :         entry->pi_loc = spdk_nvme_ns_get_data(ns)->dps.md_start;
    1344                 :        202 :         entry->pi_type = spdk_nvme_ns_get_pi_type(ns);
    1345                 :            : 
    1346         [ -  + ]:        202 :         if (spdk_nvme_ns_get_flags(ns) & SPDK_NVME_NS_DPS_PI_SUPPORTED) {
    1347                 :          0 :                 entry->io_flags = g_metacfg_pract_flag | g_metacfg_prchk_flags;
    1348                 :            :         }
    1349                 :            : 
    1350                 :            :         /* If metadata size = 8 bytes, PI is stripped (read) or inserted (write),
    1351                 :            :          *  and so reduce metadata size from block size.  (If metadata size > 8 bytes,
    1352                 :            :          *  PI is passed (read) or replaced (write).  So block size is not necessary
    1353                 :            :          *  to change.)
    1354                 :            :          */
    1355   [ -  +  -  - ]:        202 :         if ((entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT) && (entry->md_size == 8)) {
    1356                 :          0 :                 entry->block_size = spdk_nvme_ns_get_sector_size(ns);
    1357                 :            :         }
    1358                 :            : 
    1359   [ -  +  +  + ]:        202 :         if (g_io_size_bytes % entry->block_size != 0) {
    1360         [ -  + ]:          8 :                 printf("WARNING: IO size %u (-o) is not a multiple of nsid %u sector size %u."
    1361                 :            :                        " Removing this ns from test\n", g_io_size_bytes, spdk_nvme_ns_get_id(ns), entry->block_size);
    1362                 :          8 :                 g_warn = true;
    1363                 :          8 :                 spdk_zipf_free(&entry->zipf);
    1364                 :          8 :                 free(entry);
    1365                 :          8 :                 return;
    1366                 :            :         }
    1367                 :            : 
    1368         [ +  + ]:        194 :         if (g_max_io_md_size < entry->md_size) {
    1369                 :          8 :                 g_max_io_md_size = entry->md_size;
    1370                 :            :         }
    1371                 :            : 
    1372         [ +  + ]:        194 :         if (g_max_io_size_blocks < entry->io_size_blocks) {
    1373                 :        127 :                 g_max_io_size_blocks = entry->io_size_blocks;
    1374                 :            :         }
    1375                 :            : 
    1376                 :        194 :         build_nvme_ns_name(entry->name, sizeof(entry->name), ctrlr, spdk_nvme_ns_get_id(ns));
    1377                 :            : 
    1378                 :        194 :         g_num_namespaces++;
    1379                 :        194 :         TAILQ_INSERT_TAIL(&g_namespaces, entry, link);
    1380                 :            : }
    1381                 :            : 
    1382                 :            : static void
    1383                 :        137 : unregister_namespaces(void)
    1384                 :            : {
    1385                 :            :         struct ns_entry *entry, *tmp;
    1386                 :            : 
    1387         [ +  + ]:        331 :         TAILQ_FOREACH_SAFE(entry, &g_namespaces, link, tmp) {
    1388         [ +  + ]:        194 :                 TAILQ_REMOVE(&g_namespaces, entry, link);
    1389                 :        194 :                 spdk_zipf_free(&entry->zipf);
    1390   [ +  +  +  + ]:        194 :                 if (g_use_uring) {
    1391                 :            : #ifdef SPDK_CONFIG_URING
    1392                 :          0 :                         close(entry->u.uring.fd);
    1393                 :            : #endif
    1394                 :            :                 } else {
    1395                 :            : #if HAVE_LIBAIO
    1396                 :        194 :                         close(entry->u.aio.fd);
    1397                 :            : #endif
    1398                 :            :                 }
    1399                 :        194 :                 free(entry);
    1400                 :            :         }
    1401                 :        137 : }
    1402                 :            : 
    1403                 :            : static void
    1404                 :          0 : enable_latency_tracking_complete(void *cb_arg, const struct spdk_nvme_cpl *cpl)
    1405                 :            : {
    1406   [ #  #  #  # ]:          0 :         if (spdk_nvme_cpl_is_error(cpl)) {
    1407         [ #  # ]:          0 :                 printf("enable_latency_tracking_complete failed\n");
    1408                 :            :         }
    1409                 :          0 :         g_outstanding_commands--;
    1410                 :          0 : }
    1411                 :            : 
    1412                 :            : static void
    1413                 :          0 : set_latency_tracking_feature(struct spdk_nvme_ctrlr *ctrlr, bool enable)
    1414                 :            : {
    1415                 :            :         int res;
    1416                 :            :         union spdk_nvme_intel_feat_latency_tracking latency_tracking;
    1417                 :            : 
    1418         [ #  # ]:          0 :         if (enable) {
    1419                 :          0 :                 latency_tracking.bits.enable = 0x01;
    1420                 :            :         } else {
    1421                 :          0 :                 latency_tracking.bits.enable = 0x00;
    1422                 :            :         }
    1423                 :            : 
    1424                 :          0 :         res = spdk_nvme_ctrlr_cmd_set_feature(ctrlr, SPDK_NVME_INTEL_FEAT_LATENCY_TRACKING,
    1425                 :            :                                               latency_tracking.raw, 0, NULL, 0, enable_latency_tracking_complete, NULL);
    1426         [ #  # ]:          0 :         if (res) {
    1427         [ #  # ]:          0 :                 printf("fail to allocate nvme request.\n");
    1428                 :          0 :                 return;
    1429                 :            :         }
    1430                 :          0 :         g_outstanding_commands++;
    1431                 :            : 
    1432         [ #  # ]:          0 :         while (g_outstanding_commands) {
    1433                 :          0 :                 spdk_nvme_ctrlr_process_admin_completions(ctrlr);
    1434                 :            :         }
    1435                 :            : }
    1436                 :            : 
    1437                 :            : static void
    1438                 :        169 : register_ctrlr(struct spdk_nvme_ctrlr *ctrlr, struct trid_entry *trid_entry)
    1439                 :            : {
    1440                 :            :         struct spdk_nvme_ns *ns;
    1441                 :        169 :         struct ctrlr_entry *entry = malloc(sizeof(struct ctrlr_entry));
    1442                 :            :         uint32_t nsid;
    1443                 :            : 
    1444         [ -  + ]:        169 :         if (entry == NULL) {
    1445                 :          0 :                 perror("ctrlr_entry malloc");
    1446                 :          0 :                 exit(1);
    1447                 :            :         }
    1448                 :            : 
    1449                 :        169 :         entry->latency_page = spdk_dma_zmalloc(sizeof(struct spdk_nvme_intel_rw_latency_page),
    1450                 :            :                                                4096, NULL);
    1451         [ -  + ]:        169 :         if (entry->latency_page == NULL) {
    1452         [ #  # ]:          0 :                 printf("Allocation error (latency page)\n");
    1453                 :          0 :                 exit(1);
    1454                 :            :         }
    1455                 :            : 
    1456                 :        169 :         build_nvme_name(entry->name, sizeof(entry->name), ctrlr);
    1457                 :            : 
    1458                 :        169 :         entry->ctrlr = ctrlr;
    1459                 :        169 :         entry->trtype = trid_entry->trid.trtype;
    1460                 :        169 :         TAILQ_INSERT_TAIL(&g_controllers, entry, link);
    1461                 :            : 
    1462   [ -  +  -  +  :        169 :         if (g_latency_ssd_tracking_enable &&
                   -  - ]
    1463                 :          0 :             spdk_nvme_ctrlr_is_feature_supported(ctrlr, SPDK_NVME_INTEL_FEAT_LATENCY_TRACKING)) {
    1464                 :          0 :                 set_latency_tracking_feature(ctrlr, true);
    1465                 :            :         }
    1466                 :            : 
    1467         [ +  - ]:        169 :         if (trid_entry->nsid == 0) {
    1468                 :        169 :                 for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
    1469         [ +  + ]:        377 :                      nsid != 0; nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
    1470                 :        208 :                         ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
    1471         [ -  + ]:        208 :                         if (ns == NULL) {
    1472                 :          0 :                                 continue;
    1473                 :            :                         }
    1474                 :        208 :                         register_ns(ctrlr, ns);
    1475                 :            :                 }
    1476                 :            :         } else {
    1477                 :          0 :                 ns = spdk_nvme_ctrlr_get_ns(ctrlr, trid_entry->nsid);
    1478         [ #  # ]:          0 :                 if (!ns) {
    1479                 :          0 :                         perror("Namespace does not exist.");
    1480                 :          0 :                         exit(1);
    1481                 :            :                 }
    1482                 :            : 
    1483                 :          0 :                 register_ns(ctrlr, ns);
    1484                 :            :         }
    1485                 :        169 : }
    1486                 :            : 
    1487                 :            : static inline void
    1488                 :   12467069 : submit_single_io(struct perf_task *task)
    1489                 :            : {
    1490                 :            :         uint64_t                offset_in_ios;
    1491                 :            :         int                     rc;
    1492                 :   12467069 :         struct ns_worker_ctx    *ns_ctx = task->ns_ctx;
    1493                 :   12467069 :         struct ns_entry         *entry = ns_ctx->entry;
    1494                 :            : 
    1495   [ -  +  -  + ]:   12467069 :         assert(!ns_ctx->is_draining);
    1496                 :            : 
    1497         [ -  + ]:   12467069 :         if (entry->zipf) {
    1498                 :          0 :                 offset_in_ios = spdk_zipf_generate(entry->zipf);
    1499         [ +  + ]:   12467069 :         } else if (g_is_random) {
    1500         [ -  + ]:    6068833 :                 offset_in_ios = rand_r(&entry->seed) % entry->size_in_ios;
    1501                 :            :         } else {
    1502                 :    6398236 :                 offset_in_ios = ns_ctx->offset_in_ios++;
    1503         [ +  + ]:    6398236 :                 if (ns_ctx->offset_in_ios == entry->size_in_ios) {
    1504                 :         33 :                         ns_ctx->offset_in_ios = 0;
    1505                 :            :                 }
    1506                 :            :         }
    1507                 :            : 
    1508                 :   12467069 :         task->submit_tsc = spdk_get_ticks();
    1509                 :            : 
    1510         [ +  + ]:   12467069 :         if ((g_rw_percentage == 100) ||
    1511   [ +  +  +  + ]:    4369730 :             (g_rw_percentage != 0 && ((rand_r(&entry->seed) % 100) < g_rw_percentage))) {
    1512                 :    9284490 :                 task->is_read = true;
    1513                 :            :         } else {
    1514                 :    3182579 :                 task->is_read = false;
    1515                 :            :         }
    1516                 :            : 
    1517                 :   12467069 :         rc = entry->fn_table->submit_io(task, ns_ctx, entry, offset_in_ios);
    1518                 :            : 
    1519         [ +  + ]:   12467069 :         if (spdk_unlikely(rc != 0)) {
    1520   [ -  +  +  + ]:      60758 :                 if (g_continue_on_error) {
    1521                 :            :                         /* We can't just resubmit here or we can get in a loop that
    1522                 :            :                          * stack overflows. */
    1523                 :      60617 :                         TAILQ_INSERT_TAIL(&ns_ctx->queued_tasks, task, link);
    1524                 :            :                 } else {
    1525   [ -  +  +  -  :        141 :                         RATELIMIT_LOG("starting I/O failed: %d\n", rc);
          +  +  -  +  -  
                -  -  + ]
    1526                 :        141 :                         spdk_dma_free(task->iovs[0].iov_base);
    1527                 :        141 :                         free(task->iovs);
    1528                 :        141 :                         spdk_dma_free(task->md_iov.iov_base);
    1529                 :        141 :                         task->ns_ctx->status = 1;
    1530                 :        141 :                         free(task);
    1531                 :            :                 }
    1532                 :            :         } else {
    1533                 :   12406311 :                 ns_ctx->current_queue_depth++;
    1534                 :   12406311 :                 ns_ctx->stats.io_submitted++;
    1535                 :            :         }
    1536                 :            : 
    1537   [ -  +  -  - ]:   12467069 :         if (spdk_unlikely(g_number_ios && ns_ctx->stats.io_submitted >= g_number_ios)) {
    1538                 :          0 :                 ns_ctx->is_draining = true;
    1539                 :            :         }
    1540                 :   12467069 : }
    1541                 :            : 
    1542                 :            : static inline void
    1543                 :   12406439 : task_complete(struct perf_task *task)
    1544                 :            : {
    1545                 :            :         struct ns_worker_ctx    *ns_ctx;
    1546                 :            :         uint64_t                tsc_diff;
    1547                 :            :         struct ns_entry         *entry;
    1548                 :            : 
    1549                 :   12406439 :         ns_ctx = task->ns_ctx;
    1550                 :   12406439 :         entry = ns_ctx->entry;
    1551                 :   12406439 :         ns_ctx->current_queue_depth--;
    1552                 :   12406439 :         ns_ctx->stats.io_completed++;
    1553                 :   12406439 :         tsc_diff = spdk_get_ticks() - task->submit_tsc;
    1554                 :   12406439 :         ns_ctx->stats.total_tsc += tsc_diff;
    1555         [ +  + ]:   12406439 :         if (spdk_unlikely(ns_ctx->stats.min_tsc > tsc_diff)) {
    1556                 :       4611 :                 ns_ctx->stats.min_tsc = tsc_diff;
    1557                 :            :         }
    1558         [ +  + ]:   12406439 :         if (spdk_unlikely(ns_ctx->stats.max_tsc < tsc_diff)) {
    1559                 :      12299 :                 ns_ctx->stats.max_tsc = tsc_diff;
    1560                 :            :         }
    1561         [ +  + ]:   12406439 :         if (spdk_unlikely(g_latency_sw_tracking_level > 0)) {
    1562                 :    1165788 :                 spdk_histogram_data_tally(ns_ctx->histogram, tsc_diff);
    1563                 :            :         }
    1564                 :            : 
    1565         [ +  + ]:   12406439 :         if (spdk_unlikely(entry->md_size > 0)) {
    1566                 :            :                 /* add application level verification for end-to-end data protection */
    1567                 :     149248 :                 entry->fn_table->verify_io(task, entry);
    1568                 :            :         }
    1569                 :            : 
    1570                 :            :         /*
    1571                 :            :          * is_draining indicates when time has expired or io_submitted exceeded
    1572                 :            :          * g_number_ios for the test run and we are just waiting for the previously
    1573                 :            :          * submitted I/O to complete. In this case, do not submit a new I/O to
    1574                 :            :          * replace the one just completed.
    1575                 :            :          */
    1576   [ +  +  +  + ]:   12406439 :         if (spdk_unlikely(ns_ctx->is_draining)) {
    1577                 :      12646 :                 spdk_dma_free(task->iovs[0].iov_base);
    1578                 :      12646 :                 free(task->iovs);
    1579                 :      12646 :                 spdk_dma_free(task->md_iov.iov_base);
    1580                 :      12646 :                 free(task);
    1581                 :            :         } else {
    1582                 :   12393793 :                 submit_single_io(task);
    1583                 :            :         }
    1584                 :   12406439 : }
    1585                 :            : 
    1586                 :            : static void
    1587                 :   12406311 : io_complete(void *ctx, const struct spdk_nvme_cpl *cpl)
    1588                 :            : {
    1589                 :   12406311 :         struct perf_task *task = ctx;
    1590                 :            : 
    1591   [ +  +  -  + ]:   12406311 :         if (spdk_unlikely(spdk_nvme_cpl_is_error(cpl))) {
    1592   [ -  +  +  + ]:     167100 :                 if (task->is_read) {
    1593   [ -  +  +  +  :     166845 :                         RATELIMIT_LOG("Read completed with error (sct=%d, sc=%d)\n",
          +  +  +  +  -  
                +  -  + ]
    1594                 :            :                                       cpl->status.sct, cpl->status.sc);
    1595                 :            :                 } else {
    1596   [ -  +  +  -  :        255 :                         RATELIMIT_LOG("Write completed with error (sct=%d, sc=%d)\n",
          +  +  -  +  -  
                -  -  + ]
    1597                 :            :                                       cpl->status.sct, cpl->status.sc);
    1598                 :            :                 }
    1599   [ -  +  +  + ]:     167100 :                 if (!g_continue_on_error) {
    1600         [ +  - ]:        853 :                         if (cpl->status.sct == SPDK_NVME_SCT_GENERIC &&
    1601         [ -  + ]:        853 :                             cpl->status.sc == SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT) {
    1602                 :            :                                 /* The namespace was hotplugged.  Stop trying to send I/O to it. */
    1603                 :          0 :                                 task->ns_ctx->is_draining = true;
    1604                 :            :                         }
    1605                 :            : 
    1606                 :        853 :                         task->ns_ctx->status = 1;
    1607                 :            :                 }
    1608                 :            :         }
    1609                 :            : 
    1610                 :   12406311 :         task_complete(task);
    1611                 :   12406311 : }
    1612                 :            : 
    1613                 :            : static struct perf_task *
    1614                 :      12787 : allocate_task(struct ns_worker_ctx *ns_ctx, int queue_depth)
    1615                 :            : {
    1616                 :            :         struct perf_task *task;
    1617                 :            : 
    1618                 :      12787 :         task = calloc(1, sizeof(*task));
    1619         [ -  + ]:      12787 :         if (task == NULL) {
    1620   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Out of memory allocating tasks\n");
    1621                 :          0 :                 exit(1);
    1622                 :            :         }
    1623                 :            : 
    1624                 :      12787 :         ns_ctx->entry->fn_table->setup_payload(task, queue_depth % 8 + 1);
    1625                 :            : 
    1626                 :      12787 :         task->ns_ctx = ns_ctx;
    1627                 :            : 
    1628                 :      12787 :         return task;
    1629                 :            : }
    1630                 :            : 
    1631                 :            : static void
    1632                 :        212 : submit_io(struct ns_worker_ctx *ns_ctx, int queue_depth)
    1633                 :            : {
    1634                 :            :         struct perf_task *task;
    1635                 :            : 
    1636         [ +  + ]:      12999 :         while (queue_depth-- > 0) {
    1637                 :      12787 :                 task = allocate_task(ns_ctx, queue_depth);
    1638                 :      12787 :                 submit_single_io(task);
    1639                 :            :         }
    1640                 :        212 : }
    1641                 :            : 
    1642                 :            : static int
    1643                 :        212 : init_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
    1644                 :            : {
    1645                 :        212 :         TAILQ_INIT(&ns_ctx->queued_tasks);
    1646                 :        212 :         return ns_ctx->entry->fn_table->init_ns_worker_ctx(ns_ctx);
    1647                 :            : }
    1648                 :            : 
    1649                 :            : static void
    1650                 :        212 : cleanup_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
    1651                 :            : {
    1652                 :            :         struct perf_task *task, *ttask;
    1653                 :            : 
    1654         [ +  + ]:        340 :         TAILQ_FOREACH_SAFE(task, &ns_ctx->queued_tasks, link, ttask) {
    1655         [ +  + ]:        128 :                 TAILQ_REMOVE(&ns_ctx->queued_tasks, task, link);
    1656                 :        128 :                 task_complete(task);
    1657                 :            :         }
    1658                 :        212 :         ns_ctx->entry->fn_table->cleanup_ns_worker_ctx(ns_ctx);
    1659                 :        212 : }
    1660                 :            : 
    1661                 :            : static void
    1662                 :        672 : print_periodic_performance(bool warmup)
    1663                 :            : {
    1664                 :            :         uint64_t io_this_second;
    1665                 :            :         double mb_this_second;
    1666                 :            :         struct worker_thread *worker;
    1667                 :            :         struct ns_worker_ctx *ns_ctx;
    1668                 :            :         uint64_t busy_tsc;
    1669                 :            :         uint64_t idle_tsc;
    1670                 :        672 :         uint64_t core_busy_tsc = 0;
    1671                 :        672 :         uint64_t core_idle_tsc = 0;
    1672                 :        672 :         double core_busy_perc = 0;
    1673                 :            : 
    1674         [ +  - ]:        672 :         if (!isatty(STDOUT_FILENO)) {
    1675                 :            :                 /* Don't print periodic stats if output is not going
    1676                 :            :                  * to a terminal.
    1677                 :            :                  */
    1678                 :        672 :                 return;
    1679                 :            :         }
    1680                 :          0 :         io_this_second = 0;
    1681         [ #  # ]:          0 :         TAILQ_FOREACH(worker, &g_workers, link) {
    1682                 :          0 :                 busy_tsc = 0;
    1683                 :          0 :                 idle_tsc = 0;
    1684         [ #  # ]:          0 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1685                 :          0 :                         io_this_second += ns_ctx->stats.io_completed - ns_ctx->stats.last_io_completed;
    1686                 :          0 :                         ns_ctx->stats.last_io_completed = ns_ctx->stats.io_completed;
    1687                 :            : 
    1688   [ #  #  #  # ]:          0 :                         if (g_monitor_perf_cores) {
    1689                 :          0 :                                 busy_tsc += ns_ctx->stats.busy_tsc - ns_ctx->stats.last_busy_tsc;
    1690                 :          0 :                                 idle_tsc += ns_ctx->stats.idle_tsc - ns_ctx->stats.last_idle_tsc;
    1691                 :          0 :                                 ns_ctx->stats.last_busy_tsc = ns_ctx->stats.busy_tsc;
    1692                 :          0 :                                 ns_ctx->stats.last_idle_tsc = ns_ctx->stats.idle_tsc;
    1693                 :            :                         }
    1694                 :            :                 }
    1695   [ #  #  #  # ]:          0 :                 if (g_monitor_perf_cores) {
    1696                 :          0 :                         core_busy_tsc += busy_tsc;
    1697                 :          0 :                         core_idle_tsc += idle_tsc;
    1698                 :            :                 }
    1699                 :            :         }
    1700                 :          0 :         mb_this_second = (double)io_this_second * g_io_size_bytes / (1024 * 1024);
    1701                 :            : 
    1702   [ #  #  #  # ]:          0 :         printf("%s%9ju IOPS, %8.2f MiB/s", warmup ? "[warmup] " : "", io_this_second, mb_this_second);
    1703   [ #  #  #  # ]:          0 :         if (g_monitor_perf_cores) {
    1704                 :          0 :                 core_busy_perc = (double)core_busy_tsc / (core_idle_tsc + core_busy_tsc) * 100;
    1705         [ #  # ]:          0 :                 printf("%3d Core(s): %6.2f%% Busy", g_num_workers, core_busy_perc);
    1706                 :            :         }
    1707                 :          0 :         printf("\r");
    1708                 :          0 :         fflush(stdout);
    1709                 :            : }
    1710                 :            : 
    1711                 :            : static void
    1712                 :          4 : perf_dump_transport_statistics(struct worker_thread *worker)
    1713                 :            : {
    1714                 :            :         struct ns_worker_ctx *ns_ctx;
    1715                 :            : 
    1716         [ +  + ]:         12 :         TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1717         [ +  - ]:          8 :                 if (ns_ctx->entry->fn_table->dump_transport_stats) {
    1718                 :          8 :                         ns_ctx->entry->fn_table->dump_transport_stats(worker->lcore, ns_ctx);
    1719                 :            :                 }
    1720                 :            :         }
    1721                 :          4 : }
    1722                 :            : 
    1723                 :            : static int
    1724                 :        145 : work_fn(void *arg)
    1725                 :            : {
    1726                 :            :         uint64_t tsc_start, tsc_end, tsc_current, tsc_next_print;
    1727                 :        145 :         struct worker_thread *worker = (struct worker_thread *) arg;
    1728                 :        145 :         struct ns_worker_ctx *ns_ctx = NULL;
    1729                 :            :         uint32_t unfinished_ns_ctx;
    1730                 :        145 :         bool warmup = false;
    1731                 :            :         int rc;
    1732                 :            :         int64_t check_rc;
    1733                 :            :         uint64_t check_now;
    1734                 :         25 :         TAILQ_HEAD(, perf_task) swap;
    1735                 :            :         struct perf_task *task;
    1736                 :            : 
    1737                 :            :         /* Allocate queue pairs for each namespace. */
    1738         [ +  + ]:        357 :         TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1739         [ -  + ]:        212 :                 if (init_ns_worker_ctx(ns_ctx) != 0) {
    1740                 :          0 :                         printf("ERROR: init_ns_worker_ctx() failed\n");
    1741                 :            :                         /* Wait on barrier to avoid blocking of successful workers */
    1742                 :          0 :                         pthread_barrier_wait(&g_worker_sync_barrier);
    1743                 :          0 :                         ns_ctx->status = 1;
    1744                 :          0 :                         return 1;
    1745                 :            :                 }
    1746                 :            :         }
    1747                 :            : 
    1748                 :        145 :         rc = pthread_barrier_wait(&g_worker_sync_barrier);
    1749   [ +  +  -  + ]:        145 :         if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
    1750                 :          0 :                 printf("ERROR: failed to wait on thread sync barrier\n");
    1751                 :          0 :                 ns_ctx->status = 1;
    1752                 :          0 :                 return 1;
    1753                 :            :         }
    1754                 :            : 
    1755                 :        145 :         tsc_start = spdk_get_ticks();
    1756                 :        145 :         tsc_current = tsc_start;
    1757                 :        145 :         tsc_next_print = tsc_current + g_tsc_rate;
    1758                 :            : 
    1759         [ -  + ]:        145 :         if (g_warmup_time_in_sec) {
    1760                 :          0 :                 warmup = true;
    1761                 :          0 :                 tsc_end = tsc_current + g_warmup_time_in_sec * g_tsc_rate;
    1762                 :            :         } else {
    1763                 :        145 :                 tsc_end = tsc_current + g_time_in_sec * g_tsc_rate;
    1764                 :            :         }
    1765                 :            : 
    1766                 :            :         /* Submit initial I/O for each namespace. */
    1767         [ +  + ]:        357 :         TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1768                 :        212 :                 submit_io(ns_ctx, g_queue_depth);
    1769                 :            :         }
    1770                 :            : 
    1771   [ +  +  +  - ]:  197940743 :         while (spdk_likely(!g_exit)) {
    1772                 :  197940743 :                 bool all_draining = true;
    1773                 :            : 
    1774                 :            :                 /*
    1775                 :            :                  * Check for completed I/O for each controller. A new
    1776                 :            :                  * I/O will be submitted in the io_complete callback
    1777                 :            :                  * to replace each I/O that is completed.
    1778                 :            :                  */
    1779         [ +  + ]:  411454850 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1780   [ -  +  +  +  :  213514107 :                         if (g_continue_on_error && !ns_ctx->is_draining) {
             -  +  +  - ]
    1781                 :            :                                 /* Submit any I/O that is queued up */
    1782                 :   26983848 :                                 TAILQ_INIT(&swap);
    1783   [ +  +  -  + ]:   26983848 :                                 TAILQ_SWAP(&swap, &ns_ctx->queued_tasks, perf_task, link);
    1784         [ +  + ]:   27044337 :                                 while (!TAILQ_EMPTY(&swap)) {
    1785                 :      60489 :                                         task = TAILQ_FIRST(&swap);
    1786         [ +  + ]:      60489 :                                         TAILQ_REMOVE(&swap, task, link);
    1787   [ -  +  -  + ]:      60489 :                                         if (ns_ctx->is_draining) {
    1788                 :          0 :                                                 TAILQ_INSERT_TAIL(&ns_ctx->queued_tasks,
    1789                 :            :                                                                   task, link);
    1790                 :          0 :                                                 continue;
    1791                 :            :                                         }
    1792                 :      60489 :                                         submit_single_io(task);
    1793                 :            :                                 }
    1794                 :            :                         }
    1795                 :            : 
    1796                 :  213514107 :                         check_now = spdk_get_ticks();
    1797                 :  213514107 :                         check_rc = ns_ctx->entry->fn_table->check_io(ns_ctx);
    1798                 :            : 
    1799         [ +  + ]:  213514107 :                         if (check_rc > 0) {
    1800                 :    1790135 :                                 ns_ctx->stats.busy_tsc += check_now - ns_ctx->stats.last_tsc;
    1801                 :            :                         } else {
    1802                 :  211723972 :                                 ns_ctx->stats.idle_tsc += check_now - ns_ctx->stats.last_tsc;
    1803                 :            :                         }
    1804                 :  213514107 :                         ns_ctx->stats.last_tsc = check_now;
    1805                 :            : 
    1806   [ +  +  +  + ]:  213514107 :                         if (!ns_ctx->is_draining) {
    1807                 :  213514101 :                                 all_draining = false;
    1808                 :            :                         }
    1809                 :            :                 }
    1810                 :            : 
    1811         [ +  + ]:  197940743 :                 if (spdk_unlikely(all_draining)) {
    1812                 :          6 :                         break;
    1813                 :            :                 }
    1814                 :            : 
    1815                 :  197940737 :                 tsc_current = spdk_get_ticks();
    1816                 :            : 
    1817   [ +  +  +  + ]:  197940737 :                 if (worker->lcore == g_main_core && tsc_current > tsc_next_print) {
    1818                 :        672 :                         tsc_next_print += g_tsc_rate;
    1819                 :        672 :                         print_periodic_performance(warmup);
    1820                 :            :                 }
    1821                 :            : 
    1822         [ +  + ]:  197940737 :                 if (tsc_current > tsc_end) {
    1823         [ -  + ]:        139 :                         if (warmup) {
    1824                 :            :                                 /* Update test start and end time, clear statistics */
    1825                 :          0 :                                 tsc_start = spdk_get_ticks();
    1826                 :          0 :                                 tsc_end = tsc_start + g_time_in_sec * g_tsc_rate;
    1827                 :            : 
    1828         [ #  # ]:          0 :                                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1829         [ #  # ]:          0 :                                         memset(&ns_ctx->stats, 0, sizeof(ns_ctx->stats));
    1830                 :          0 :                                         ns_ctx->stats.min_tsc = UINT64_MAX;
    1831                 :          0 :                                         spdk_histogram_data_reset(ns_ctx->histogram);
    1832                 :            :                                 }
    1833                 :            : 
    1834   [ #  #  #  # ]:          0 :                                 if (worker->lcore == g_main_core && isatty(STDOUT_FILENO)) {
    1835                 :            :                                         /* warmup stage prints a longer string to stdout, need to erase it */
    1836                 :          0 :                                         printf("%c[2K", 27);
    1837                 :            :                                 }
    1838                 :            : 
    1839                 :          0 :                                 warmup = false;
    1840                 :            :                         } else {
    1841                 :        139 :                                 break;
    1842                 :            :                         }
    1843                 :            :                 }
    1844                 :            :         }
    1845                 :            : 
    1846                 :            :         /* Capture the actual elapsed time when we break out of the main loop. This will account
    1847                 :            :          * for cases where we exit prematurely due to a signal. We only need to capture it on
    1848                 :            :          * one core, so use the main core.
    1849                 :            :          */
    1850         [ +  + ]:        145 :         if (worker->lcore == g_main_core) {
    1851         [ -  + ]:        127 :                 g_elapsed_time_in_usec = (tsc_current - tsc_start) * SPDK_SEC_TO_USEC / g_tsc_rate;
    1852                 :            :         }
    1853                 :            : 
    1854                 :            :         /* drain the io of each ns_ctx in round robin to make the fairness */
    1855                 :            :         do {
    1856                 :    2115403 :                 unfinished_ns_ctx = 0;
    1857         [ +  + ]:    4930872 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1858                 :            :                         /* first time will enter into this if case */
    1859   [ +  +  +  + ]:    2815469 :                         if (!ns_ctx->is_draining) {
    1860                 :        206 :                                 ns_ctx->is_draining = true;
    1861                 :            :                         }
    1862                 :            : 
    1863         [ +  + ]:    2815469 :                         if (ns_ctx->current_queue_depth > 0) {
    1864                 :    2126289 :                                 ns_ctx->entry->fn_table->check_io(ns_ctx);
    1865         [ +  + ]:    2126289 :                                 if (ns_ctx->current_queue_depth > 0) {
    1866                 :    2126078 :                                         unfinished_ns_ctx++;
    1867                 :            :                                 }
    1868                 :            :                         }
    1869                 :            :                 }
    1870         [ +  + ]:    2115403 :         } while (unfinished_ns_ctx > 0);
    1871                 :            : 
    1872   [ -  +  +  + ]:        145 :         if (g_dump_transport_stats) {
    1873                 :          4 :                 pthread_mutex_lock(&g_stats_mutex);
    1874                 :          4 :                 perf_dump_transport_statistics(worker);
    1875                 :          4 :                 pthread_mutex_unlock(&g_stats_mutex);
    1876                 :            :         }
    1877                 :            : 
    1878         [ +  + ]:        357 :         TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    1879                 :        212 :                 cleanup_ns_worker_ctx(ns_ctx);
    1880                 :            :         }
    1881                 :            : 
    1882                 :        145 :         return 0;
    1883                 :            : }
    1884                 :            : 
    1885                 :            : static void
    1886                 :          0 : usage(char *program_name)
    1887                 :            : {
    1888         [ #  # ]:          0 :         printf("%s options", program_name);
    1889                 :            : #if defined(SPDK_CONFIG_URING) || defined(HAVE_LIBAIO)
    1890         [ #  # ]:          0 :         printf(" [Kernel device(s)]...");
    1891                 :            : #endif
    1892         [ #  # ]:          0 :         printf("\n\n");
    1893         [ #  # ]:          0 :         printf("==== BASIC OPTIONS ====\n\n");
    1894         [ #  # ]:          0 :         printf("\t-q, --io-depth <val> io depth\n");
    1895         [ #  # ]:          0 :         printf("\t-o, --io-size <val> io size in bytes\n");
    1896         [ #  # ]:          0 :         printf("\t-w, --io-pattern <pattern> io pattern type, must be one of\n");
    1897         [ #  # ]:          0 :         printf("\t\t(read, write, randread, randwrite, rw, randrw)\n");
    1898         [ #  # ]:          0 :         printf("\t-M, --rwmixread <0-100> rwmixread (100 for reads, 0 for writes)\n");
    1899         [ #  # ]:          0 :         printf("\t-t, --time <sec> time in seconds\n");
    1900         [ #  # ]:          0 :         printf("\t-a, --warmup-time <sec> warmup time in seconds\n");
    1901         [ #  # ]:          0 :         printf("\t-c, --core-mask <mask> core mask for I/O submission/completion.\n");
    1902         [ #  # ]:          0 :         printf("\t\t(default: 1)\n");
    1903         [ #  # ]:          0 :         printf("\t-r, --transport <fmt> Transport ID for local PCIe NVMe or NVMeoF\n");
    1904         [ #  # ]:          0 :         printf("\t\t Format: 'key:value [key:value] ...'\n");
    1905         [ #  # ]:          0 :         printf("\t\t Keys:\n");
    1906         [ #  # ]:          0 :         printf("\t\t  trtype      Transport type (e.g. PCIe, RDMA)\n");
    1907         [ #  # ]:          0 :         printf("\t\t  adrfam      Address family (e.g. IPv4, IPv6)\n");
    1908         [ #  # ]:          0 :         printf("\t\t  traddr      Transport address (e.g. 0000:04:00.0 for PCIe or 192.168.100.8 for RDMA)\n");
    1909         [ #  # ]:          0 :         printf("\t\t  trsvcid     Transport service identifier (e.g. 4420)\n");
    1910         [ #  # ]:          0 :         printf("\t\t  subnqn      Subsystem NQN (default: %s)\n", SPDK_NVMF_DISCOVERY_NQN);
    1911         [ #  # ]:          0 :         printf("\t\t  ns          NVMe namespace ID (all active namespaces are used by default)\n");
    1912         [ #  # ]:          0 :         printf("\t\t  hostnqn     Host NQN\n");
    1913         [ #  # ]:          0 :         printf("\t\t Example: -r 'trtype:PCIe traddr:0000:04:00.0' for PCIe or\n");
    1914         [ #  # ]:          0 :         printf("\t\t          -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420' for NVMeoF\n");
    1915         [ #  # ]:          0 :         printf("\t\t Note: can be specified multiple times to test multiple disks/targets.\n");
    1916                 :          0 :         printf("\n");
    1917                 :            : 
    1918         [ #  # ]:          0 :         printf("==== ADVANCED OPTIONS ====\n\n");
    1919         [ #  # ]:          0 :         printf("\t--use-every-core for each namespace, I/Os are submitted from all cores\n");
    1920         [ #  # ]:          0 :         printf("\t--io-queue-size <val> size of NVMe IO queue. Default: maximum allowed by controller\n");
    1921         [ #  # ]:          0 :         printf("\t-O, --io-unit-size io unit size in bytes (4-byte aligned) for SPDK driver. default: same as io size\n");
    1922         [ #  # ]:          0 :         printf("\t-P, --num-qpairs <val> number of io queues per namespace. default: 1\n");
    1923         [ #  # ]:          0 :         printf("\t-U, --num-unused-qpairs <val> number of unused io queues per controller. default: 0\n");
    1924         [ #  # ]:          0 :         printf("\t-A, --buffer-alignment IO buffer alignment. Must be power of 2 and not less than cache line (%u)\n",
    1925                 :            :                SPDK_CACHE_LINE_SIZE);
    1926         [ #  # ]:          0 :         printf("\t-s, --hugemem-size <MB> DPDK huge memory size in MB.\n");
    1927         [ #  # ]:          0 :         printf("\t-g, --mem-single-seg use single file descriptor for DPDK memory segments\n");
    1928         [ #  # ]:          0 :         printf("\t-C, --max-completion-per-poll <val> max completions per poll\n");
    1929         [ #  # ]:          0 :         printf("\t\t(default: 0 - unlimited)\n");
    1930         [ #  # ]:          0 :         printf("\t-i, --shmem-grp-id <id> shared memory group ID\n");
    1931         [ #  # ]:          0 :         printf("\t-d, --number-ios <val> number of I/O to perform per thread on each namespace. Note: this is additional exit criteria.\n");
    1932         [ #  # ]:          0 :         printf("\t\t(default: 0 - unlimited)\n");
    1933         [ #  # ]:          0 :         printf("\t-e, --metadata <fmt> metadata configuration\n");
    1934         [ #  # ]:          0 :         printf("\t\t Keys:\n");
    1935         [ #  # ]:          0 :         printf("\t\t  PRACT      Protection Information Action bit (PRACT=1 or PRACT=0)\n");
    1936         [ #  # ]:          0 :         printf("\t\t  PRCHK      Control of Protection Information Checking (PRCHK=GUARD|REFTAG|APPTAG)\n");
    1937         [ #  # ]:          0 :         printf("\t\t Example: -e 'PRACT=0,PRCHK=GUARD|REFTAG|APPTAG'\n");
    1938         [ #  # ]:          0 :         printf("\t\t          -e 'PRACT=1,PRCHK=GUARD'\n");
    1939         [ #  # ]:          0 :         printf("\t-F, --zipf <theta> use zipf distribution for random I/O\n");
    1940                 :            : #ifdef SPDK_CONFIG_URING
    1941         [ #  # ]:          0 :         printf("\t-R, --enable-uring enable using liburing to drive kernel devices (Default: libaio)\n");
    1942                 :            : #endif
    1943         [ #  # ]:          0 :         printf("\t--iova-mode <mode> specify DPDK IOVA mode: va|pa\n");
    1944         [ #  # ]:          0 :         printf("\t--no-huge, SPDK is run without hugepages\n");
    1945                 :          0 :         printf("\n");
    1946                 :            : 
    1947         [ #  # ]:          0 :         printf("==== PCIe OPTIONS ====\n\n");
    1948         [ #  # ]:          0 :         printf("\t-b, --allowed-pci-addr <addr> allowed local PCIe device address\n");
    1949         [ #  # ]:          0 :         printf("\t\t Example: -b 0000:d8:00.0 -b 0000:d9:00.0\n");
    1950         [ #  # ]:          0 :         printf("\t-V, --enable-vmd enable VMD enumeration\n");
    1951         [ #  # ]:          0 :         printf("\t-D, --disable-sq-cmb disable submission queue in controller memory buffer, default: enabled\n");
    1952                 :          0 :         printf("\n");
    1953                 :            : 
    1954         [ #  # ]:          0 :         printf("==== TCP OPTIONS ====\n\n");
    1955         [ #  # ]:          0 :         printf("\t-S, --default-sock-impl <impl> set the default sock impl, e.g. \"posix\"\n");
    1956         [ #  # ]:          0 :         printf("\t--disable-ktls disable Kernel TLS. Only valid for ssl impl. Default for ssl impl\n");
    1957         [ #  # ]:          0 :         printf("\t--enable-ktls enable Kernel TLS. Only valid for ssl impl\n");
    1958         [ #  # ]:          0 :         printf("\t--tls-version <val> TLS version to use. Only valid for ssl impl. Default: 0 (auto-negotiation)\n");
    1959         [ #  # ]:          0 :         printf("\t--psk-path <val> Path to PSK file (only applies when sock_impl == ssl)\n");
    1960         [ #  # ]:          0 :         printf("\t--psk-identity <val> Default PSK ID, e.g. psk.spdk.io (only applies when sock_impl == ssl)\n");
    1961         [ #  # ]:          0 :         printf("\t--zerocopy-threshold <val> data is sent with MSG_ZEROCOPY if size is greater than this val. Default: 0 to disable it\n");
    1962         [ #  # ]:          0 :         printf("\t--zerocopy-threshold-sock-impl <impl> specify the sock implementation to set zerocopy_threshold\n");
    1963         [ #  # ]:          0 :         printf("\t-z, --disable-zcopy <impl> disable zero copy send for the given sock implementation. Default for posix impl\n");
    1964         [ #  # ]:          0 :         printf("\t-Z, --enable-zcopy <impl> enable zero copy send for the given sock implementation\n");
    1965         [ #  # ]:          0 :         printf("\t-k, --keepalive <ms> keep alive timeout period in millisecond\n");
    1966         [ #  # ]:          0 :         printf("\t-H, --enable-tcp-hdgst enable header digest for TCP transport, default: disabled\n");
    1967         [ #  # ]:          0 :         printf("\t-I, --enable-tcp-ddgst enable data digest for TCP transport, default: disabled\n");
    1968                 :          0 :         printf("\n");
    1969                 :            : 
    1970         [ #  # ]:          0 :         printf("==== RDMA OPTIONS ====\n\n");
    1971         [ #  # ]:          0 :         printf("\t--transport-tos <val> specify the type of service for RDMA transport. Default: 0 (disabled)\n");
    1972         [ #  # ]:          0 :         printf("\t--rdma-srq-size <val> The size of a shared rdma receive queue. Default: 0 (disabled)\n");
    1973         [ #  # ]:          0 :         printf("\t-k, --keepalive <ms> keep alive timeout period in millisecond\n");
    1974                 :          0 :         printf("\n");
    1975                 :            : 
    1976         [ #  # ]:          0 :         printf("==== LOGGING ====\n\n");
    1977         [ #  # ]:          0 :         printf("\t-L, --enable-sw-latency-tracking enable latency tracking via sw, default: disabled\n");
    1978         [ #  # ]:          0 :         printf("\t\t-L for latency summary, -LL for detailed histogram\n");
    1979         [ #  # ]:          0 :         printf("\t-l, --enable-ssd-latency-tracking enable latency tracking via ssd (if supported), default: disabled\n");
    1980         [ #  # ]:          0 :         printf("\t-N, --no-shst-notification no shutdown notification process for controllers, default: disabled\n");
    1981         [ #  # ]:          0 :         printf("\t-Q, --continue-on-error <val> Do not stop on error. Log I/O errors every N times (default: 1)\n");
    1982                 :          0 :         spdk_log_usage(stdout, "\t-T");
    1983         [ #  # ]:          0 :         printf("\t-m, --cpu-usage display real-time overall cpu usage on used cores\n");
    1984                 :            : #ifdef DEBUG
    1985         [ #  # ]:          0 :         printf("\t-G, --enable-debug enable debug logging\n");
    1986                 :            : #else
    1987                 :            :         printf("\t-G, --enable-debug enable debug logging (flag disabled, must reconfigure with --enable-debug)\n");
    1988                 :            : #endif
    1989         [ #  # ]:          0 :         printf("\t--transport-stats dump transport statistics\n");
    1990         [ #  # ]:          0 :         printf("\n\n");
    1991                 :          0 : }
    1992                 :            : 
    1993                 :            : static void
    1994                 :     185600 : check_cutoff(void *ctx, uint64_t start, uint64_t end, uint64_t count,
    1995                 :            :              uint64_t total, uint64_t so_far)
    1996                 :            : {
    1997                 :            :         double so_far_pct;
    1998                 :     185600 :         double **cutoff = ctx;
    1999                 :            : 
    2000         [ +  + ]:     185600 :         if (count == 0) {
    2001                 :     180043 :                 return;
    2002                 :            :         }
    2003                 :            : 
    2004                 :       5557 :         so_far_pct = (double)so_far / total;
    2005   [ +  +  +  + ]:       5932 :         while (so_far_pct >= **cutoff && **cutoff > 0) {
    2006         [ -  + ]:        375 :                 printf("%9.5f%% : %9.3fus\n", **cutoff * 100, (double)end * 1000 * 1000 / g_tsc_rate);
    2007                 :        375 :                 (*cutoff)++;
    2008                 :            :         }
    2009                 :            : }
    2010                 :            : 
    2011                 :            : static void
    2012                 :     185600 : print_bucket(void *ctx, uint64_t start, uint64_t end, uint64_t count,
    2013                 :            :              uint64_t total, uint64_t so_far)
    2014                 :            : {
    2015                 :            :         double so_far_pct;
    2016                 :            : 
    2017         [ +  + ]:     185600 :         if (count == 0) {
    2018                 :     180043 :                 return;
    2019                 :            :         }
    2020                 :            : 
    2021                 :       5557 :         so_far_pct = (double)so_far * 100 / total;
    2022                 :       5557 :         printf("%9.3f - %9.3f: %9.4f%%  (%9ju)\n",
    2023                 :       5557 :                (double)start * 1000 * 1000 / g_tsc_rate,
    2024         [ -  + ]:       5557 :                (double)end * 1000 * 1000 / g_tsc_rate,
    2025                 :            :                so_far_pct, count);
    2026                 :            : }
    2027                 :            : 
    2028                 :            : static void
    2029                 :        127 : print_performance(void)
    2030                 :            : {
    2031                 :            :         uint64_t total_io_completed, total_io_tsc;
    2032                 :            :         double io_per_second, mb_per_second, average_latency, min_latency, max_latency;
    2033                 :            :         double sum_ave_latency, min_latency_so_far, max_latency_so_far;
    2034                 :            :         double total_io_per_second, total_mb_per_second;
    2035                 :            :         int ns_count;
    2036                 :            :         struct worker_thread    *worker;
    2037                 :            :         struct ns_worker_ctx    *ns_ctx;
    2038                 :            :         uint32_t max_strlen;
    2039                 :            : 
    2040                 :        127 :         total_io_per_second = 0;
    2041                 :        127 :         total_mb_per_second = 0;
    2042                 :        127 :         total_io_completed = 0;
    2043                 :        127 :         total_io_tsc = 0;
    2044                 :        127 :         min_latency_so_far = (double)UINT64_MAX;
    2045                 :        127 :         max_latency_so_far = 0;
    2046                 :        127 :         ns_count = 0;
    2047                 :            : 
    2048                 :        127 :         max_strlen = 0;
    2049         [ +  + ]:        272 :         TAILQ_FOREACH(worker, &g_workers, link) {
    2050         [ +  + ]:        357 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    2051   [ +  +  +  +  :        212 :                         max_strlen = spdk_max(strlen(ns_ctx->entry->name), max_strlen);
                   -  + ]
    2052                 :            :                 }
    2053                 :            :         }
    2054                 :            : 
    2055                 :        127 :         printf("========================================================\n");
    2056                 :        127 :         printf("%*s\n", max_strlen + 60, "Latency(us)");
    2057                 :        127 :         printf("%-*s: %10s %10s %10s %10s %10s\n",
    2058                 :            :                max_strlen + 13, "Device Information", "IOPS", "MiB/s", "Average", "min", "max");
    2059                 :            : 
    2060         [ +  + ]:        272 :         TAILQ_FOREACH(worker, &g_workers, link) {
    2061         [ +  + ]:        357 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    2062         [ +  - ]:        212 :                         if (ns_ctx->stats.io_completed != 0) {
    2063                 :        212 :                                 io_per_second = (double)ns_ctx->stats.io_completed * 1000 * 1000 / g_elapsed_time_in_usec;
    2064                 :        212 :                                 mb_per_second = io_per_second * g_io_size_bytes / (1024 * 1024);
    2065                 :        212 :                                 average_latency = ((double)ns_ctx->stats.total_tsc / ns_ctx->stats.io_completed) * 1000 * 1000 /
    2066                 :            :                                                   g_tsc_rate;
    2067                 :        212 :                                 min_latency = (double)ns_ctx->stats.min_tsc * 1000 * 1000 / g_tsc_rate;
    2068         [ +  + ]:        212 :                                 if (min_latency < min_latency_so_far) {
    2069                 :        159 :                                         min_latency_so_far = min_latency;
    2070                 :            :                                 }
    2071                 :            : 
    2072                 :        212 :                                 max_latency = (double)ns_ctx->stats.max_tsc * 1000 * 1000 / g_tsc_rate;
    2073         [ +  + ]:        212 :                                 if (max_latency > max_latency_so_far) {
    2074                 :        162 :                                         max_latency_so_far = max_latency;
    2075                 :            :                                 }
    2076                 :            : 
    2077                 :        212 :                                 printf("%-*.*s from core %2u: %10.2f %10.2f %10.2f %10.2f %10.2f\n",
    2078                 :        212 :                                        max_strlen, max_strlen, ns_ctx->entry->name, worker->lcore,
    2079                 :            :                                        io_per_second, mb_per_second,
    2080                 :            :                                        average_latency, min_latency, max_latency);
    2081                 :        212 :                                 total_io_per_second += io_per_second;
    2082                 :        212 :                                 total_mb_per_second += mb_per_second;
    2083                 :        212 :                                 total_io_completed += ns_ctx->stats.io_completed;
    2084                 :        212 :                                 total_io_tsc += ns_ctx->stats.total_tsc;
    2085                 :        212 :                                 ns_count++;
    2086                 :            :                         }
    2087                 :            :                 }
    2088                 :            :         }
    2089                 :            : 
    2090   [ +  -  +  - ]:        127 :         if (ns_count != 0 && total_io_completed) {
    2091                 :        127 :                 sum_ave_latency = ((double)total_io_tsc / total_io_completed) * 1000 * 1000 / g_tsc_rate;
    2092                 :        127 :                 printf("========================================================\n");
    2093                 :        127 :                 printf("%-*s: %10.2f %10.2f %10.2f %10.2f %10.2f\n",
    2094                 :            :                        max_strlen + 13, "Total", total_io_per_second, total_mb_per_second,
    2095                 :            :                        sum_ave_latency, min_latency_so_far, max_latency_so_far);
    2096                 :        127 :                 printf("\n");
    2097                 :            :         }
    2098                 :            : 
    2099   [ +  +  -  + ]:        127 :         if (g_latency_sw_tracking_level == 0 || total_io_completed == 0) {
    2100                 :        114 :                 return;
    2101                 :            :         }
    2102                 :            : 
    2103         [ +  + ]:         26 :         TAILQ_FOREACH(worker, &g_workers, link) {
    2104         [ +  + ]:         38 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    2105                 :         25 :                         const double *cutoff = g_latency_cutoffs;
    2106                 :            : 
    2107                 :         25 :                         printf("Summary latency data for %-43.43s from core %u:\n", ns_ctx->entry->name, worker->lcore);
    2108                 :         25 :                         printf("=================================================================================\n");
    2109                 :            : 
    2110                 :         25 :                         spdk_histogram_data_iterate(ns_ctx->histogram, check_cutoff, &cutoff);
    2111                 :            : 
    2112                 :         25 :                         printf("\n");
    2113                 :            :                 }
    2114                 :            :         }
    2115                 :            : 
    2116         [ -  + ]:         13 :         if (g_latency_sw_tracking_level == 1) {
    2117                 :          0 :                 return;
    2118                 :            :         }
    2119                 :            : 
    2120         [ +  + ]:         26 :         TAILQ_FOREACH(worker, &g_workers, link) {
    2121         [ +  + ]:         38 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    2122                 :         25 :                         printf("Latency histogram for %-43.43s from core %u:\n", ns_ctx->entry->name, worker->lcore);
    2123                 :         25 :                         printf("==============================================================================\n");
    2124                 :         25 :                         printf("       Range in us     Cumulative    IO count\n");
    2125                 :            : 
    2126                 :         25 :                         spdk_histogram_data_iterate(ns_ctx->histogram, print_bucket, NULL);
    2127                 :         25 :                         printf("\n");
    2128                 :            :                 }
    2129                 :            :         }
    2130                 :            : 
    2131                 :            : }
    2132                 :            : 
    2133                 :            : static void
    2134                 :          0 : print_latency_page(struct ctrlr_entry *entry)
    2135                 :            : {
    2136                 :            :         int i;
    2137                 :            : 
    2138                 :          0 :         printf("\n");
    2139         [ #  # ]:          0 :         printf("%s\n", entry->name);
    2140         [ #  # ]:          0 :         printf("--------------------------------------------------------\n");
    2141                 :            : 
    2142         [ #  # ]:          0 :         for (i = 0; i < 32; i++) {
    2143         [ #  # ]:          0 :                 if (entry->latency_page->buckets_32us[i]) {
    2144         [ #  # ]:          0 :                         printf("Bucket %dus - %dus: %d\n", i * 32, (i + 1) * 32, entry->latency_page->buckets_32us[i]);
    2145                 :            :                 }
    2146                 :            :         }
    2147         [ #  # ]:          0 :         for (i = 0; i < 31; i++) {
    2148         [ #  # ]:          0 :                 if (entry->latency_page->buckets_1ms[i]) {
    2149         [ #  # ]:          0 :                         printf("Bucket %dms - %dms: %d\n", i + 1, i + 2, entry->latency_page->buckets_1ms[i]);
    2150                 :            :                 }
    2151                 :            :         }
    2152         [ #  # ]:          0 :         for (i = 0; i < 31; i++) {
    2153         [ #  # ]:          0 :                 if (entry->latency_page->buckets_32ms[i])
    2154         [ #  # ]:          0 :                         printf("Bucket %dms - %dms: %d\n", (i + 1) * 32, (i + 2) * 32,
    2155                 :          0 :                                entry->latency_page->buckets_32ms[i]);
    2156                 :            :         }
    2157                 :          0 : }
    2158                 :            : 
    2159                 :            : static void
    2160                 :          0 : print_latency_statistics(const char *op_name, enum spdk_nvme_intel_log_page log_page)
    2161                 :            : {
    2162                 :            :         struct ctrlr_entry      *ctrlr;
    2163                 :            : 
    2164         [ #  # ]:          0 :         printf("%s Latency Statistics:\n", op_name);
    2165         [ #  # ]:          0 :         printf("========================================================\n");
    2166         [ #  # ]:          0 :         TAILQ_FOREACH(ctrlr, &g_controllers, link) {
    2167         [ #  # ]:          0 :                 if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr->ctrlr, log_page)) {
    2168         [ #  # ]:          0 :                         if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr->ctrlr, log_page, SPDK_NVME_GLOBAL_NS_TAG,
    2169                 :          0 :                                                              ctrlr->latency_page, sizeof(struct spdk_nvme_intel_rw_latency_page), 0,
    2170                 :            :                                                              enable_latency_tracking_complete,
    2171                 :            :                                                              NULL)) {
    2172         [ #  # ]:          0 :                                 printf("nvme_ctrlr_cmd_get_log_page() failed\n");
    2173                 :          0 :                                 exit(1);
    2174                 :            :                         }
    2175                 :            : 
    2176                 :          0 :                         g_outstanding_commands++;
    2177                 :            :                 } else {
    2178         [ #  # ]:          0 :                         printf("Controller %s: %s latency statistics not supported\n", ctrlr->name, op_name);
    2179                 :            :                 }
    2180                 :            :         }
    2181                 :            : 
    2182         [ #  # ]:          0 :         while (g_outstanding_commands) {
    2183         [ #  # ]:          0 :                 TAILQ_FOREACH(ctrlr, &g_controllers, link) {
    2184                 :          0 :                         spdk_nvme_ctrlr_process_admin_completions(ctrlr->ctrlr);
    2185                 :            :                 }
    2186                 :            :         }
    2187                 :            : 
    2188         [ #  # ]:          0 :         TAILQ_FOREACH(ctrlr, &g_controllers, link) {
    2189         [ #  # ]:          0 :                 if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr->ctrlr, log_page)) {
    2190                 :          0 :                         print_latency_page(ctrlr);
    2191                 :            :                 }
    2192                 :            :         }
    2193                 :          0 :         printf("\n");
    2194                 :          0 : }
    2195                 :            : 
    2196                 :            : static void
    2197                 :        127 : print_stats(void)
    2198                 :            : {
    2199                 :        127 :         print_performance();
    2200   [ -  +  -  + ]:        127 :         if (g_latency_ssd_tracking_enable) {
    2201         [ #  # ]:          0 :                 if (g_rw_percentage != 0) {
    2202                 :          0 :                         print_latency_statistics("Read", SPDK_NVME_INTEL_LOG_READ_CMD_LATENCY);
    2203                 :            :                 }
    2204         [ #  # ]:          0 :                 if (g_rw_percentage != 100) {
    2205                 :          0 :                         print_latency_statistics("Write", SPDK_NVME_INTEL_LOG_WRITE_CMD_LATENCY);
    2206                 :            :                 }
    2207                 :            :         }
    2208                 :        127 : }
    2209                 :            : 
    2210                 :            : static void
    2211                 :        137 : unregister_trids(void)
    2212                 :            : {
    2213                 :            :         struct trid_entry *trid_entry, *tmp;
    2214                 :            : 
    2215         [ +  + ]:        274 :         TAILQ_FOREACH_SAFE(trid_entry, &g_trid_list, tailq, tmp) {
    2216         [ -  + ]:        137 :                 TAILQ_REMOVE(&g_trid_list, trid_entry, tailq);
    2217                 :        137 :                 free(trid_entry);
    2218                 :            :         }
    2219                 :        137 : }
    2220                 :            : 
    2221                 :            : static int
    2222                 :        137 : add_trid(const char *trid_str)
    2223                 :            : {
    2224                 :            :         struct trid_entry *trid_entry;
    2225                 :            :         struct spdk_nvme_transport_id *trid;
    2226                 :            :         char *ns;
    2227                 :            :         char *hostnqn;
    2228                 :            : 
    2229                 :        137 :         trid_entry = calloc(1, sizeof(*trid_entry));
    2230         [ -  + ]:        137 :         if (trid_entry == NULL) {
    2231                 :          0 :                 return -1;
    2232                 :            :         }
    2233                 :            : 
    2234                 :        137 :         trid = &trid_entry->trid;
    2235                 :        137 :         trid->trtype = SPDK_NVME_TRANSPORT_PCIE;
    2236                 :        137 :         snprintf(trid->subnqn, sizeof(trid->subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
    2237                 :            : 
    2238         [ -  + ]:        137 :         if (spdk_nvme_transport_id_parse(trid, trid_str) != 0) {
    2239         [ #  # ]:          0 :                 fprintf(stderr, "Invalid transport ID format '%s'\n", trid_str);
    2240                 :          0 :                 free(trid_entry);
    2241                 :          0 :                 return 1;
    2242                 :            :         }
    2243                 :            : 
    2244   [ +  +  +  - ]:        137 :         if ((ns = strcasestr(trid_str, "ns:")) ||
    2245   [ -  +  -  + ]:        137 :             (ns = strcasestr(trid_str, "ns="))) {
    2246                 :          0 :                 char nsid_str[6]; /* 5 digits maximum in an nsid */
    2247                 :            :                 int len;
    2248                 :            :                 int nsid;
    2249                 :            : 
    2250                 :          0 :                 ns += 3;
    2251                 :            : 
    2252         [ #  # ]:          0 :                 len = strcspn(ns, " \t\n");
    2253         [ #  # ]:          0 :                 if (len > 5) {
    2254         [ #  # ]:          0 :                         fprintf(stderr, "NVMe namespace IDs must be 5 digits or less\n");
    2255                 :          0 :                         free(trid_entry);
    2256                 :          0 :                         return 1;
    2257                 :            :                 }
    2258                 :            : 
    2259         [ #  # ]:          0 :                 memcpy(nsid_str, ns, len);
    2260                 :          0 :                 nsid_str[len] = '\0';
    2261                 :            : 
    2262                 :          0 :                 nsid = spdk_strtol(nsid_str, 10);
    2263   [ #  #  #  # ]:          0 :                 if (nsid <= 0 || nsid > 65535) {
    2264         [ #  # ]:          0 :                         fprintf(stderr, "NVMe namespace IDs must be less than 65536 and greater than 0\n");
    2265                 :          0 :                         free(trid_entry);
    2266                 :          0 :                         return 1;
    2267                 :            :                 }
    2268                 :            : 
    2269                 :          0 :                 trid_entry->nsid = (uint16_t)nsid;
    2270                 :            :         }
    2271                 :            : 
    2272   [ +  +  +  + ]:        137 :         if ((hostnqn = strcasestr(trid_str, "hostnqn:")) ||
    2273   [ -  +  -  + ]:        134 :             (hostnqn = strcasestr(trid_str, "hostnqn="))) {
    2274                 :            :                 size_t len;
    2275                 :            : 
    2276                 :          3 :                 hostnqn += strlen("hostnqn:");
    2277                 :            : 
    2278         [ -  + ]:          3 :                 len = strcspn(hostnqn, " \t\n");
    2279         [ -  + ]:          3 :                 if (len > (sizeof(trid_entry->hostnqn) - 1)) {
    2280         [ #  # ]:          0 :                         fprintf(stderr, "Host NQN is too long\n");
    2281                 :          0 :                         free(trid_entry);
    2282                 :          0 :                         return 1;
    2283                 :            :                 }
    2284                 :            : 
    2285   [ -  +  -  + ]:          3 :                 memcpy(trid_entry->hostnqn, hostnqn, len);
    2286                 :          3 :                 trid_entry->hostnqn[len] = '\0';
    2287                 :            :         }
    2288                 :            : 
    2289                 :        137 :         TAILQ_INSERT_TAIL(&g_trid_list, trid_entry, tailq);
    2290                 :        137 :         return 0;
    2291                 :            : }
    2292                 :            : 
    2293                 :            : static int
    2294                 :          0 : add_allowed_pci_device(const char *bdf_str, struct spdk_env_opts *env_opts)
    2295                 :            : {
    2296                 :            :         int rc;
    2297                 :            : 
    2298         [ #  # ]:          0 :         if (env_opts->num_pci_addr >= MAX_ALLOWED_PCI_DEVICE_NUM) {
    2299   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Currently we only support allowed PCI device num=%d\n",
    2300                 :            :                         MAX_ALLOWED_PCI_DEVICE_NUM);
    2301                 :          0 :                 return -1;
    2302                 :            :         }
    2303                 :            : 
    2304                 :          0 :         rc = spdk_pci_addr_parse(&env_opts->pci_allowed[env_opts->num_pci_addr], bdf_str);
    2305         [ #  # ]:          0 :         if (rc < 0) {
    2306   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to parse the given bdf_str=%s\n", bdf_str);
    2307                 :          0 :                 return -1;
    2308                 :            :         }
    2309                 :            : 
    2310                 :          0 :         env_opts->num_pci_addr++;
    2311                 :          0 :         return 0;
    2312                 :            : }
    2313                 :            : 
    2314                 :            : static size_t
    2315                 :          0 : parse_next_key(const char **str, char *key, char *val, size_t key_buf_size,
    2316                 :            :                size_t val_buf_size)
    2317                 :            : {
    2318                 :            :         const char *sep;
    2319                 :          0 :         const char *separator = ", \t\n";
    2320                 :            :         size_t key_len, val_len;
    2321                 :            : 
    2322   [ #  #  #  # ]:          0 :         *str += strspn(*str, separator);
    2323                 :            : 
    2324         [ #  # ]:          0 :         sep = strchr(*str, '=');
    2325         [ #  # ]:          0 :         if (!sep) {
    2326         [ #  # ]:          0 :                 fprintf(stderr, "Key without '=' separator\n");
    2327                 :          0 :                 return 0;
    2328                 :            :         }
    2329                 :            : 
    2330                 :          0 :         key_len = sep - *str;
    2331         [ #  # ]:          0 :         if (key_len >= key_buf_size) {
    2332         [ #  # ]:          0 :                 fprintf(stderr, "Key length %zu is greater than maximum allowed %zu\n",
    2333                 :            :                         key_len, key_buf_size - 1);
    2334                 :          0 :                 return 0;
    2335                 :            :         }
    2336                 :            : 
    2337   [ #  #  #  # ]:          0 :         memcpy(key, *str, key_len);
    2338                 :          0 :         key[key_len] = '\0';
    2339                 :            : 
    2340                 :          0 :         *str += key_len + 1;    /* Skip key */
    2341   [ #  #  #  # ]:          0 :         val_len = strcspn(*str, separator);
    2342         [ #  # ]:          0 :         if (val_len == 0) {
    2343         [ #  # ]:          0 :                 fprintf(stderr, "Key without value\n");
    2344                 :          0 :                 return 0;
    2345                 :            :         }
    2346                 :            : 
    2347         [ #  # ]:          0 :         if (val_len >= val_buf_size) {
    2348         [ #  # ]:          0 :                 fprintf(stderr, "Value length %zu is greater than maximum allowed %zu\n",
    2349                 :            :                         val_len, val_buf_size - 1);
    2350                 :          0 :                 return 0;
    2351                 :            :         }
    2352                 :            : 
    2353   [ #  #  #  # ]:          0 :         memcpy(val, *str, val_len);
    2354                 :          0 :         val[val_len] = '\0';
    2355                 :            : 
    2356                 :          0 :         *str += val_len;
    2357                 :            : 
    2358                 :          0 :         return val_len;
    2359                 :            : }
    2360                 :            : 
    2361                 :            : static int
    2362                 :          0 : parse_metadata(const char *metacfg_str)
    2363                 :            : {
    2364                 :          0 :         const char *str;
    2365                 :            :         size_t val_len;
    2366                 :          0 :         char key[32];
    2367                 :          0 :         char val[1024];
    2368                 :            : 
    2369         [ #  # ]:          0 :         if (metacfg_str == NULL) {
    2370                 :          0 :                 return -EINVAL;
    2371                 :            :         }
    2372                 :            : 
    2373                 :          0 :         str = metacfg_str;
    2374                 :            : 
    2375         [ #  # ]:          0 :         while (*str != '\0') {
    2376                 :          0 :                 val_len = parse_next_key(&str, key, val, sizeof(key), sizeof(val));
    2377         [ #  # ]:          0 :                 if (val_len == 0) {
    2378         [ #  # ]:          0 :                         fprintf(stderr, "Failed to parse metadata\n");
    2379                 :          0 :                         return -EINVAL;
    2380                 :            :                 }
    2381                 :            : 
    2382         [ #  # ]:          0 :                 if (strcmp(key, "PRACT") == 0) {
    2383         [ #  # ]:          0 :                         if (*val == '1') {
    2384                 :          0 :                                 g_metacfg_pract_flag = SPDK_NVME_IO_FLAGS_PRACT;
    2385                 :            :                         }
    2386         [ #  # ]:          0 :                 } else if (strcmp(key, "PRCHK") == 0) {
    2387         [ #  # ]:          0 :                         if (strstr(val, "GUARD") != NULL) {
    2388                 :          0 :                                 g_metacfg_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
    2389                 :            :                         }
    2390         [ #  # ]:          0 :                         if (strstr(val, "REFTAG") != NULL) {
    2391                 :          0 :                                 g_metacfg_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
    2392                 :            :                         }
    2393         [ #  # ]:          0 :                         if (strstr(val, "APPTAG") != NULL) {
    2394                 :          0 :                                 g_metacfg_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_APPTAG;
    2395                 :            :                         }
    2396                 :            :                 } else {
    2397         [ #  # ]:          0 :                         fprintf(stderr, "Unknown key '%s'\n", key);
    2398                 :            :                 }
    2399                 :            :         }
    2400                 :            : 
    2401                 :          0 :         return 0;
    2402                 :            : }
    2403                 :            : 
    2404                 :            : #define PERF_GETOPT_SHORT "a:b:c:d:e:ghi:lmo:q:r:k:s:t:w:z:A:C:DF:GHILM:NO:P:Q:RS:T:U:VZ:"
    2405                 :            : 
    2406                 :            : static const struct option g_perf_cmdline_opts[] = {
    2407                 :            : #define PERF_WARMUP_TIME        'a'
    2408                 :            :         {"warmup-time",                       required_argument,      NULL, PERF_WARMUP_TIME},
    2409                 :            : #define PERF_ALLOWED_PCI_ADDR   'b'
    2410                 :            :         {"allowed-pci-addr",                  required_argument,      NULL, PERF_ALLOWED_PCI_ADDR},
    2411                 :            : #define PERF_CORE_MASK  'c'
    2412                 :            :         {"core-mask",                 required_argument,      NULL, PERF_CORE_MASK},
    2413                 :            : #define PERF_METADATA   'e'
    2414                 :            :         {"metadata",                  required_argument,      NULL, PERF_METADATA},
    2415                 :            : #define PERF_MEM_SINGL_SEG      'g'
    2416                 :            :         {"mem-single-seg", no_argument, NULL, PERF_MEM_SINGL_SEG},
    2417                 :            : #define PERF_HELP               'h'
    2418                 :            :         {"help", no_argument, NULL, PERF_HELP},
    2419                 :            : #define PERF_SHMEM_GROUP_ID     'i'
    2420                 :            :         {"shmem-grp-id",                      required_argument,      NULL, PERF_SHMEM_GROUP_ID},
    2421                 :            : #define PERF_ENABLE_SSD_LATENCY_TRACING 'l'
    2422                 :            :         {"enable-ssd-latency-tracking", no_argument, NULL, PERF_ENABLE_SSD_LATENCY_TRACING},
    2423                 :            : #define PERF_CPU_USAGE  'm'
    2424                 :            :         {"cpu-usage", no_argument, NULL, PERF_CPU_USAGE},
    2425                 :            : #define PERF_IO_SIZE    'o'
    2426                 :            :         {"io-size",                   required_argument,      NULL, PERF_IO_SIZE},
    2427                 :            : #define PERF_IO_DEPTH   'q'
    2428                 :            :         {"io-depth",                  required_argument,      NULL, PERF_IO_DEPTH},
    2429                 :            : #define PERF_TRANSPORT  'r'
    2430                 :            :         {"transport",                 required_argument,      NULL, PERF_TRANSPORT},
    2431                 :            : #define PERF_KEEPALIVE  'k'
    2432                 :            :         {"keepalive",                 required_argument,      NULL, PERF_KEEPALIVE},
    2433                 :            : #define PERF_HUGEMEM_SIZE       's'
    2434                 :            :         {"hugemem-size",                      required_argument,      NULL, PERF_HUGEMEM_SIZE},
    2435                 :            : #define PERF_TIME       't'
    2436                 :            :         {"time",                      required_argument,      NULL, PERF_TIME},
    2437                 :            : #define PERF_NUMBER_IOS 'd'
    2438                 :            :         {"number-ios",                        required_argument,      NULL, PERF_NUMBER_IOS},
    2439                 :            : #define PERF_IO_PATTERN 'w'
    2440                 :            :         {"io-pattern",                        required_argument,      NULL, PERF_IO_PATTERN},
    2441                 :            : #define PERF_DISABLE_ZCOPY      'z'
    2442                 :            :         {"disable-zcopy",                     required_argument,      NULL, PERF_DISABLE_ZCOPY},
    2443                 :            : #define PERF_BUFFER_ALIGNMENT   'A'
    2444                 :            :         {"buffer-alignment",                  required_argument,      NULL, PERF_BUFFER_ALIGNMENT},
    2445                 :            : #define PERF_MAX_COMPLETIONS_PER_POLL   'C'
    2446                 :            :         {"max-completion-per-poll",                   required_argument,      NULL, PERF_MAX_COMPLETIONS_PER_POLL},
    2447                 :            : #define PERF_DISABLE_SQ_CMB     'D'
    2448                 :            :         {"disable-sq-cmb",                    no_argument,    NULL, PERF_DISABLE_SQ_CMB},
    2449                 :            : #define PERF_ZIPF               'F'
    2450                 :            :         {"zipf",                              required_argument,      NULL, PERF_ZIPF},
    2451                 :            : #define PERF_ENABLE_DEBUG       'G'
    2452                 :            :         {"enable-debug",                      no_argument,    NULL, PERF_ENABLE_DEBUG},
    2453                 :            : #define PERF_ENABLE_TCP_HDGST   'H'
    2454                 :            :         {"enable-tcp-hdgst",                  no_argument,    NULL, PERF_ENABLE_TCP_HDGST},
    2455                 :            : #define PERF_ENABLE_TCP_DDGST   'I'
    2456                 :            :         {"enable-tcp-ddgst",                  no_argument,    NULL, PERF_ENABLE_TCP_DDGST},
    2457                 :            : #define PERF_ENABLE_SW_LATENCY_TRACING  'L'
    2458                 :            :         {"enable-sw-latency-tracking", no_argument, NULL, PERF_ENABLE_SW_LATENCY_TRACING},
    2459                 :            : #define PERF_RW_MIXREAD 'M'
    2460                 :            :         {"rwmixread", required_argument, NULL, PERF_RW_MIXREAD},
    2461                 :            : #define PERF_NO_SHST_NOTIFICATION       'N'
    2462                 :            :         {"no-shst-notification", no_argument, NULL, PERF_NO_SHST_NOTIFICATION},
    2463                 :            : #define PERF_IO_UNIT_SIZE       'O'
    2464                 :            :         {"io-unit-size",                      required_argument,      NULL, PERF_IO_UNIT_SIZE},
    2465                 :            : #define PERF_IO_QUEUES_PER_NS   'P'
    2466                 :            :         {"num-qpairs", required_argument, NULL, PERF_IO_QUEUES_PER_NS},
    2467                 :            : #define PERF_CONTINUE_ON_ERROR  'Q'
    2468                 :            :         {"continue-on-error",                 required_argument,      NULL, PERF_CONTINUE_ON_ERROR},
    2469                 :            : #define PERF_ENABLE_URING       'R'
    2470                 :            :         {"enable-uring", no_argument, NULL, PERF_ENABLE_URING},
    2471                 :            : #define PERF_DEFAULT_SOCK_IMPL  'S'
    2472                 :            :         {"default-sock-impl", required_argument, NULL, PERF_DEFAULT_SOCK_IMPL},
    2473                 :            : #define PERF_LOG_FLAG   'T'
    2474                 :            :         {"logflag", required_argument, NULL, PERF_LOG_FLAG},
    2475                 :            : #define PERF_NUM_UNUSED_IO_QPAIRS       'U'
    2476                 :            :         {"num-unused-qpairs", required_argument, NULL, PERF_NUM_UNUSED_IO_QPAIRS},
    2477                 :            : #define PERF_ENABLE_VMD 'V'
    2478                 :            :         {"enable-vmd", no_argument, NULL, PERF_ENABLE_VMD},
    2479                 :            : #define PERF_ENABLE_ZCOPY       'Z'
    2480                 :            :         {"enable-zcopy",                      required_argument,      NULL, PERF_ENABLE_ZCOPY},
    2481                 :            : #define PERF_TRANSPORT_STATISTICS       257
    2482                 :            :         {"transport-stats", no_argument, NULL, PERF_TRANSPORT_STATISTICS},
    2483                 :            : #define PERF_IOVA_MODE          258
    2484                 :            :         {"iova-mode", required_argument, NULL, PERF_IOVA_MODE},
    2485                 :            : #define PERF_IO_QUEUE_SIZE      259
    2486                 :            :         {"io-queue-size", required_argument, NULL, PERF_IO_QUEUE_SIZE},
    2487                 :            : #define PERF_DISABLE_KTLS       260
    2488                 :            :         {"disable-ktls", no_argument, NULL, PERF_DISABLE_KTLS},
    2489                 :            : #define PERF_ENABLE_KTLS        261
    2490                 :            :         {"enable-ktls", no_argument, NULL, PERF_ENABLE_KTLS},
    2491                 :            : #define PERF_TLS_VERSION        262
    2492                 :            :         {"tls-version", required_argument, NULL, PERF_TLS_VERSION},
    2493                 :            : #define PERF_PSK_PATH           263
    2494                 :            :         {"psk-path", required_argument, NULL, PERF_PSK_PATH},
    2495                 :            : #define PERF_PSK_IDENTITY       264
    2496                 :            :         {"psk-identity ", required_argument, NULL, PERF_PSK_IDENTITY},
    2497                 :            : #define PERF_ZEROCOPY_THRESHOLD         265
    2498                 :            :         {"zerocopy-threshold", required_argument, NULL, PERF_ZEROCOPY_THRESHOLD},
    2499                 :            : #define PERF_SOCK_IMPL          266
    2500                 :            :         {"zerocopy-threshold-sock-impl", required_argument, NULL, PERF_SOCK_IMPL},
    2501                 :            : #define PERF_TRANSPORT_TOS              267
    2502                 :            :         {"transport-tos", required_argument, NULL, PERF_TRANSPORT_TOS},
    2503                 :            : #define PERF_RDMA_SRQ_SIZE      268
    2504                 :            :         {"rdma-srq-size", required_argument, NULL, PERF_RDMA_SRQ_SIZE},
    2505                 :            : #define PERF_USE_EVERY_CORE     269
    2506                 :            :         {"use-every-core", no_argument, NULL, PERF_USE_EVERY_CORE},
    2507                 :            : #define PERF_NO_HUGE            270
    2508                 :            :         {"no-huge", no_argument, NULL, PERF_NO_HUGE},
    2509                 :            :         /* Should be the last element */
    2510                 :            :         {0, 0, 0, 0}
    2511                 :            : };
    2512                 :            : 
    2513                 :            : static int
    2514                 :        137 : parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
    2515                 :            : {
    2516                 :         25 :         int op, long_idx;
    2517                 :            :         long int val;
    2518                 :         25 :         uint64_t val_u64;
    2519                 :            :         int rc;
    2520                 :         25 :         char *endptr;
    2521                 :        137 :         bool ssl_used = false;
    2522                 :        137 :         char *sock_impl = "posix";
    2523                 :            : 
    2524   [ +  +  +  + ]:       1045 :         while ((op = getopt_long(argc, argv, PERF_GETOPT_SHORT, g_perf_cmdline_opts, &long_idx)) != -1) {
    2525   [ +  +  -  -  :        908 :                 switch (op) {
          +  -  +  -  -  
          +  +  -  -  +  
          +  +  +  -  -  
          +  -  -  -  +  
          -  -  -  -  +  
          +  -  -  -  -  
                   -  - ]
    2526                 :        265 :                 case PERF_WARMUP_TIME:
    2527                 :            :                 case PERF_SHMEM_GROUP_ID:
    2528                 :            :                 case PERF_MAX_COMPLETIONS_PER_POLL:
    2529                 :            :                 case PERF_IO_QUEUES_PER_NS:
    2530                 :            :                 case PERF_KEEPALIVE:
    2531                 :            :                 case PERF_TIME:
    2532                 :            :                 case PERF_RW_MIXREAD:
    2533                 :            :                 case PERF_NUM_UNUSED_IO_QPAIRS:
    2534                 :            :                 case PERF_CONTINUE_ON_ERROR:
    2535                 :            :                 case PERF_RDMA_SRQ_SIZE:
    2536                 :        265 :                         val = spdk_strtol(optarg, 10);
    2537         [ -  + ]:        265 :                         if (val < 0) {
    2538         [ #  # ]:          0 :                                 fprintf(stderr, "Converting a string to integer failed\n");
    2539                 :          0 :                                 return val;
    2540                 :            :                         }
    2541   [ -  +  -  +  :        233 :                         switch (op) {
          -  +  +  +  -  
                   -  - ]
    2542                 :          0 :                         case PERF_WARMUP_TIME:
    2543                 :          0 :                                 g_warmup_time_in_sec = val;
    2544                 :          0 :                                 break;
    2545                 :         53 :                         case PERF_SHMEM_GROUP_ID:
    2546                 :         53 :                                 env_opts->shm_id = val;
    2547                 :         53 :                                 break;
    2548                 :          0 :                         case PERF_MAX_COMPLETIONS_PER_POLL:
    2549                 :          0 :                                 g_max_completions = val;
    2550                 :          0 :                                 break;
    2551                 :         10 :                         case PERF_IO_QUEUES_PER_NS:
    2552                 :         10 :                                 g_nr_io_queues_per_ns = val;
    2553                 :         10 :                                 break;
    2554                 :          0 :                         case PERF_KEEPALIVE:
    2555                 :          0 :                                 g_keep_alive_timeout_in_ms = val;
    2556                 :          0 :                                 break;
    2557                 :        137 :                         case PERF_TIME:
    2558                 :        137 :                                 g_time_in_sec = val;
    2559                 :        137 :                                 break;
    2560                 :         62 :                         case PERF_RW_MIXREAD:
    2561                 :         62 :                                 g_rw_percentage = val;
    2562                 :         62 :                                 g_mix_specified = true;
    2563                 :         62 :                                 break;
    2564                 :          3 :                         case PERF_CONTINUE_ON_ERROR:
    2565                 :          3 :                                 g_quiet_count = val;
    2566                 :          3 :                                 g_continue_on_error = true;
    2567                 :          3 :                                 break;
    2568                 :          0 :                         case PERF_NUM_UNUSED_IO_QPAIRS:
    2569                 :          0 :                                 g_nr_unused_io_queues = val;
    2570                 :          0 :                                 break;
    2571                 :          0 :                         case PERF_RDMA_SRQ_SIZE:
    2572                 :          0 :                                 g_rdma_srq_size = val;
    2573                 :          0 :                                 break;
    2574                 :            :                         }
    2575                 :        265 :                         break;
    2576                 :        292 :                 case PERF_IO_SIZE:
    2577                 :            :                 case PERF_IO_UNIT_SIZE:
    2578                 :            :                 case PERF_ZEROCOPY_THRESHOLD:
    2579                 :            :                 case PERF_BUFFER_ALIGNMENT:
    2580                 :            :                 case PERF_HUGEMEM_SIZE:
    2581                 :            :                 case PERF_NUMBER_IOS:
    2582                 :            :                 case PERF_IO_DEPTH:
    2583                 :            :                 case PERF_IO_QUEUE_SIZE:
    2584                 :        292 :                         rc = spdk_parse_capacity(optarg, &val_u64, NULL);
    2585         [ -  + ]:        292 :                         if (rc != 0) {
    2586         [ #  # ]:          0 :                                 fprintf(stderr, "Converting a string to integer failed\n");
    2587                 :          0 :                                 return 1;
    2588                 :            :                         }
    2589   [ +  +  -  +  :        260 :                         switch (op) {
             -  -  +  -  
                      - ]
    2590                 :        137 :                         case PERF_IO_SIZE:
    2591                 :        137 :                                 g_io_size_bytes = (uint32_t)val_u64;
    2592                 :        137 :                                 break;
    2593                 :          8 :                         case PERF_IO_UNIT_SIZE:
    2594                 :          8 :                                 g_io_unit_size = (uint32_t)val_u64;
    2595                 :          8 :                                 break;
    2596                 :          0 :                         case PERF_ZEROCOPY_THRESHOLD:
    2597                 :          0 :                                 g_sock_zcopy_threshold = (uint32_t)val_u64;
    2598                 :          0 :                                 break;
    2599                 :        137 :                         case PERF_IO_DEPTH:
    2600                 :        137 :                                 g_queue_depth = (uint32_t)val_u64;
    2601                 :        137 :                                 break;
    2602                 :          0 :                         case PERF_IO_QUEUE_SIZE:
    2603                 :          0 :                                 g_io_queue_size = (uint32_t)val_u64;
    2604                 :          0 :                                 break;
    2605                 :          0 :                         case PERF_BUFFER_ALIGNMENT:
    2606                 :          0 :                                 g_io_align = (uint32_t)val_u64;
    2607   [ #  #  #  # ]:          0 :                                 if (!spdk_u32_is_pow2(g_io_align) || g_io_align < SPDK_CACHE_LINE_SIZE) {
    2608         [ #  # ]:          0 :                                         fprintf(stderr, "Wrong alignment %u. Must be power of 2 and not less than cache lize (%u)\n",
    2609                 :            :                                                 g_io_align, SPDK_CACHE_LINE_SIZE);
    2610                 :          0 :                                         usage(argv[0]);
    2611                 :          0 :                                         return 1;
    2612                 :            :                                 }
    2613                 :          0 :                                 g_io_align_specified = true;
    2614                 :          0 :                                 break;
    2615                 :         10 :                         case PERF_HUGEMEM_SIZE:
    2616                 :         10 :                                 env_opts->mem_size = (int)val_u64;
    2617                 :         10 :                                 break;
    2618                 :          0 :                         case PERF_NUMBER_IOS:
    2619                 :          0 :                                 g_number_ios = val_u64;
    2620                 :          0 :                                 break;
    2621                 :            :                         }
    2622                 :        292 :                         break;
    2623                 :          0 :                 case PERF_ZIPF:
    2624                 :          0 :                         errno = 0;
    2625         [ #  # ]:          0 :                         g_zipf_theta = strtod(optarg, &endptr);
    2626   [ #  #  #  #  :          0 :                         if (errno || optarg == endptr || g_zipf_theta < 0) {
                   #  # ]
    2627         [ #  # ]:          0 :                                 fprintf(stderr, "Illegal zipf theta value %s\n", optarg);
    2628                 :          0 :                                 return 1;
    2629                 :            :                         }
    2630                 :          0 :                         break;
    2631                 :          0 :                 case PERF_ALLOWED_PCI_ADDR:
    2632         [ #  # ]:          0 :                         if (add_allowed_pci_device(optarg, env_opts)) {
    2633                 :          0 :                                 usage(argv[0]);
    2634                 :          0 :                                 return 1;
    2635                 :            :                         }
    2636                 :          0 :                         break;
    2637                 :         70 :                 case PERF_CORE_MASK:
    2638                 :         70 :                         env_opts->core_mask = optarg;
    2639                 :         70 :                         break;
    2640                 :          0 :                 case PERF_METADATA:
    2641         [ #  # ]:          0 :                         if (parse_metadata(optarg)) {
    2642                 :          0 :                                 usage(argv[0]);
    2643                 :          0 :                                 return 1;
    2644                 :            :                         }
    2645                 :          0 :                         break;
    2646                 :          4 :                 case PERF_MEM_SINGL_SEG:
    2647                 :          4 :                         env_opts->hugepage_single_segments = true;
    2648                 :          4 :                         break;
    2649                 :          0 :                 case PERF_ENABLE_SSD_LATENCY_TRACING:
    2650                 :          0 :                         g_latency_ssd_tracking_enable = true;
    2651                 :          0 :                         break;
    2652                 :          0 :                 case PERF_CPU_USAGE:
    2653                 :          0 :                         g_monitor_perf_cores = true;
    2654                 :          0 :                         break;
    2655                 :         89 :                 case PERF_TRANSPORT:
    2656         [ -  + ]:         89 :                         if (add_trid(optarg)) {
    2657                 :          0 :                                 usage(argv[0]);
    2658                 :          0 :                                 return 1;
    2659                 :            :                         }
    2660                 :         89 :                         break;
    2661                 :        137 :                 case PERF_IO_PATTERN:
    2662                 :        137 :                         g_workload_type = optarg;
    2663                 :        137 :                         break;
    2664                 :          0 :                 case PERF_DISABLE_SQ_CMB:
    2665                 :          0 :                         g_disable_sq_cmb = 1;
    2666                 :          0 :                         break;
    2667                 :          0 :                 case PERF_ENABLE_DEBUG:
    2668                 :            : #ifndef DEBUG
    2669                 :            :                         fprintf(stderr, "%s must be configured with --enable-debug for -G flag\n",
    2670                 :            :                                 argv[0]);
    2671                 :            :                         usage(argv[0]);
    2672                 :            :                         return 1;
    2673                 :            : #else
    2674                 :          0 :                         spdk_log_set_flag("nvme");
    2675                 :          0 :                         spdk_log_set_print_level(SPDK_LOG_DEBUG);
    2676                 :          0 :                         break;
    2677                 :            : #endif
    2678                 :          4 :                 case PERF_ENABLE_TCP_HDGST:
    2679                 :          4 :                         g_header_digest = 1;
    2680                 :          4 :                         break;
    2681                 :          4 :                 case PERF_ENABLE_TCP_DDGST:
    2682                 :          4 :                         g_data_digest = 1;
    2683                 :          4 :                         break;
    2684                 :         26 :                 case PERF_ENABLE_SW_LATENCY_TRACING:
    2685                 :         26 :                         g_latency_sw_tracking_level++;
    2686                 :         26 :                         break;
    2687                 :          6 :                 case PERF_NO_SHST_NOTIFICATION:
    2688                 :          6 :                         g_no_shn_notification = true;
    2689                 :          6 :                         break;
    2690                 :          0 :                 case PERF_ENABLE_URING:
    2691                 :            : #ifndef SPDK_CONFIG_URING
    2692         [ #  # ]:          0 :                         fprintf(stderr, "%s must be rebuilt with CONFIG_URING=y for -R flag.\n",
    2693                 :            :                                 argv[0]);
    2694                 :          0 :                         usage(argv[0]);
    2695                 :          0 :                         return 0;
    2696                 :            : #endif
    2697                 :          0 :                         g_use_uring = true;
    2698                 :          0 :                         break;
    2699                 :          0 :                 case PERF_LOG_FLAG:
    2700                 :          0 :                         rc = spdk_log_set_flag(optarg);
    2701         [ #  # ]:          0 :                         if (rc < 0) {
    2702         [ #  # ]:          0 :                                 fprintf(stderr, "unknown flag\n");
    2703                 :          0 :                                 usage(argv[0]);
    2704                 :          0 :                                 exit(EXIT_FAILURE);
    2705                 :            :                         }
    2706                 :            : #ifdef DEBUG
    2707                 :          0 :                         spdk_log_set_print_level(SPDK_LOG_DEBUG);
    2708                 :            : #endif
    2709                 :          0 :                         break;
    2710                 :          1 :                 case PERF_ENABLE_VMD:
    2711                 :          1 :                         g_vmd = true;
    2712                 :          1 :                         break;
    2713                 :          0 :                 case PERF_DISABLE_KTLS:
    2714                 :          0 :                         ssl_used = true;
    2715                 :          0 :                         perf_set_sock_opts("ssl", "ktls", 0, NULL);
    2716                 :          0 :                         break;
    2717                 :          0 :                 case PERF_ENABLE_KTLS:
    2718                 :          0 :                         ssl_used = true;
    2719                 :          0 :                         perf_set_sock_opts("ssl", "ktls", 1, NULL);
    2720                 :          0 :                         break;
    2721                 :          0 :                 case PERF_TLS_VERSION:
    2722                 :          0 :                         ssl_used = true;
    2723                 :          0 :                         val = spdk_strtol(optarg, 10);
    2724         [ #  # ]:          0 :                         if (val < 0) {
    2725         [ #  # ]:          0 :                                 fprintf(stderr, "Illegal tls version value %s\n", optarg);
    2726                 :          0 :                                 return val;
    2727                 :            :                         }
    2728                 :          0 :                         perf_set_sock_opts("ssl", "tls_version", val, NULL);
    2729                 :          0 :                         break;
    2730                 :          3 :                 case PERF_PSK_PATH:
    2731                 :          3 :                         ssl_used = true;
    2732                 :          3 :                         perf_set_sock_opts("ssl", "psk_path", 0, optarg);
    2733                 :          3 :                         break;
    2734                 :          0 :                 case PERF_PSK_IDENTITY:
    2735                 :          0 :                         ssl_used = true;
    2736                 :          0 :                         perf_set_sock_opts("ssl", "psk_identity", 0, optarg);
    2737                 :          0 :                         break;
    2738                 :          0 :                 case PERF_DISABLE_ZCOPY:
    2739                 :          0 :                         perf_set_sock_opts(optarg, "enable_zerocopy_send_client", 0, NULL);
    2740                 :          0 :                         break;
    2741                 :          0 :                 case PERF_ENABLE_ZCOPY:
    2742                 :          0 :                         perf_set_sock_opts(optarg, "enable_zerocopy_send_client", 1, NULL);
    2743                 :          0 :                         break;
    2744                 :          0 :                 case PERF_USE_EVERY_CORE:
    2745                 :          0 :                         g_use_every_core = true;
    2746                 :          0 :                         break;
    2747                 :          3 :                 case PERF_DEFAULT_SOCK_IMPL:
    2748                 :          3 :                         sock_impl = optarg;
    2749                 :          3 :                         rc = spdk_sock_set_default_impl(optarg);
    2750         [ -  + ]:          3 :                         if (rc) {
    2751         [ #  # ]:          0 :                                 fprintf(stderr, "Failed to set sock impl %s, err %d (%s)\n", optarg, errno, strerror(errno));
    2752                 :          0 :                                 return 1;
    2753                 :            :                         }
    2754                 :          3 :                         break;
    2755                 :          4 :                 case PERF_TRANSPORT_STATISTICS:
    2756                 :          4 :                         g_dump_transport_stats = true;
    2757                 :          4 :                         break;
    2758                 :          0 :                 case PERF_IOVA_MODE:
    2759                 :          0 :                         env_opts->iova_mode = optarg;
    2760                 :          0 :                         break;
    2761                 :          0 :                 case PERF_SOCK_IMPL:
    2762                 :          0 :                         g_sock_threshold_impl = optarg;
    2763                 :          0 :                         break;
    2764                 :          0 :                 case PERF_TRANSPORT_TOS:
    2765                 :          0 :                         val = spdk_strtol(optarg, 10);
    2766         [ #  # ]:          0 :                         if (val < 0) {
    2767         [ #  # ]:          0 :                                 fprintf(stderr, "Invalid TOS value\n");
    2768                 :          0 :                                 return 1;
    2769                 :            :                         }
    2770                 :          0 :                         g_transport_tos = val;
    2771                 :          0 :                         break;
    2772                 :          0 :                 case PERF_NO_HUGE:
    2773                 :          0 :                         env_opts->no_huge = true;
    2774                 :          0 :                         break;
    2775                 :          0 :                 case PERF_HELP:
    2776                 :          0 :                         usage(argv[0]);
    2777                 :          0 :                         return HELP_RETURN_CODE;
    2778                 :          0 :                 default:
    2779                 :          0 :                         usage(argv[0]);
    2780                 :          0 :                         return 1;
    2781                 :            :                 }
    2782                 :            :         }
    2783                 :            : 
    2784         [ -  + ]:        137 :         if (!g_nr_io_queues_per_ns) {
    2785                 :          0 :                 usage(argv[0]);
    2786                 :          0 :                 return 1;
    2787                 :            :         }
    2788                 :            : 
    2789         [ -  + ]:        137 :         if (!g_queue_depth) {
    2790         [ #  # ]:          0 :                 fprintf(stderr, "missing -q (--io-depth) operand\n");
    2791                 :          0 :                 usage(argv[0]);
    2792                 :          0 :                 return 1;
    2793                 :            :         }
    2794         [ -  + ]:        137 :         if (!g_io_size_bytes) {
    2795         [ #  # ]:          0 :                 fprintf(stderr, "missing -o (--io-size) operand\n");
    2796                 :          0 :                 usage(argv[0]);
    2797                 :          0 :                 return 1;
    2798                 :            :         }
    2799   [ +  -  -  + ]:        137 :         if (!g_io_unit_size || g_io_unit_size % 4) {
    2800         [ #  # ]:          0 :                 fprintf(stderr, "io unit size can not be 0 or non 4-byte aligned\n");
    2801                 :          0 :                 return 1;
    2802                 :            :         }
    2803         [ -  + ]:        137 :         if (!g_workload_type) {
    2804         [ #  # ]:          0 :                 fprintf(stderr, "missing -w (--io-pattern) operand\n");
    2805                 :          0 :                 usage(argv[0]);
    2806                 :          0 :                 return 1;
    2807                 :            :         }
    2808         [ -  + ]:        137 :         if (!g_time_in_sec) {
    2809         [ #  # ]:          0 :                 fprintf(stderr, "missing -t (--time) operand\n");
    2810                 :          0 :                 usage(argv[0]);
    2811                 :          0 :                 return 1;
    2812                 :            :         }
    2813         [ -  + ]:        137 :         if (!g_quiet_count) {
    2814         [ #  # ]:          0 :                 fprintf(stderr, "-Q (--continue-on-error) value must be greater than 0\n");
    2815                 :          0 :                 usage(argv[0]);
    2816                 :          0 :                 return 1;
    2817                 :            :         }
    2818                 :            : 
    2819   [ -  +  +  + ]:        137 :         if (strncmp(g_workload_type, "rand", 4) == 0) {
    2820                 :         83 :                 g_is_random = 1;
    2821                 :         83 :                 g_workload_type = &g_workload_type[4];
    2822                 :            :         }
    2823                 :            : 
    2824   [ +  +  -  +  :        137 :         if (ssl_used && strncmp(sock_impl, "ssl", 3) != 0) {
                   -  + ]
    2825         [ #  # ]:          0 :                 fprintf(stderr, "sock impl is not SSL but tried to use one of the SSL only options\n");
    2826                 :          0 :                 usage(argv[0]);
    2827                 :          0 :                 return 1;
    2828                 :            :         }
    2829                 :            : 
    2830                 :            : 
    2831   [ +  +  +  +  :        137 :         if (strcmp(g_workload_type, "read") == 0 || strcmp(g_workload_type, "write") == 0) {
             -  +  +  + ]
    2832   [ +  +  +  + ]:         75 :                 g_rw_percentage = strcmp(g_workload_type, "read") == 0 ? 100 : 0;
    2833   [ -  +  -  + ]:         75 :                 if (g_mix_specified) {
    2834         [ #  # ]:          0 :                         fprintf(stderr, "Ignoring -M (--rwmixread) option... Please use -M option"
    2835                 :            :                                 " only when using rw or randrw.\n");
    2836                 :            :                 }
    2837   [ -  +  +  - ]:         62 :         } else if (strcmp(g_workload_type, "rw") == 0) {
    2838   [ +  -  -  + ]:         62 :                 if (g_rw_percentage < 0 || g_rw_percentage > 100) {
    2839         [ #  # ]:          0 :                         fprintf(stderr,
    2840                 :            :                                 "-M (--rwmixread) must be specified to value from 0 to 100 "
    2841                 :            :                                 "for rw or randrw.\n");
    2842                 :          0 :                         return 1;
    2843                 :            :                 }
    2844                 :            :         } else {
    2845         [ #  # ]:          0 :                 fprintf(stderr,
    2846                 :            :                         "-w (--io-pattern) io pattern type must be one of\n"
    2847                 :            :                         "(read, write, randread, randwrite, rw, randrw)\n");
    2848                 :          0 :                 return 1;
    2849                 :            :         }
    2850                 :            : 
    2851         [ -  + ]:        137 :         if (g_sock_zcopy_threshold > 0) {
    2852         [ #  # ]:          0 :                 if (!g_sock_threshold_impl) {
    2853         [ #  # ]:          0 :                         fprintf(stderr,
    2854                 :            :                                 "--zerocopy-threshold must be set with sock implementation specified(--zerocopy-threshold-sock-impl <impl>)\n");
    2855                 :          0 :                         return 1;
    2856                 :            :                 }
    2857                 :            : 
    2858                 :          0 :                 perf_set_sock_opts(g_sock_threshold_impl, "zerocopy_threshold", g_sock_zcopy_threshold, NULL);
    2859                 :            :         }
    2860                 :            : 
    2861   [ -  +  -  - ]:        137 :         if (g_number_ios && g_warmup_time_in_sec) {
    2862         [ #  # ]:          0 :                 fprintf(stderr, "-d (--number-ios) with -a (--warmup-time) is not supported\n");
    2863                 :          0 :                 return 1;
    2864                 :            :         }
    2865                 :            : 
    2866   [ -  +  -  - ]:        137 :         if (g_number_ios && g_number_ios < g_queue_depth) {
    2867         [ #  # ]:          0 :                 fprintf(stderr, "-d (--number-ios) less than -q (--io-depth) is not supported\n");
    2868                 :          0 :                 return 1;
    2869                 :            :         }
    2870                 :            : 
    2871         [ -  + ]:        137 :         if (g_rdma_srq_size != 0) {
    2872                 :          0 :                 struct spdk_nvme_transport_opts opts;
    2873                 :            : 
    2874                 :          0 :                 spdk_nvme_transport_get_opts(&opts, sizeof(opts));
    2875                 :          0 :                 opts.rdma_srq_size = g_rdma_srq_size;
    2876                 :            : 
    2877                 :          0 :                 rc = spdk_nvme_transport_set_opts(&opts, sizeof(opts));
    2878         [ #  # ]:          0 :                 if (rc != 0) {
    2879         [ #  # ]:          0 :                         fprintf(stderr, "Failed to set NVMe transport options.\n");
    2880                 :          0 :                         return 1;
    2881                 :            :                 }
    2882                 :            :         }
    2883                 :            : 
    2884         [ +  + ]:        137 :         if (TAILQ_EMPTY(&g_trid_list)) {
    2885                 :            :                 /* If no transport IDs specified, default to enumerating all local PCIe devices */
    2886                 :         48 :                 add_trid("trtype:PCIe");
    2887                 :            :         } else {
    2888                 :            :                 struct trid_entry *trid_entry, *trid_entry_tmp;
    2889                 :            : 
    2890                 :         89 :                 env_opts->no_pci = true;
    2891                 :            :                 /* check whether there is local PCIe type */
    2892         [ +  + ]:        173 :                 TAILQ_FOREACH_SAFE(trid_entry, &g_trid_list, tailq, trid_entry_tmp) {
    2893         [ +  + ]:         89 :                         if (trid_entry->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
    2894                 :          5 :                                 env_opts->no_pci = false;
    2895                 :          5 :                                 break;
    2896                 :            :                         }
    2897                 :            :                 }
    2898                 :            :         }
    2899                 :            : 
    2900                 :        137 :         g_file_optind = optind;
    2901                 :            : 
    2902                 :        137 :         return 0;
    2903                 :            : }
    2904                 :            : 
    2905                 :            : static int
    2906                 :        137 : register_workers(void)
    2907                 :            : {
    2908                 :            :         uint32_t i;
    2909                 :            :         struct worker_thread *worker;
    2910                 :            : 
    2911         [ +  + ]:        304 :         SPDK_ENV_FOREACH_CORE(i) {
    2912                 :        167 :                 worker = calloc(1, sizeof(*worker));
    2913         [ -  + ]:        167 :                 if (worker == NULL) {
    2914   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to allocate worker\n");
    2915                 :          0 :                         return -1;
    2916                 :            :                 }
    2917                 :            : 
    2918                 :        167 :                 TAILQ_INIT(&worker->ns_ctx);
    2919                 :        167 :                 worker->lcore = i;
    2920                 :        167 :                 TAILQ_INSERT_TAIL(&g_workers, worker, link);
    2921                 :        167 :                 g_num_workers++;
    2922                 :            :         }
    2923                 :            : 
    2924                 :        137 :         return 0;
    2925                 :            : }
    2926                 :            : 
    2927                 :            : static void
    2928                 :        137 : unregister_workers(void)
    2929                 :            : {
    2930                 :            :         struct worker_thread *worker, *tmp_worker;
    2931                 :            :         struct ns_worker_ctx *ns_ctx, *tmp_ns_ctx;
    2932                 :            : 
    2933                 :            :         /* Free namespace context and worker thread */
    2934         [ +  + ]:        304 :         TAILQ_FOREACH_SAFE(worker, &g_workers, link, tmp_worker) {
    2935         [ +  + ]:        167 :                 TAILQ_REMOVE(&g_workers, worker, link);
    2936                 :            : 
    2937         [ +  + ]:        379 :                 TAILQ_FOREACH_SAFE(ns_ctx, &worker->ns_ctx, link, tmp_ns_ctx) {
    2938         [ +  + ]:        212 :                         TAILQ_REMOVE(&worker->ns_ctx, ns_ctx, link);
    2939                 :        212 :                         spdk_histogram_data_free(ns_ctx->histogram);
    2940                 :        212 :                         free(ns_ctx);
    2941                 :            :                 }
    2942                 :            : 
    2943                 :        167 :                 free(worker);
    2944                 :            :         }
    2945                 :        137 : }
    2946                 :            : 
    2947                 :            : static bool
    2948                 :         85 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
    2949                 :            :          struct spdk_nvme_ctrlr_opts *opts)
    2950                 :            : {
    2951                 :         85 :         struct trid_entry *trid_entry = cb_ctx;
    2952                 :            : 
    2953         [ +  + ]:         85 :         if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
    2954         [ -  + ]:          1 :                 if (g_disable_sq_cmb) {
    2955                 :          0 :                         opts->use_cmb_sqs = false;
    2956                 :            :                 }
    2957   [ -  +  -  + ]:          1 :                 if (g_no_shn_notification) {
    2958                 :          0 :                         opts->no_shn_notification = true;
    2959                 :            :                 }
    2960                 :            :         }
    2961                 :            : 
    2962         [ -  + ]:         85 :         if (trid->trtype != trid_entry->trid.trtype &&
    2963   [ #  #  #  #  :          0 :             strcasecmp(trid->trstring, trid_entry->trid.trstring)) {
                   #  # ]
    2964                 :          0 :                 return false;
    2965                 :            :         }
    2966                 :            : 
    2967                 :         85 :         opts->io_queue_size = g_io_queue_size;
    2968                 :            : 
    2969                 :            :         /* Set the header and data_digest */
    2970         [ -  + ]:         85 :         opts->header_digest = g_header_digest;
    2971         [ -  + ]:         85 :         opts->data_digest = g_data_digest;
    2972                 :         85 :         opts->keep_alive_timeout_ms = g_keep_alive_timeout_in_ms;
    2973   [ -  +  -  + ]:         85 :         memcpy(opts->hostnqn, trid_entry->hostnqn, sizeof(opts->hostnqn));
    2974                 :            : 
    2975                 :         85 :         opts->transport_tos = g_transport_tos;
    2976         [ -  + ]:         85 :         if (opts->num_io_queues < g_num_workers * g_nr_io_queues_per_ns) {
    2977                 :          0 :                 opts->num_io_queues = g_num_workers * g_nr_io_queues_per_ns;
    2978                 :            :         }
    2979                 :            : 
    2980         [ +  + ]:         85 :         if (g_psk != NULL) {
    2981   [ -  +  -  +  :          3 :                 memcpy(opts->psk, g_psk, strlen(g_psk));
                   -  + ]
    2982                 :            :         }
    2983                 :            : 
    2984                 :         85 :         return true;
    2985                 :            : }
    2986                 :            : 
    2987                 :            : static void
    2988                 :        169 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
    2989                 :            :           struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
    2990                 :            : {
    2991                 :        169 :         struct trid_entry       *trid_entry = cb_ctx;
    2992                 :         49 :         struct spdk_pci_addr    pci_addr;
    2993                 :            :         struct spdk_pci_device  *pci_dev;
    2994                 :            :         struct spdk_pci_id      pci_id;
    2995                 :            : 
    2996         [ +  + ]:        169 :         if (trid->trtype != SPDK_NVME_TRANSPORT_PCIE) {
    2997                 :         84 :                 printf("Attached to NVMe over Fabrics controller at %s:%s: %s\n",
    2998         [ -  + ]:         84 :                        trid->traddr, trid->trsvcid,
    2999                 :         84 :                        trid->subnqn);
    3000                 :            :         } else {
    3001         [ -  + ]:         85 :                 if (spdk_pci_addr_parse(&pci_addr, trid->traddr)) {
    3002                 :          0 :                         return;
    3003                 :            :                 }
    3004                 :            : 
    3005                 :         85 :                 pci_dev = spdk_nvme_ctrlr_get_pci_device(ctrlr);
    3006         [ -  + ]:         85 :                 if (!pci_dev) {
    3007                 :          0 :                         return;
    3008                 :            :                 }
    3009                 :            : 
    3010                 :         85 :                 pci_id = spdk_pci_device_get_id(pci_dev);
    3011                 :            : 
    3012                 :         85 :                 printf("Attached to NVMe Controller at %s [%04x:%04x]\n",
    3013         [ -  + ]:         85 :                        trid->traddr,
    3014                 :         85 :                        pci_id.vendor_id, pci_id.device_id);
    3015                 :            :         }
    3016                 :            : 
    3017                 :        169 :         register_ctrlr(ctrlr, trid_entry);
    3018                 :            : }
    3019                 :            : 
    3020                 :            : static int
    3021                 :        137 : register_controllers(void)
    3022                 :            : {
    3023                 :            :         struct trid_entry *trid_entry;
    3024                 :            : 
    3025         [ -  + ]:        137 :         printf("Initializing NVMe Controllers\n");
    3026                 :            : 
    3027   [ -  +  +  +  :        137 :         if (g_vmd && spdk_vmd_init()) {
                   -  + ]
    3028   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to initialize VMD."
    3029                 :            :                         " Some NVMe devices can be unavailable.\n");
    3030                 :            :         }
    3031                 :            : 
    3032         [ +  + ]:        274 :         TAILQ_FOREACH(trid_entry, &g_trid_list, tailq) {
    3033         [ -  + ]:        137 :                 if (spdk_nvme_probe(&trid_entry->trid, trid_entry, probe_cb, attach_cb, NULL) != 0) {
    3034         [ #  # ]:          0 :                         fprintf(stderr, "spdk_nvme_probe() failed for transport address '%s'\n",
    3035         [ #  # ]:          0 :                                 trid_entry->trid.traddr);
    3036                 :          0 :                         return -1;
    3037                 :            :                 }
    3038                 :            :         }
    3039                 :            : 
    3040                 :        137 :         return 0;
    3041                 :            : }
    3042                 :            : 
    3043                 :            : static void
    3044                 :        137 : unregister_controllers(void)
    3045                 :            : {
    3046                 :            :         struct ctrlr_entry *entry, *tmp;
    3047                 :        137 :         struct spdk_nvme_detach_ctx *detach_ctx = NULL;
    3048                 :            : 
    3049         [ +  + ]:        306 :         TAILQ_FOREACH_SAFE(entry, &g_controllers, link, tmp) {
    3050         [ +  + ]:        169 :                 TAILQ_REMOVE(&g_controllers, entry, link);
    3051                 :            : 
    3052                 :        169 :                 spdk_dma_free(entry->latency_page);
    3053   [ -  +  -  +  :        169 :                 if (g_latency_ssd_tracking_enable &&
                   -  - ]
    3054                 :          0 :                     spdk_nvme_ctrlr_is_feature_supported(entry->ctrlr, SPDK_NVME_INTEL_FEAT_LATENCY_TRACKING)) {
    3055                 :          0 :                         set_latency_tracking_feature(entry->ctrlr, false);
    3056                 :            :                 }
    3057                 :            : 
    3058         [ -  + ]:        169 :                 if (g_nr_unused_io_queues) {
    3059                 :            :                         int i;
    3060                 :            : 
    3061         [ #  # ]:          0 :                         for (i = 0; i < g_nr_unused_io_queues; i++) {
    3062                 :          0 :                                 spdk_nvme_ctrlr_free_io_qpair(entry->unused_qpairs[i]);
    3063                 :            :                         }
    3064                 :            : 
    3065                 :          0 :                         free(entry->unused_qpairs);
    3066                 :            :                 }
    3067                 :            : 
    3068                 :        169 :                 spdk_nvme_detach_async(entry->ctrlr, &detach_ctx);
    3069                 :        169 :                 free(entry);
    3070                 :            :         }
    3071                 :            : 
    3072         [ +  + ]:        137 :         if (detach_ctx) {
    3073                 :         85 :                 spdk_nvme_detach_poll(detach_ctx);
    3074                 :            :         }
    3075                 :            : 
    3076   [ -  +  +  + ]:        137 :         if (g_vmd) {
    3077                 :          1 :                 spdk_vmd_fini();
    3078                 :            :         }
    3079                 :        137 : }
    3080                 :            : 
    3081                 :            : static int
    3082                 :        212 : allocate_ns_worker(struct ns_entry *entry, struct worker_thread *worker)
    3083                 :            : {
    3084                 :            :         struct ns_worker_ctx    *ns_ctx;
    3085                 :            : 
    3086                 :        212 :         ns_ctx = calloc(1, sizeof(struct ns_worker_ctx));
    3087         [ -  + ]:        212 :         if (!ns_ctx) {
    3088                 :          0 :                 return -1;
    3089                 :            :         }
    3090                 :            : 
    3091         [ -  + ]:        212 :         printf("Associating %s with lcore %d\n", entry->name, worker->lcore);
    3092                 :        212 :         ns_ctx->stats.min_tsc = UINT64_MAX;
    3093                 :        212 :         ns_ctx->entry = entry;
    3094                 :        212 :         ns_ctx->histogram = spdk_histogram_data_alloc();
    3095                 :        212 :         TAILQ_INSERT_TAIL(&worker->ns_ctx, ns_ctx, link);
    3096                 :            : 
    3097                 :        212 :         return 0;
    3098                 :            : }
    3099                 :            : 
    3100                 :            : static int
    3101                 :        127 : associate_workers_with_ns(void)
    3102                 :            : {
    3103                 :        127 :         struct ns_entry         *entry = TAILQ_FIRST(&g_namespaces);
    3104                 :        127 :         struct worker_thread    *worker = TAILQ_FIRST(&g_workers);
    3105                 :            :         int                     i, count;
    3106                 :            : 
    3107                 :            :         /* Each core contains single worker, and namespaces are associated as follows:
    3108                 :            :          * --use-every-core not specified (default):
    3109                 :            :          * 2) equal workers and namespaces - each worker associated with single namespace
    3110                 :            :          * 3) more workers than namespaces - each namespace is associated with one or more workers
    3111                 :            :          * 4) more namespaces than workers - each worker is associated with one or more namespaces
    3112                 :            :          * --use-every-core option enabled - every worker is associated with all namespaces
    3113                 :            :          */
    3114   [ -  +  -  + ]:        127 :         if (g_use_every_core) {
    3115         [ #  # ]:          0 :                 TAILQ_FOREACH(worker, &g_workers, link) {
    3116         [ #  # ]:          0 :                         TAILQ_FOREACH(entry, &g_namespaces, link) {
    3117         [ #  # ]:          0 :                                 if (allocate_ns_worker(entry, worker) != 0) {
    3118                 :          0 :                                         return -1;
    3119                 :            :                                 }
    3120                 :            :                         }
    3121                 :            :                 }
    3122                 :          0 :                 return 0;
    3123                 :            :         }
    3124                 :            : 
    3125                 :        127 :         count = g_num_namespaces > g_num_workers ? g_num_namespaces : g_num_workers;
    3126                 :            : 
    3127         [ +  + ]:        339 :         for (i = 0; i < count; i++) {
    3128         [ -  + ]:        212 :                 if (entry == NULL) {
    3129                 :          0 :                         break;
    3130                 :            :                 }
    3131                 :            : 
    3132         [ -  + ]:        212 :                 if (allocate_ns_worker(entry, worker) != 0) {
    3133                 :          0 :                         return -1;
    3134                 :            :                 }
    3135                 :            : 
    3136                 :        212 :                 worker = TAILQ_NEXT(worker, link);
    3137         [ +  + ]:        212 :                 if (worker == NULL) {
    3138                 :        194 :                         worker = TAILQ_FIRST(&g_workers);
    3139                 :            :                 }
    3140                 :            : 
    3141                 :        212 :                 entry = TAILQ_NEXT(entry, link);
    3142         [ +  + ]:        212 :                 if (entry == NULL) {
    3143                 :        145 :                         entry = TAILQ_FIRST(&g_namespaces);
    3144                 :            :                 }
    3145                 :            : 
    3146                 :            :         }
    3147                 :            : 
    3148                 :        127 :         return 0;
    3149                 :            : }
    3150                 :            : 
    3151                 :            : static void *
    3152                 :        127 : nvme_poll_ctrlrs(void *arg)
    3153                 :            : {
    3154                 :            :         struct ctrlr_entry *entry;
    3155                 :         25 :         int oldstate;
    3156                 :            :         int rc;
    3157                 :            : 
    3158                 :        127 :         spdk_unaffinitize_thread();
    3159                 :            : 
    3160                 :            :         while (true) {
    3161                 :        806 :                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
    3162                 :            : 
    3163         [ +  + ]:       1735 :                 TAILQ_FOREACH(entry, &g_controllers, link) {
    3164         [ +  + ]:        929 :                         if (entry->trtype != SPDK_NVME_TRANSPORT_PCIE) {
    3165                 :        621 :                                 rc = spdk_nvme_ctrlr_process_admin_completions(entry->ctrlr);
    3166   [ -  +  -  -  :        621 :                                 if (spdk_unlikely(rc < 0 && !g_exit)) {
                   -  - ]
    3167                 :          0 :                                         g_exit = true;
    3168                 :            :                                 }
    3169                 :            :                         }
    3170                 :            :                 }
    3171                 :            : 
    3172                 :        806 :                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
    3173                 :            : 
    3174                 :            :                 /* This is a pthread cancellation point and cannot be removed. */
    3175                 :        806 :                 sleep(1);
    3176                 :            :         }
    3177                 :            : 
    3178                 :            :         return NULL;
    3179                 :            : }
    3180                 :            : 
    3181                 :            : static void
    3182                 :          0 : sig_handler(int signo)
    3183                 :            : {
    3184                 :          0 :         g_exit = true;
    3185                 :          0 : }
    3186                 :            : 
    3187                 :            : static int
    3188                 :        137 : setup_sig_handlers(void)
    3189                 :            : {
    3190                 :        137 :         struct sigaction sigact = {};
    3191                 :            :         int rc;
    3192                 :            : 
    3193                 :        137 :         sigemptyset(&sigact.sa_mask);
    3194                 :        137 :         sigact.sa_handler = sig_handler;
    3195                 :        137 :         rc = sigaction(SIGINT, &sigact, NULL);
    3196         [ -  + ]:        137 :         if (rc < 0) {
    3197         [ #  # ]:          0 :                 fprintf(stderr, "sigaction(SIGINT) failed, errno %d (%s)\n", errno, strerror(errno));
    3198                 :          0 :                 return -1;
    3199                 :            :         }
    3200                 :            : 
    3201                 :        137 :         rc = sigaction(SIGTERM, &sigact, NULL);
    3202         [ -  + ]:        137 :         if (rc < 0) {
    3203         [ #  # ]:          0 :                 fprintf(stderr, "sigaction(SIGTERM) failed, errno %d (%s)\n", errno, strerror(errno));
    3204                 :          0 :                 return -1;
    3205                 :            :         }
    3206                 :            : 
    3207                 :        137 :         return 0;
    3208                 :            : }
    3209                 :            : 
    3210                 :            : int
    3211                 :        137 : main(int argc, char **argv)
    3212                 :            : {
    3213                 :            :         int rc;
    3214                 :            :         struct worker_thread *worker, *main_worker;
    3215                 :            :         struct ns_worker_ctx *ns_ctx;
    3216                 :         25 :         struct spdk_env_opts opts;
    3217                 :        137 :         pthread_t thread_id = 0;
    3218                 :            : 
    3219                 :            :         /* Use the runtime PID to set the random seed */
    3220                 :        137 :         srand(getpid());
    3221                 :            : 
    3222                 :        137 :         opts.opts_size = sizeof(opts);
    3223                 :        137 :         spdk_env_opts_init(&opts);
    3224                 :        137 :         opts.name = "perf";
    3225                 :        137 :         opts.pci_allowed = g_allowed_pci_addr;
    3226                 :        137 :         rc = parse_args(argc, argv, &opts);
    3227   [ +  -  -  + ]:        137 :         if (rc != 0 || rc == HELP_RETURN_CODE) {
    3228                 :          0 :                 free(g_psk);
    3229         [ #  # ]:          0 :                 if (rc == HELP_RETURN_CODE) {
    3230                 :          0 :                         return 0;
    3231                 :            :                 }
    3232                 :            : 
    3233                 :          0 :                 return rc;
    3234                 :            :         }
    3235                 :            :         /* Transport statistics are printed from each thread.
    3236                 :            :          * To avoid mess in terminal, init and use mutex */
    3237         [ -  + ]:        137 :         rc = pthread_mutex_init(&g_stats_mutex, NULL);
    3238         [ -  + ]:        137 :         if (rc != 0) {
    3239   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to init mutex\n");
    3240                 :          0 :                 free(g_psk);
    3241                 :          0 :                 return -1;
    3242                 :            :         }
    3243         [ -  + ]:        137 :         if (spdk_env_init(&opts) < 0) {
    3244   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to initialize SPDK env\n");
    3245                 :          0 :                 unregister_trids();
    3246         [ #  # ]:          0 :                 pthread_mutex_destroy(&g_stats_mutex);
    3247                 :          0 :                 free(g_psk);
    3248                 :          0 :                 return -1;
    3249                 :            :         }
    3250                 :            : 
    3251                 :        137 :         rc = setup_sig_handlers();
    3252         [ -  + ]:        137 :         if (rc != 0) {
    3253                 :          0 :                 rc = -1;
    3254                 :          0 :                 goto cleanup;
    3255                 :            :         }
    3256                 :            : 
    3257                 :        137 :         g_tsc_rate = spdk_get_ticks_hz();
    3258                 :            : 
    3259         [ -  + ]:        137 :         if (register_workers() != 0) {
    3260                 :          0 :                 rc = -1;
    3261                 :          0 :                 goto cleanup;
    3262                 :            :         }
    3263                 :            : 
    3264                 :            : #if defined(HAVE_LIBAIO) || defined(SPDK_CONFIG_URING)
    3265         [ -  + ]:        137 :         if (register_files(argc, argv) != 0) {
    3266                 :          0 :                 rc = -1;
    3267                 :          0 :                 goto cleanup;
    3268                 :            :         }
    3269                 :            : #endif
    3270                 :            : 
    3271         [ -  + ]:        137 :         if (register_controllers() != 0) {
    3272                 :          0 :                 rc = -1;
    3273                 :          0 :                 goto cleanup;
    3274                 :            :         }
    3275                 :            : 
    3276   [ -  +  +  + ]:        137 :         if (g_warn) {
    3277         [ -  + ]:         10 :                 printf("WARNING: Some requested NVMe devices were skipped\n");
    3278                 :            :         }
    3279                 :            : 
    3280         [ +  + ]:        137 :         if (g_num_namespaces == 0) {
    3281   [ -  +  -  + ]:         10 :                 fprintf(stderr, "No valid NVMe controllers or AIO or URING devices found\n");
    3282                 :         10 :                 goto cleanup;
    3283                 :            :         }
    3284                 :            : 
    3285   [ +  +  -  + ]:        127 :         if (g_num_workers > 1 && g_quiet_count > 1) {
    3286   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Error message rate-limiting enabled across multiple threads.\n");
    3287   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Error suppression count may not be exact.\n");
    3288                 :            :         }
    3289                 :            : 
    3290   [ -  +  -  + ]:        127 :         rc = pthread_create(&thread_id, NULL, &nvme_poll_ctrlrs, NULL);
    3291         [ -  + ]:        127 :         if (rc != 0) {
    3292   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to spawn a thread to poll admin queues.\n");
    3293                 :          0 :                 goto cleanup;
    3294                 :            :         }
    3295                 :            : 
    3296         [ -  + ]:        127 :         if (associate_workers_with_ns() != 0) {
    3297                 :          0 :                 rc = -1;
    3298                 :          0 :                 goto cleanup;
    3299                 :            :         }
    3300                 :            : 
    3301         [ -  + ]:        127 :         rc = pthread_barrier_init(&g_worker_sync_barrier, NULL, g_num_workers);
    3302         [ -  + ]:        127 :         if (rc != 0) {
    3303   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to initialize thread sync barrier\n");
    3304                 :          0 :                 goto cleanup;
    3305                 :            :         }
    3306                 :            : 
    3307         [ -  + ]:        127 :         printf("Initialization complete. Launching workers.\n");
    3308                 :            : 
    3309                 :            :         /* Launch all of the secondary workers */
    3310                 :        127 :         g_main_core = spdk_env_get_current_core();
    3311                 :        127 :         main_worker = NULL;
    3312         [ +  + ]:        272 :         TAILQ_FOREACH(worker, &g_workers, link) {
    3313         [ +  + ]:        145 :                 if (worker->lcore != g_main_core) {
    3314                 :         18 :                         spdk_env_thread_launch_pinned(worker->lcore, work_fn, worker);
    3315                 :            :                 } else {
    3316         [ -  + ]:        127 :                         assert(main_worker == NULL);
    3317                 :        127 :                         main_worker = worker;
    3318                 :            :                 }
    3319                 :            :         }
    3320                 :            : 
    3321         [ -  + ]:        127 :         assert(main_worker != NULL);
    3322                 :        127 :         work_fn(main_worker);
    3323                 :            : 
    3324                 :        127 :         spdk_env_thread_wait_all();
    3325                 :            : 
    3326                 :        127 :         print_stats();
    3327                 :            : 
    3328         [ -  + ]:        127 :         pthread_barrier_destroy(&g_worker_sync_barrier);
    3329                 :            : 
    3330                 :        137 : cleanup:
    3331                 :        137 :         fflush(stdout);
    3332                 :            : 
    3333   [ +  +  +  - ]:        137 :         if (thread_id && pthread_cancel(thread_id) == 0) {
    3334                 :        127 :                 pthread_join(thread_id, NULL);
    3335                 :            :         }
    3336                 :            : 
    3337                 :            :         /* Collect errors from all workers and namespaces */
    3338         [ +  + ]:        301 :         TAILQ_FOREACH(worker, &g_workers, link) {
    3339         [ +  + ]:        167 :                 if (rc != 0) {
    3340                 :          3 :                         break;
    3341                 :            :                 }
    3342                 :            : 
    3343         [ +  + ]:        370 :                 TAILQ_FOREACH(ns_ctx, &worker->ns_ctx, link) {
    3344         [ +  + ]:        209 :                         if (ns_ctx->status != 0) {
    3345                 :          3 :                                 rc = ns_ctx->status;
    3346                 :          3 :                                 break;
    3347                 :            :                         }
    3348                 :            :                 }
    3349                 :            :         }
    3350                 :            : 
    3351                 :        137 :         unregister_trids();
    3352                 :        137 :         unregister_namespaces();
    3353                 :        137 :         unregister_controllers();
    3354                 :        137 :         unregister_workers();
    3355                 :            : 
    3356                 :        137 :         spdk_env_fini();
    3357                 :            : 
    3358                 :        137 :         free(g_psk);
    3359                 :            : 
    3360         [ -  + ]:        137 :         pthread_mutex_destroy(&g_stats_mutex);
    3361                 :            : 
    3362         [ +  + ]:        137 :         if (rc != 0) {
    3363   [ -  +  -  + ]:          3 :                 fprintf(stderr, "%s: errors occurred\n", argv[0]);
    3364                 :            :         }
    3365                 :            : 
    3366                 :        137 :         return rc;
    3367                 :            : }

Generated by: LCOV version 1.14