LCOV - code coverage report
Current view: top level - spdk/test/dma/test_dma - test_dma.c (source / functions) Hit Total Coverage
Test: Combined Lines: 359 500 71.8 %
Date: 2024-07-15 23:08:32 Functions: 30 34 88.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 173 416 41.6 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "spdk/stdinc.h"
       6                 :            : 
       7                 :            : #include "spdk/dma.h"
       8                 :            : #include "spdk/bdev.h"
       9                 :            : #include "spdk/env.h"
      10                 :            : #include "spdk/event.h"
      11                 :            : #include "spdk/likely.h"
      12                 :            : #include "spdk/string.h"
      13                 :            : #include "spdk/util.h"
      14                 :            : 
      15                 :            : #include <infiniband/verbs.h>
      16                 :            : 
      17                 :            : struct dma_test_task;
      18                 :            : 
      19                 :            : struct dma_test_req {
      20                 :            :         struct iovec iov;
      21                 :            :         struct spdk_bdev_ext_io_opts io_opts;
      22                 :            :         uint64_t submit_tsc;
      23                 :            :         struct ibv_mr *mr;
      24                 :            :         struct dma_test_task *task;
      25                 :            : };
      26                 :            : 
      27                 :            : struct dma_test_task_stats {
      28                 :            :         uint64_t io_completed;
      29                 :            :         uint64_t total_tsc;
      30                 :            :         uint64_t min_tsc;
      31                 :            :         uint64_t max_tsc;
      32                 :            : };
      33                 :            : 
      34                 :            : struct dma_test_task {
      35                 :            :         struct spdk_bdev_desc *desc;
      36                 :            :         struct spdk_io_channel *channel;
      37                 :            :         uint64_t cur_io_offset;
      38                 :            :         uint64_t max_offset_in_ios;
      39                 :            :         uint64_t num_blocks_per_io;
      40                 :            :         int rw_percentage;
      41                 :            :         uint32_t seed;
      42                 :            :         uint32_t io_inflight;
      43                 :            :         struct dma_test_task_stats stats;
      44                 :            :         struct dma_test_task_stats last_stats;
      45                 :            :         bool is_draining;
      46                 :            :         bool is_random;
      47                 :            :         struct dma_test_req *reqs;
      48                 :            :         struct spdk_thread *thread;
      49                 :            :         const char *bdev_name;
      50                 :            :         uint64_t num_translations;
      51                 :            :         uint64_t num_pull_push;
      52                 :            :         uint64_t num_mem_zero;
      53                 :            :         uint32_t lcore;
      54                 :            : 
      55                 :            :         TAILQ_ENTRY(dma_test_task) link;
      56                 :            : };
      57                 :            : 
      58                 :            : struct dma_test_data_cpl_ctx {
      59                 :            :         spdk_memory_domain_data_cpl_cb data_cpl;
      60                 :            :         void *data_cpl_arg;
      61                 :            : };
      62                 :            : 
      63                 :            : enum dma_test_domain_ops {
      64                 :            :         DMA_TEST_DOMAIN_OP_TRANSLATE = 1u << 0,
      65                 :            :         DMA_TEST_DOMAIN_OP_PULL_PUSH = 1u << 1,
      66                 :            :         DMA_TEST_DOMAIN_OP_MEMZERO = 1u << 2,
      67                 :            : };
      68                 :            : 
      69                 :            : TAILQ_HEAD(, dma_test_task) g_tasks = TAILQ_HEAD_INITIALIZER(g_tasks);
      70                 :            : 
      71                 :            : /* User's input */
      72                 :            : static char *g_bdev_name;
      73                 :            : static const char *g_rw_mode_str;
      74                 :            : static int g_rw_percentage = -1;
      75                 :            : static uint32_t g_queue_depth;
      76                 :            : static uint32_t g_io_size;
      77                 :            : static uint32_t g_run_time_sec;
      78                 :            : static uint32_t g_run_count;
      79                 :            : static uint32_t g_test_ops;
      80                 :            : static bool g_is_random;
      81                 :            : static bool g_force_memory_domains_support;
      82                 :            : 
      83                 :            : static struct spdk_thread *g_main_thread;
      84                 :            : static struct spdk_poller *g_runtime_poller;
      85                 :            : static struct spdk_memory_domain *g_domain;
      86                 :            : static uint64_t g_num_blocks_per_io;
      87                 :            : static uint32_t g_num_construct_tasks;
      88                 :            : static uint32_t g_num_complete_tasks;
      89                 :            : static uint64_t g_start_tsc;
      90                 :            : static int g_run_rc;
      91                 :            : 
      92                 :            : static void destroy_tasks(void);
      93                 :            : static int dma_test_submit_io(struct dma_test_req *req);
      94                 :            : 
      95                 :            : static void
      96                 :          4 : print_total_stats(void)
      97                 :            : {
      98                 :            :         struct dma_test_task *task;
      99                 :          4 :         uint64_t tsc_rate = spdk_get_ticks_hz();
     100         [ -  + ]:          4 :         uint64_t test_time_usec = (spdk_get_ticks() - g_start_tsc) * SPDK_SEC_TO_USEC / tsc_rate;
     101                 :          4 :         uint64_t total_tsc = 0, total_io_completed = 0;
     102                 :            :         double task_iops, task_bw, task_min_lat, task_avg_lat, task_max_lat;
     103                 :          4 :         double total_iops = 0, total_bw = 0, total_min_lat = (double)UINT64_MAX, total_max_lat = 0,
     104                 :            :                total_avg_lat;
     105                 :            : 
     106         [ -  + ]:          4 :         printf("==========================================================================\n");
     107         [ -  + ]:          4 :         printf("%*s\n", 55, "Latency [us]");
     108         [ -  + ]:          4 :         printf("%*s %10s %10s %10s %10s\n", 19, "IOPS", "MiB/s", "Average", "min", "max");
     109                 :            : 
     110         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     111         [ -  + ]:          8 :                 if (!task->stats.io_completed) {
     112                 :          0 :                         continue;
     113                 :            :                 }
     114                 :          8 :                 task_iops = (double)task->stats.io_completed * SPDK_SEC_TO_USEC / test_time_usec;
     115                 :          8 :                 task_bw = task_iops * g_io_size / (1024 * 1024);
     116                 :          8 :                 task_avg_lat = (double)task->stats.total_tsc / task->stats.io_completed * SPDK_SEC_TO_USEC /
     117                 :            :                                tsc_rate;
     118                 :          8 :                 task_min_lat = (double)task->stats.min_tsc * SPDK_SEC_TO_USEC / tsc_rate;
     119                 :          8 :                 task_max_lat = (double)task->stats.max_tsc * SPDK_SEC_TO_USEC / tsc_rate;
     120                 :            : 
     121                 :          8 :                 total_iops += task_iops;
     122                 :          8 :                 total_bw += task_bw;
     123                 :          8 :                 total_io_completed += task->stats.io_completed;
     124                 :          8 :                 total_tsc += task->stats.total_tsc;
     125         [ +  + ]:          8 :                 if (task_min_lat < total_min_lat) {
     126                 :          6 :                         total_min_lat = task_min_lat;
     127                 :            :                 }
     128         [ +  + ]:          8 :                 if (task_max_lat > total_max_lat) {
     129                 :          6 :                         total_max_lat = task_max_lat;
     130                 :            :                 }
     131         [ -  + ]:          8 :                 printf("Core %2u: %10.2f %10.2f %10.2f %10.2f %10.2f\n",
     132                 :            :                        task->lcore, task_iops, task_bw, task_avg_lat, task_min_lat, task_max_lat);
     133                 :            :         }
     134                 :            : 
     135         [ +  - ]:          4 :         if (total_io_completed) {
     136                 :          4 :                 total_avg_lat = (double)total_tsc / total_io_completed  * SPDK_SEC_TO_USEC / tsc_rate;
     137         [ -  + ]:          4 :                 printf("==========================================================================\n");
     138         [ -  + ]:          4 :                 printf("%-*s %10.2f %10.2f %10.2f %10.2f %10.2f\n",
     139                 :            :                        8, "Total  :", total_iops, total_bw, total_avg_lat, total_min_lat, total_max_lat);
     140                 :          4 :                 printf("\n");
     141                 :            :         }
     142                 :          4 : }
     143                 :            : 
     144                 :            : static void
     145                 :          0 : print_periodic_stats(void)
     146                 :            : {
     147                 :            :         struct dma_test_task *task;
     148                 :          0 :         uint64_t io_last_sec = 0, tsc_last_sec = 0;
     149                 :            :         double lat_last_sec, bw_last_sec;
     150                 :            : 
     151         [ #  # ]:          0 :         TAILQ_FOREACH(task, &g_tasks, link) {
     152                 :          0 :                 io_last_sec += task->stats.io_completed - task->last_stats.io_completed;
     153                 :          0 :                 tsc_last_sec += task->stats.total_tsc - task->last_stats.total_tsc;
     154   [ #  #  #  # ]:          0 :                 memcpy(&task->last_stats, &task->stats, sizeof(task->stats));
     155                 :            :         }
     156                 :            : 
     157         [ #  # ]:          0 :         printf("Running %3u/%-3u sec", g_run_count, g_run_time_sec);
     158         [ #  # ]:          0 :         if (io_last_sec) {
     159                 :          0 :                 lat_last_sec =  (double)tsc_last_sec / io_last_sec * SPDK_SEC_TO_USEC / spdk_get_ticks_hz();
     160                 :          0 :                 bw_last_sec = (double)io_last_sec * g_io_size / (1024 * 1024);
     161         [ #  # ]:          0 :                 printf(" IOPS: %-8"PRIu64" BW: %-6.2f [MiB/s] avg.lat %-5.2f [us]",
     162                 :            :                        io_last_sec, bw_last_sec, lat_last_sec);
     163                 :            :         }
     164                 :            : 
     165                 :          0 :         printf("\r");
     166                 :          0 :         fflush(stdout);
     167                 :          0 : }
     168                 :            : 
     169                 :            : static void
     170                 :          8 : dma_test_task_complete(void *ctx)
     171                 :            : {
     172         [ -  + ]:          8 :         assert(g_num_complete_tasks > 0);
     173                 :            : 
     174         [ +  + ]:          8 :         if (--g_num_complete_tasks == 0) {
     175                 :          4 :                 spdk_poller_unregister(&g_runtime_poller);
     176                 :          4 :                 print_total_stats();
     177                 :          4 :                 spdk_app_stop(g_run_rc);
     178                 :            :         }
     179                 :          8 : }
     180                 :            : 
     181                 :            : static inline void
     182                 :        128 : dma_test_check_and_signal_task_done(struct dma_test_task *task)
     183                 :            : {
     184         [ +  + ]:        128 :         if (task->io_inflight == 0) {
     185                 :          8 :                 spdk_put_io_channel(task->channel);
     186                 :          8 :                 spdk_bdev_close(task->desc);
     187                 :          8 :                 spdk_thread_send_msg(g_main_thread, dma_test_task_complete, task);
     188                 :          8 :                 spdk_thread_exit(spdk_get_thread());
     189                 :            :         }
     190                 :        128 : }
     191                 :            : 
     192                 :            : static inline void
     193                 :    1364703 : dma_test_task_update_stats(struct dma_test_task *task, uint64_t submit_tsc)
     194                 :            : {
     195                 :    1364703 :         uint64_t tsc_diff = spdk_get_ticks() - submit_tsc;
     196                 :            : 
     197                 :    1364703 :         task->stats.io_completed++;
     198                 :    1364703 :         task->stats.total_tsc += tsc_diff;
     199         [ +  + ]:    1364703 :         if (spdk_unlikely(tsc_diff < task->stats.min_tsc)) {
     200                 :        175 :                 task->stats.min_tsc = tsc_diff;
     201                 :            :         }
     202         [ +  + ]:    1364703 :         if (spdk_unlikely(tsc_diff > task->stats.max_tsc)) {
     203                 :        123 :                 task->stats.max_tsc = tsc_diff;
     204                 :            :         }
     205                 :    1364703 : }
     206                 :            : 
     207                 :            : static void
     208                 :    1364703 : dma_test_bdev_io_completion_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     209                 :            : {
     210                 :    1364703 :         struct dma_test_req *req = cb_arg;
     211                 :    1364703 :         struct dma_test_task *task = req->task;
     212                 :            : 
     213         [ -  + ]:    1364703 :         assert(task->io_inflight > 0);
     214                 :    1364703 :         --task->io_inflight;
     215                 :    1364703 :         dma_test_task_update_stats(task, req->submit_tsc);
     216                 :            : 
     217         [ -  + ]:    1364703 :         if (!success) {
     218         [ #  # ]:          0 :                 if (!g_run_rc) {
     219         [ #  # ]:          0 :                         fprintf(stderr, "IO completed with error\n");
     220                 :          0 :                         g_run_rc = -1;
     221                 :            :                 }
     222                 :          0 :                 task->is_draining = true;
     223                 :            :         }
     224                 :            : 
     225                 :    1364703 :         spdk_bdev_free_io(bdev_io);
     226                 :            : 
     227   [ -  +  +  + ]:    1364703 :         if (spdk_unlikely(task->is_draining)) {
     228                 :        128 :                 dma_test_check_and_signal_task_done(task);
     229                 :        128 :                 return;
     230                 :            :         }
     231                 :            : 
     232                 :    1364575 :         dma_test_submit_io(req);
     233                 :            : }
     234                 :            : 
     235                 :            : static inline uint64_t
     236                 :    1364703 : dma_test_get_offset_in_ios(struct dma_test_task *task)
     237                 :            : {
     238                 :            :         uint64_t offset;
     239                 :            : 
     240   [ -  +  +  - ]:    1364703 :         if (task->is_random) {
     241         [ -  + ]:    1364703 :                 offset = rand_r(&task->seed) % task->max_offset_in_ios;
     242                 :            :         } else {
     243                 :          0 :                 offset = task->cur_io_offset++;
     244         [ #  # ]:          0 :                 if (spdk_unlikely(task->cur_io_offset == task->max_offset_in_ios)) {
     245                 :          0 :                         task->cur_io_offset = 0;
     246                 :            :                 }
     247                 :            :         }
     248                 :            : 
     249                 :    1364703 :         return offset;
     250                 :            : }
     251                 :            : 
     252                 :            : static inline bool
     253                 :    1364703 : dma_test_task_is_read(struct dma_test_task *task)
     254                 :            : {
     255         [ +  + ]:    1364703 :         if (task->rw_percentage == 100) {
     256                 :     817513 :                 return true;
     257                 :            :         }
     258   [ +  -  +  + ]:     547190 :         if (task->rw_percentage != 0 && (rand_r(&task->seed) % 100) <  task->rw_percentage) {
     259                 :     383023 :                 return true;
     260                 :            :         }
     261                 :     164167 :         return false;
     262                 :            : }
     263                 :            : 
     264                 :            : static void
     265                 :    1390658 : dma_test_data_cpl(void *ctx)
     266                 :            : {
     267                 :    1390658 :         struct dma_test_data_cpl_ctx *cpl_ctx = ctx;
     268                 :            : 
     269                 :    1390658 :         cpl_ctx->data_cpl(cpl_ctx->data_cpl_arg, 0);
     270                 :    1390658 :         free(cpl_ctx);
     271                 :    1390658 : }
     272                 :            : 
     273                 :            : static int
     274                 :     573040 : dma_test_copy_memory(struct dma_test_req *req, struct iovec *dst_iov, uint32_t dst_iovcnt,
     275                 :            :                      struct iovec *src_iov, uint32_t src_iovcnt, spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
     276                 :            : {
     277                 :            :         struct dma_test_data_cpl_ctx *cpl_ctx;
     278                 :            : 
     279                 :     573040 :         cpl_ctx = calloc(1, sizeof(*cpl_ctx));
     280         [ -  + ]:     573040 :         if (!cpl_ctx) {
     281                 :          0 :                 return -ENOMEM;
     282                 :            :         }
     283                 :            : 
     284                 :     573040 :         cpl_ctx->data_cpl = cpl_cb;
     285                 :     573040 :         cpl_ctx->data_cpl_arg = cpl_cb_arg;
     286                 :            : 
     287                 :     573040 :         spdk_iovcpy(src_iov, src_iovcnt, dst_iov, dst_iovcnt);
     288                 :     573040 :         req->task->num_pull_push++;
     289                 :     573040 :         spdk_thread_send_msg(req->task->thread, dma_test_data_cpl, cpl_ctx);
     290                 :            : 
     291                 :     573040 :         return 0;
     292                 :            : }
     293                 :            : 
     294                 :            : static int
     295                 :     401296 : dma_test_push_memory_cb(struct spdk_memory_domain *dst_domain,
     296                 :            :                         void *dst_domain_ctx,
     297                 :            :                         struct iovec *dst_iov, uint32_t dst_iovcnt, struct iovec *src_iov, uint32_t src_iovcnt,
     298                 :            :                         spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
     299                 :            : {
     300                 :     401296 :         struct dma_test_req *req = dst_domain_ctx;
     301                 :            : 
     302                 :     401296 :         return dma_test_copy_memory(req, dst_iov, dst_iovcnt, src_iov, src_iovcnt, cpl_cb, cpl_cb_arg);
     303                 :            : }
     304                 :            : 
     305                 :            : static int
     306                 :     171744 : dma_test_pull_memory_cb(struct spdk_memory_domain *src_domain,
     307                 :            :                         void *src_domain_ctx,
     308                 :            :                         struct iovec *src_iov, uint32_t src_iovcnt, struct iovec *dst_iov, uint32_t dst_iovcnt,
     309                 :            :                         spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
     310                 :            : {
     311                 :     171744 :         struct dma_test_req *req = src_domain_ctx;
     312                 :            : 
     313                 :     171744 :         return dma_test_copy_memory(req, dst_iov, dst_iovcnt, src_iov, src_iovcnt, cpl_cb, cpl_cb_arg);
     314                 :            : }
     315                 :            : 
     316                 :            : static int
     317                 :     817618 : dma_test_memzero_cb(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
     318                 :            :                     struct iovec *iov, uint32_t iovcnt,
     319                 :            :                     spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
     320                 :            : {
     321                 :     817618 :         struct dma_test_req *req = src_domain_ctx;
     322                 :            :         struct dma_test_data_cpl_ctx *cpl_ctx;
     323                 :            :         uint32_t i;
     324                 :            : 
     325                 :     817618 :         cpl_ctx = calloc(1, sizeof(*cpl_ctx));
     326         [ -  + ]:     817618 :         if (!cpl_ctx) {
     327                 :          0 :                 return -ENOMEM;
     328                 :            :         }
     329                 :            : 
     330                 :     817618 :         cpl_ctx->data_cpl = cpl_cb;
     331                 :     817618 :         cpl_ctx->data_cpl_arg = cpl_cb_arg;
     332                 :            : 
     333         [ +  + ]:    1635236 :         for (i = 0; i < iovcnt; i++) {
     334         [ -  + ]:     817618 :                 memset(iov[i].iov_base, 0, iov[i].iov_len);
     335                 :            :         }
     336                 :     817618 :         req->task->num_mem_zero++;
     337                 :            : 
     338                 :     817618 :         spdk_thread_send_msg(req->task->thread, dma_test_data_cpl, cpl_ctx);
     339                 :            : 
     340                 :     817618 :         return 0;
     341                 :            : }
     342                 :            : 
     343                 :            : 
     344                 :            : static int
     345                 :     403825 : dma_test_translate_memory_cb(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
     346                 :            :                              struct spdk_memory_domain *dst_domain, struct spdk_memory_domain_translation_ctx *dst_domain_ctx,
     347                 :            :                              void *addr, size_t len, struct spdk_memory_domain_translation_result *result)
     348                 :            : {
     349                 :     403825 :         struct dma_test_req *req = src_domain_ctx;
     350                 :     403825 :         struct ibv_qp *dst_domain_qp = (struct ibv_qp *)dst_domain_ctx->rdma.ibv_qp;
     351                 :            : 
     352         [ +  + ]:     403825 :         if (spdk_unlikely(!req->mr)) {
     353         [ +  - ]:        128 :                 req->mr = ibv_reg_mr(dst_domain_qp->pd, addr, len, IBV_ACCESS_LOCAL_WRITE |
     354                 :            :                                      IBV_ACCESS_REMOTE_READ |
     355                 :            :                                      IBV_ACCESS_REMOTE_WRITE);
     356         [ -  + ]:         64 :                 if (!req->mr) {
     357         [ #  # ]:          0 :                         fprintf(stderr, "Failed to register memory region, errno %d\n", errno);
     358                 :          0 :                         return -1;
     359                 :            :                 }
     360                 :            :         }
     361                 :            : 
     362                 :     403825 :         result->iov.iov_base = addr;
     363                 :     403825 :         result->iov.iov_len = len;
     364                 :     403825 :         result->iov_count = 1;
     365                 :     403825 :         result->rdma.lkey = req->mr->lkey;
     366                 :     403825 :         result->rdma.rkey = req->mr->rkey;
     367                 :     403825 :         result->dst_domain = dst_domain;
     368                 :            : 
     369                 :     403825 :         req->task->num_translations++;
     370                 :            : 
     371                 :     403825 :         return 0;
     372                 :            : }
     373                 :            : 
     374                 :            : static int
     375                 :    1364703 : dma_test_submit_io(struct dma_test_req *req)
     376                 :            : {
     377                 :    1364703 :         struct dma_test_task *task = req->task;
     378                 :            :         uint64_t offset_in_ios;
     379                 :            :         int rc;
     380                 :            :         bool is_read;
     381                 :            : 
     382                 :    1364703 :         offset_in_ios = dma_test_get_offset_in_ios(task);
     383                 :    1364703 :         is_read = dma_test_task_is_read(task);
     384                 :    1364703 :         req->submit_tsc = spdk_get_ticks();
     385         [ +  + ]:    1364703 :         if (is_read) {
     386                 :    2401072 :                 rc = spdk_bdev_readv_blocks_ext(task->desc, task->channel, &req->iov, 1,
     387                 :    1200536 :                                                 offset_in_ios * task->num_blocks_per_io, task->num_blocks_per_io,
     388                 :            :                                                 dma_test_bdev_io_completion_cb, req, &req->io_opts);
     389                 :            :         } else {
     390                 :     328334 :                 rc = spdk_bdev_writev_blocks_ext(task->desc, task->channel, &req->iov, 1,
     391                 :     164167 :                                                  offset_in_ios * task->num_blocks_per_io, task->num_blocks_per_io,
     392                 :            :                                                  dma_test_bdev_io_completion_cb, req, &req->io_opts);
     393                 :            :         }
     394                 :            : 
     395         [ -  + ]:    1364703 :         if (spdk_unlikely(rc)) {
     396         [ #  # ]:          0 :                 if (!g_run_rc) {
     397                 :            :                         /* log an error only once */
     398   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to submit %s IO, rc %d, stop sending IO\n", is_read ? "read" : "write", rc);
     399                 :          0 :                         g_run_rc = rc;
     400                 :            :                 }
     401                 :          0 :                 task->is_draining = true;
     402                 :          0 :                 dma_test_check_and_signal_task_done(task);
     403                 :          0 :                 return rc;
     404                 :            :         }
     405                 :            : 
     406                 :    1364703 :         task->io_inflight++;
     407                 :            : 
     408                 :    1364703 :         return 0;
     409                 :            : }
     410                 :            : 
     411                 :            : static void
     412                 :          0 : dma_test_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
     413                 :            : {
     414                 :          0 :         struct dma_test_task *task = event_ctx;
     415                 :            : 
     416         [ #  # ]:          0 :         if (type == SPDK_BDEV_EVENT_REMOVE) {
     417                 :          0 :                 task->is_draining = true;
     418                 :            :         }
     419                 :          0 : }
     420                 :            : 
     421                 :            : static void
     422                 :          0 : dma_test_bdev_dummy_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
     423                 :            :                              void *event_ctx)
     424                 :            : {
     425                 :          0 : }
     426                 :            : 
     427                 :            : static void
     428                 :          8 : dma_test_task_run(void *ctx)
     429                 :            : {
     430                 :          8 :         struct dma_test_task *task = ctx;
     431                 :            :         uint32_t i;
     432                 :          8 :         int rc = 0;
     433                 :            : 
     434   [ +  +  +  - ]:        136 :         for (i = 0; i < g_queue_depth && rc == 0; i++) {
     435                 :        128 :                 rc = dma_test_submit_io(&task->reqs[i]);
     436                 :            :         }
     437                 :          8 : }
     438                 :            : 
     439                 :            : static void
     440                 :          8 : dma_test_drain_task(void *ctx)
     441                 :            : {
     442                 :          8 :         struct dma_test_task *task = ctx;
     443                 :            : 
     444                 :          8 :         task->is_draining = true;
     445                 :          8 : }
     446                 :            : 
     447                 :            : static void
     448                 :          4 : dma_test_shutdown_cb(void)
     449                 :            : {
     450                 :            :         struct dma_test_task *task;
     451                 :            : 
     452                 :          4 :         spdk_poller_unregister(&g_runtime_poller);
     453                 :            : 
     454         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     455                 :          8 :                 spdk_thread_send_msg(task->thread, dma_test_drain_task, task);
     456                 :            :         }
     457                 :          4 : }
     458                 :            : 
     459                 :            : static int
     460                 :         20 : dma_test_run_time_poller(void *ctx)
     461                 :            : {
     462                 :         20 :         g_run_count++;
     463                 :            : 
     464         [ +  + ]:         20 :         if (g_run_count < g_run_time_sec) {
     465         [ -  + ]:         16 :                 if (isatty(STDOUT_FILENO)) {
     466                 :          0 :                         print_periodic_stats();
     467                 :            :                 }
     468                 :            :         } else {
     469                 :          4 :                 dma_test_shutdown_cb();
     470                 :            :         }
     471                 :            : 
     472                 :         20 :         return SPDK_POLLER_BUSY;
     473                 :            : }
     474                 :            : 
     475                 :            : static void
     476                 :          8 : dma_test_construct_task_done(void *ctx)
     477                 :            : {
     478                 :            :         struct dma_test_task *task;
     479                 :            : 
     480         [ -  + ]:          8 :         assert(g_num_construct_tasks > 0);
     481                 :          8 :         --g_num_construct_tasks;
     482                 :            : 
     483         [ +  + ]:          8 :         if (g_num_construct_tasks != 0) {
     484                 :          4 :                 return;
     485                 :            :         }
     486                 :            : 
     487         [ -  + ]:          4 :         if (g_run_rc) {
     488   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Initialization failed with error %d\n", g_run_rc);
     489                 :          0 :                 spdk_app_stop(g_run_rc);
     490                 :          0 :                 return;
     491                 :            :         }
     492                 :            : 
     493                 :          4 :         g_runtime_poller = spdk_poller_register_named(dma_test_run_time_poller, NULL, 1 * 1000 * 1000,
     494                 :            :                            "dma_test_run_time_poller");
     495         [ -  + ]:          4 :         if (!g_runtime_poller) {
     496   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to run timer\n");
     497                 :          0 :                 spdk_app_stop(-1);
     498                 :          0 :                 return;
     499                 :            :         }
     500                 :            : 
     501         [ -  + ]:          4 :         printf("Initialization complete, running %s IO for %u sec on %u cores\n", g_rw_mode_str,
     502                 :            :                g_run_time_sec, spdk_env_get_core_count());
     503                 :          4 :         g_start_tsc = spdk_get_ticks();
     504         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     505                 :          8 :                 spdk_thread_send_msg(task->thread, dma_test_task_run, task);
     506                 :            :         }
     507                 :            : }
     508                 :            : 
     509                 :            : static void
     510                 :          8 : dma_test_construct_task_on_thread(void *ctx)
     511                 :            : {
     512                 :          8 :         struct dma_test_task *task = ctx;
     513                 :            :         int rc;
     514                 :            : 
     515                 :          8 :         rc = spdk_bdev_open_ext(task->bdev_name, true, dma_test_bdev_event_cb, task, &task->desc);
     516         [ -  + ]:          8 :         if (rc) {
     517   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to open bdev %s, rc %d\n", task->bdev_name, rc);
     518                 :          0 :                 g_run_rc = rc;
     519                 :          0 :                 spdk_thread_send_msg(g_main_thread, dma_test_construct_task_done, NULL);
     520                 :          0 :                 return;
     521                 :            :         }
     522                 :            : 
     523                 :          8 :         task->channel = spdk_bdev_get_io_channel(task->desc);
     524         [ -  + ]:          8 :         if (!task->channel) {
     525                 :          0 :                 spdk_bdev_close(task->desc);
     526                 :          0 :                 task->desc = NULL;
     527   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to open bdev %s, rc %d\n", task->bdev_name, rc);
     528                 :          0 :                 g_run_rc = rc;
     529                 :          0 :                 spdk_thread_send_msg(g_main_thread, dma_test_construct_task_done, NULL);
     530                 :          0 :                 return;
     531                 :            :         }
     532                 :            : 
     533         [ -  + ]:         16 :         task->max_offset_in_ios = spdk_bdev_get_num_blocks(spdk_bdev_desc_get_bdev(
     534                 :         16 :                                           task->desc)) / task->num_blocks_per_io;
     535                 :            : 
     536                 :          8 :         spdk_thread_send_msg(g_main_thread, dma_test_construct_task_done, task);
     537                 :            : }
     538                 :            : 
     539                 :            : static bool
     540                 :          4 : dma_test_check_bdev_supports_rdma_memory_domain(struct spdk_bdev *bdev)
     541                 :            : {
     542                 :            :         struct spdk_memory_domain **bdev_domains;
     543                 :            :         int bdev_domains_count, bdev_domains_count_tmp, i;
     544                 :          4 :         bool rdma_domain_supported = false;
     545                 :            : 
     546                 :          4 :         bdev_domains_count = spdk_bdev_get_memory_domains(bdev, NULL, 0);
     547                 :            : 
     548         [ -  + ]:          4 :         if (bdev_domains_count < 0) {
     549   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to get bdev memory domains count, rc %d\n", bdev_domains_count);
     550                 :          0 :                 return false;
     551         [ -  + ]:          4 :         } else if (bdev_domains_count == 0) {
     552   [ #  #  #  # ]:          0 :                 fprintf(stderr, "bdev %s doesn't support any memory domains\n", spdk_bdev_get_name(bdev));
     553                 :          0 :                 return false;
     554                 :            :         }
     555                 :            : 
     556   [ -  +  -  + ]:          4 :         fprintf(stdout, "bdev %s reports %d memory domains\n", spdk_bdev_get_name(bdev),
     557                 :            :                 bdev_domains_count);
     558                 :            : 
     559                 :          4 :         bdev_domains = calloc((size_t)bdev_domains_count, sizeof(*bdev_domains));
     560         [ -  + ]:          4 :         if (!bdev_domains) {
     561   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate memory domains\n");
     562                 :          0 :                 return false;
     563                 :            :         }
     564                 :            : 
     565                 :          4 :         bdev_domains_count_tmp = spdk_bdev_get_memory_domains(bdev, bdev_domains, bdev_domains_count);
     566         [ -  + ]:          4 :         if (bdev_domains_count_tmp != bdev_domains_count) {
     567   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unexpected bdev domains return value %d\n", bdev_domains_count_tmp);
     568                 :          0 :                 return false;
     569                 :            :         }
     570                 :            : 
     571         [ +  + ]:          6 :         for (i = 0; i < bdev_domains_count; i++) {
     572         [ +  + ]:          5 :                 if (spdk_memory_domain_get_dma_device_type(bdev_domains[i]) == SPDK_DMA_DEVICE_TYPE_RDMA) {
     573                 :            :                         /* Bdev supports memory domain of RDMA type, we can try to submit IO request to it using
     574                 :            :                          * bdev ext API */
     575                 :          3 :                         rdma_domain_supported = true;
     576                 :          3 :                         break;
     577                 :            :                 }
     578                 :            :         }
     579                 :            : 
     580   [ +  +  -  +  :          4 :         fprintf(stdout, "bdev %s %s RDMA memory domain\n", spdk_bdev_get_name(bdev),
                   -  + ]
     581                 :            :                 rdma_domain_supported ? "supports" : "doesn't support");
     582                 :          4 :         free(bdev_domains);
     583                 :            : 
     584                 :          4 :         return rdma_domain_supported;
     585                 :            : }
     586                 :            : 
     587                 :            : static int
     588                 :          8 : allocate_task(uint32_t core, const char *bdev_name)
     589                 :            : {
     590                 :          0 :         char thread_name[32];
     591                 :          0 :         struct spdk_cpuset cpu_set;
     592                 :            :         uint32_t i;
     593                 :            :         struct dma_test_task *task;
     594                 :            :         struct dma_test_req *req;
     595                 :            : 
     596                 :          8 :         task = calloc(1, sizeof(*task));
     597         [ -  + ]:          8 :         if (!task) {
     598   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate per thread task\n");
     599                 :          0 :                 return -ENOMEM;
     600                 :            :         }
     601                 :            : 
     602                 :          8 :         TAILQ_INSERT_TAIL(&g_tasks, task, link);
     603                 :            : 
     604                 :          8 :         task->reqs = calloc(g_queue_depth, sizeof(*task->reqs));
     605         [ -  + ]:          8 :         if (!task->reqs) {
     606   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate requests\n");
     607                 :          0 :                 return -ENOMEM;
     608                 :            :         }
     609                 :            : 
     610         [ +  + ]:        136 :         for (i = 0; i < g_queue_depth; i++) {
     611                 :        128 :                 req = &task->reqs[i];
     612                 :        128 :                 req->task = task;
     613                 :        128 :                 req->iov.iov_len = g_io_size;
     614                 :        128 :                 req->iov.iov_base = malloc(req->iov.iov_len);
     615         [ -  + ]:        128 :                 if (!req->iov.iov_base) {
     616   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to allocate request data buffer\n");
     617                 :          0 :                         return -ENOMEM;
     618                 :            :                 }
     619         [ -  + ]:        128 :                 memset(req->iov.iov_base, 0xc, req->iov.iov_len);
     620                 :        128 :                 req->io_opts.size = sizeof(req->io_opts);
     621                 :        128 :                 req->io_opts.memory_domain = g_domain;
     622                 :        128 :                 req->io_opts.memory_domain_ctx = req;
     623                 :            :         }
     624                 :            : 
     625         [ -  + ]:          8 :         snprintf(thread_name, 32, "task_%u", core);
     626                 :          8 :         spdk_cpuset_zero(&cpu_set);
     627                 :          8 :         spdk_cpuset_set_cpu(&cpu_set, core, true);
     628                 :          8 :         task->thread = spdk_thread_create(thread_name, &cpu_set);
     629         [ -  + ]:          8 :         if (!task->thread) {
     630   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to create SPDK thread, core %u, cpu_mask %s\n", core,
     631                 :            :                         spdk_cpuset_fmt(&cpu_set));
     632                 :          0 :                 return -ENOMEM;
     633                 :            :         }
     634                 :            : 
     635                 :          8 :         task->seed = core;
     636                 :          8 :         task->lcore = core;
     637                 :          8 :         task->bdev_name = bdev_name;
     638         [ -  + ]:          8 :         task->is_random = g_is_random;
     639                 :          8 :         task->rw_percentage = g_rw_percentage;
     640                 :          8 :         task->num_blocks_per_io = g_num_blocks_per_io;
     641                 :          8 :         task->stats.min_tsc = UINT64_MAX;
     642                 :            : 
     643                 :          8 :         return 0;
     644                 :            : }
     645                 :            : 
     646                 :            : static void
     647                 :          8 : destroy_task(struct dma_test_task *task)
     648                 :            : {
     649                 :            :         struct dma_test_req *req;
     650                 :            :         uint32_t i;
     651                 :            : 
     652         [ +  + ]:        136 :         for (i = 0; i < g_queue_depth; i++) {
     653                 :        128 :                 req = &task->reqs[i];
     654         [ +  + ]:        128 :                 if (req->mr) {
     655                 :         64 :                         ibv_dereg_mr(req->mr);
     656                 :            :                 }
     657                 :        128 :                 free(req->iov.iov_base);
     658                 :            :         }
     659                 :          8 :         free(task->reqs);
     660         [ +  + ]:          8 :         TAILQ_REMOVE(&g_tasks, task, link);
     661                 :          8 :         free(task);
     662                 :          8 : }
     663                 :            : 
     664                 :            : static void
     665                 :          4 : destroy_tasks(void)
     666                 :            : {
     667                 :            :         struct dma_test_task *task, *tmp_task;
     668                 :            : 
     669         [ +  + ]:         12 :         TAILQ_FOREACH_SAFE(task, &g_tasks, link, tmp_task) {
     670                 :          8 :                 destroy_task(task);
     671                 :            :         }
     672                 :          4 : }
     673                 :            : 
     674                 :            : static int
     675                 :          4 : verify_tasks(void)
     676                 :            : {
     677                 :            :         struct dma_test_task *task;
     678                 :          4 :         uint64_t total_requests = 0;
     679                 :          4 :         uint64_t num_translations = 0;
     680                 :          4 :         uint64_t num_pull_push = 0;
     681                 :          4 :         uint64_t num_memzero = 0;
     682                 :          4 :         int rc = 0;
     683                 :            : 
     684         [ -  + ]:          4 :         if (!g_test_ops) {
     685                 :            :                 /* No specific ops were requested, nothing to check */
     686                 :          0 :                 return rc;
     687                 :            :         }
     688                 :            : 
     689         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     690                 :          8 :                 total_requests += task->stats.io_completed;
     691                 :          8 :                 num_translations += task->num_translations;
     692                 :          8 :                 num_pull_push += task->num_pull_push;
     693                 :          8 :                 num_memzero += task->num_mem_zero;
     694                 :            :         }
     695                 :            : 
     696         [ +  + ]:          4 :         if (g_test_ops & DMA_TEST_DOMAIN_OP_TRANSLATE) {
     697         [ -  + ]:          2 :                 if (num_translations == 0) {
     698   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Requested \"translate\" operation, but it was not executed\n");
     699                 :          0 :                         rc = -EINVAL;
     700                 :            :                 }
     701                 :            :         }
     702         [ +  + ]:          4 :         if (g_test_ops & DMA_TEST_DOMAIN_OP_PULL_PUSH) {
     703         [ -  + ]:          1 :                 if (num_pull_push == 0) {
     704   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Requested \"pull_push\" operation, but it was not executed\n");
     705                 :          0 :                         rc = -EINVAL;
     706                 :            :                 }
     707                 :            :         }
     708         [ +  + ]:          4 :         if (g_test_ops & DMA_TEST_DOMAIN_OP_MEMZERO) {
     709         [ -  + ]:          1 :                 if (num_memzero == 0) {
     710   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Requested \"memzero\" operation, but it was not executed\n");
     711                 :          0 :                         rc = -EINVAL;
     712                 :            :                 }
     713                 :            :         }
     714                 :            : 
     715                 :            :         /* bdev request can be split, so the total number of pull_push +translate operations
     716                 :            :          * can be bigger than total_number of requests */
     717         [ -  + ]:          4 :         if (num_translations + num_pull_push + num_memzero < total_requests) {
     718   [ #  #  #  # ]:          0 :                 fprintf(stderr,
     719                 :            :                         "Operations number mismatch: translate %"PRIu64", pull_push %"PRIu64", mem_zero %"PRIu64" expected total %"PRIu64"\n",
     720                 :            :                         num_translations, num_pull_push, num_memzero, total_requests);
     721                 :          0 :                 rc = -EINVAL;
     722                 :            :         } else {
     723   [ -  +  -  + ]:          4 :                 fprintf(stdout,
     724                 :            :                         "Total operations: %"PRIu64", translate %"PRIu64" pull_push %"PRIu64" memzero %"PRIu64"\n",
     725                 :            :                         total_requests, num_translations, num_pull_push, num_memzero);
     726                 :            :         }
     727                 :            : 
     728                 :          4 :         return rc;
     729                 :            : }
     730                 :            : 
     731                 :            : static void
     732                 :          4 : dma_test_start(void *arg)
     733                 :            : {
     734                 :          0 :         struct spdk_bdev_desc *desc;
     735                 :            :         struct spdk_bdev *bdev;
     736                 :            :         struct dma_test_task *task;
     737                 :            :         uint32_t block_size, i;
     738                 :            :         int rc;
     739                 :            : 
     740                 :          4 :         rc = spdk_bdev_open_ext(g_bdev_name, true, dma_test_bdev_dummy_event_cb, NULL, &desc);
     741         [ -  + ]:          4 :         if (rc) {
     742   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Can't find bdev %s\n", g_bdev_name);
     743                 :          0 :                 spdk_app_stop(-ENODEV);
     744                 :          0 :                 return;
     745                 :            :         }
     746                 :          4 :         bdev = spdk_bdev_desc_get_bdev(desc);
     747                 :            :         /* This function checks if bdev supports memory domains. Test is not failed if there are
     748                 :            :          * no memory domains since bdev layer can pull/push data */
     749   [ +  +  -  +  :          4 :         if (!dma_test_check_bdev_supports_rdma_memory_domain(bdev) && g_force_memory_domains_support) {
                   -  + ]
     750   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Test aborted due to \"-f\" (force memory domains support) option\n");
     751                 :          0 :                 spdk_bdev_close(desc);
     752                 :          0 :                 spdk_app_stop(-ENODEV);
     753                 :          0 :                 return;
     754                 :            :         }
     755                 :            : 
     756                 :          4 :         g_main_thread = spdk_get_thread();
     757                 :            : 
     758                 :          4 :         block_size = spdk_bdev_get_block_size(bdev);
     759   [ +  -  -  +  :          4 :         if (g_io_size < block_size || g_io_size % block_size != 0) {
                   -  + ]
     760   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Invalid io_size %u requested, bdev block size %u\n", g_io_size, block_size);
     761                 :          0 :                 spdk_bdev_close(desc);
     762                 :          0 :                 spdk_app_stop(-EINVAL);
     763                 :          0 :                 return;
     764                 :            :         }
     765         [ -  + ]:          4 :         g_num_blocks_per_io = g_io_size / block_size;
     766                 :            : 
     767                 :            :         /* Create a memory domain to represent the source memory domain.
     768                 :            :          * Since we don't actually have a remote memory domain in this test, this will describe memory
     769                 :            :          * on the local system and the translation to the destination memory domain will be trivial.
     770                 :            :          * But this at least allows us to demonstrate the flow and test the functionality. */
     771                 :          4 :         rc = spdk_memory_domain_create(&g_domain, SPDK_DMA_DEVICE_TYPE_RDMA, NULL, "test_dma");
     772         [ -  + ]:          4 :         if (rc != 0) {
     773                 :          0 :                 spdk_bdev_close(desc);
     774                 :          0 :                 spdk_app_stop(rc);
     775                 :          0 :                 return;
     776                 :            :         }
     777                 :          4 :         spdk_memory_domain_set_translation(g_domain, dma_test_translate_memory_cb);
     778                 :          4 :         spdk_memory_domain_set_pull(g_domain, dma_test_pull_memory_cb);
     779                 :          4 :         spdk_memory_domain_set_push(g_domain, dma_test_push_memory_cb);
     780                 :          4 :         spdk_memory_domain_set_memzero(g_domain, dma_test_memzero_cb);
     781                 :            : 
     782         [ +  + ]:         12 :         SPDK_ENV_FOREACH_CORE(i) {
     783                 :          8 :                 rc = allocate_task(i, g_bdev_name);
     784         [ -  + ]:          8 :                 if (rc) {
     785                 :          0 :                         destroy_tasks();
     786                 :          0 :                         spdk_bdev_close(desc);
     787                 :          0 :                         spdk_app_stop(rc);
     788                 :          0 :                         return;
     789                 :            :                 }
     790                 :          8 :                 g_num_construct_tasks++;
     791                 :          8 :                 g_num_complete_tasks++;
     792                 :            :         }
     793                 :            : 
     794         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     795                 :          8 :                 spdk_thread_send_msg(task->thread, dma_test_construct_task_on_thread, task);
     796                 :            :         }
     797                 :            : 
     798                 :          4 :         spdk_bdev_close(desc);
     799                 :            : }
     800                 :            : 
     801                 :            : static void
     802                 :          0 : print_usage(void)
     803                 :            : {
     804         [ #  # ]:          0 :         printf(" -b <bdev>         bdev name for test\n");
     805         [ #  # ]:          0 :         printf(" -f                force memory domains support - abort test if bdev doesn't report memory domains\n");
     806         [ #  # ]:          0 :         printf(" -q <val>          io depth\n");
     807         [ #  # ]:          0 :         printf(" -o <val>          io size in bytes\n");
     808         [ #  # ]:          0 :         printf(" -t <val>          run time in seconds\n");
     809         [ #  # ]:          0 :         printf(" -x <op,op>        Comma separated memory domain operations expected in the test. Values are \"translate\" and \"pull_push\"\n");
     810         [ #  # ]:          0 :         printf(" -w <str>          io pattern (read, write, randread, randwrite, randrw)\n");
     811         [ #  # ]:          0 :         printf(" -M <0-100>        rw percentage (100 for reads, 0 for writes)\n");
     812                 :          0 : }
     813                 :            : 
     814                 :            : static int
     815                 :          4 : parse_expected_ops(const char *_str)
     816                 :            : {
     817         [ -  + ]:          4 :         char *str = strdup(_str);
     818                 :            :         char *tok;
     819                 :          4 :         int rc = 0;
     820                 :            : 
     821         [ -  + ]:          4 :         if (!str) {
     822         [ #  # ]:          0 :                 fprintf(stderr, "Failed to dup args\n");
     823                 :          0 :                 return -ENOMEM;
     824                 :            :         }
     825                 :            : 
     826                 :          4 :         tok = strtok(str, ",");
     827         [ +  + ]:          8 :         while (tok) {
     828   [ -  +  +  + ]:          4 :                 if (strcmp(tok, "translate") == 0) {
     829                 :          2 :                         g_test_ops |= DMA_TEST_DOMAIN_OP_TRANSLATE;
     830   [ -  +  +  + ]:          2 :                 } else if (strcmp(tok, "pull_push") == 0) {
     831                 :          1 :                         g_test_ops |= DMA_TEST_DOMAIN_OP_PULL_PUSH;
     832   [ -  +  +  - ]:          1 :                 } else if (strcmp(tok, "memzero") == 0) {
     833                 :          1 :                         g_test_ops |= DMA_TEST_DOMAIN_OP_MEMZERO;
     834                 :            :                 } else {
     835         [ #  # ]:          0 :                         fprintf(stderr, "Unknown value %s\n", tok);
     836                 :          0 :                         rc = -EINVAL;
     837                 :          0 :                         break;
     838                 :            :                 }
     839                 :          4 :                 tok = strtok(NULL, ",");
     840                 :            :         }
     841                 :            : 
     842                 :          4 :         free(str);
     843                 :            : 
     844   [ +  -  -  + ]:          4 :         if (g_test_ops == 0 || rc) {
     845         [ #  # ]:          0 :                 fprintf(stderr, "-e \"%s\" specified but nothing was parsed\n", _str);
     846                 :          0 :                 return -EINVAL;
     847                 :            :         }
     848                 :            : 
     849                 :          4 :         return rc;
     850                 :            : }
     851                 :            : 
     852                 :            : static int
     853                 :         31 : parse_arg(int ch, char *arg)
     854                 :            : {
     855                 :            :         long tmp;
     856                 :            : 
     857   [ +  +  +  +  :         31 :         switch (ch) {
                   +  - ]
     858                 :         16 :         case 'q':
     859                 :            :         case 'o':
     860                 :            :         case 't':
     861                 :            :         case 'M':
     862                 :         16 :                 tmp = spdk_strtol(arg, 10);
     863         [ -  + ]:         16 :                 if (tmp < 0) {
     864   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Invalid option %c value %s\n", ch, arg);
     865                 :          0 :                         return 1;
     866                 :            :                 }
     867                 :            : 
     868                 :            :                 switch (ch) {
     869                 :          4 :                 case 'q':
     870                 :          4 :                         g_queue_depth = (uint32_t) tmp;
     871                 :          4 :                         break;
     872                 :          4 :                 case 'o':
     873                 :          4 :                         g_io_size = (uint32_t) tmp;
     874                 :          4 :                         break;
     875                 :          4 :                 case 't':
     876                 :          4 :                         g_run_time_sec = (uint32_t) tmp;
     877                 :          4 :                         break;
     878                 :          4 :                 case 'M':
     879                 :          4 :                         g_rw_percentage = (uint32_t) tmp;
     880                 :          4 :                         break;
     881                 :            :                 }
     882                 :         16 :                 break;
     883                 :          4 :         case 'w':
     884                 :          4 :                 g_rw_mode_str = arg;
     885                 :          4 :                 break;
     886                 :          4 :         case 'b':
     887                 :          4 :                 g_bdev_name = arg;
     888                 :          4 :                 break;
     889                 :          3 :         case 'f':
     890                 :          3 :                 g_force_memory_domains_support = true;
     891                 :          3 :                 break;
     892                 :          4 :         case 'x':
     893         [ -  + ]:          4 :                 if (parse_expected_ops(arg)) {
     894                 :          0 :                         return 1;
     895                 :            :                 }
     896                 :          4 :                 break;
     897                 :          0 :         default:
     898   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unknown option %c\n", ch);
     899                 :          0 :                 return 1;
     900                 :            :         }
     901                 :            : 
     902                 :         31 :         return 0;
     903                 :            : }
     904                 :            : 
     905                 :            : static int
     906                 :          4 : verify_args(void)
     907                 :            : {
     908                 :          4 :         const char *rw_mode = g_rw_mode_str;
     909                 :            : 
     910         [ -  + ]:          4 :         if (g_queue_depth == 0) {
     911         [ #  # ]:          0 :                 fprintf(stderr, "queue depth (-q) is not set\n");
     912                 :          0 :                 return 1;
     913                 :            :         }
     914         [ -  + ]:          4 :         if (g_io_size == 0) {
     915         [ #  # ]:          0 :                 fprintf(stderr, "io size (-o) is not set\n");
     916                 :          0 :                 return 1;
     917                 :            :         }
     918         [ -  + ]:          4 :         if (g_run_time_sec == 0) {
     919         [ #  # ]:          0 :                 fprintf(stderr, "test run time (-t) is not set\n");
     920                 :          0 :                 return 1;
     921                 :            :         }
     922         [ -  + ]:          4 :         if (!rw_mode) {
     923         [ #  # ]:          0 :                 fprintf(stderr, "io pattern (-w) is not set\n");
     924                 :          0 :                 return 1;
     925                 :            :         }
     926   [ -  +  +  - ]:          4 :         if (strncmp(rw_mode, "rand", 4) == 0) {
     927                 :          4 :                 g_is_random = true;
     928                 :          4 :                 rw_mode = &rw_mode[4];
     929                 :            :         }
     930   [ -  +  +  +  :          4 :         if (strcmp(rw_mode, "read") == 0 || strcmp(rw_mode, "write") == 0) {
             -  +  -  + ]
     931         [ +  - ]:          1 :                 if (g_rw_percentage > 0) {
     932         [ -  + ]:          1 :                         fprintf(stderr, "Ignoring -M option\n");
     933                 :            :                 }
     934   [ -  +  +  - ]:          1 :                 g_rw_percentage = strcmp(rw_mode, "read") == 0 ? 100 : 0;
     935   [ -  +  +  - ]:          3 :         } else if (strcmp(rw_mode, "rw") == 0) {
     936   [ +  -  -  + ]:          3 :                 if (g_rw_percentage < 0 || g_rw_percentage > 100) {
     937         [ #  # ]:          0 :                         fprintf(stderr, "Invalid -M value (%d) must be 0..100\n", g_rw_percentage);
     938                 :          0 :                         return 1;
     939                 :            :                 }
     940                 :            :         } else {
     941         [ #  # ]:          0 :                 fprintf(stderr, "io pattern (-w) one of [read, write, randread, randwrite, rw, randrw]\n");
     942                 :          0 :                 return 1;
     943                 :            :         }
     944         [ -  + ]:          4 :         if (!g_bdev_name) {
     945         [ #  # ]:          0 :                 fprintf(stderr, "bdev name (-b) is not set\n");
     946                 :          0 :                 return 1;
     947                 :            :         }
     948                 :            : 
     949                 :          4 :         return 0;
     950                 :            : }
     951                 :            : 
     952                 :            : int
     953                 :          4 : main(int argc, char **argv)
     954                 :            : {
     955                 :          4 :         struct spdk_app_opts opts = {};
     956                 :            :         int rc;
     957                 :            : 
     958                 :          4 :         spdk_app_opts_init(&opts, sizeof(opts));
     959                 :          4 :         opts.name = "test_dma";
     960                 :          4 :         opts.shutdown_cb = dma_test_shutdown_cb;
     961                 :          4 :         opts.rpc_addr = NULL;
     962                 :            : 
     963                 :          4 :         rc = spdk_app_parse_args(argc, argv, &opts, "b:fq:o:t:x:w:M:", NULL, parse_arg, print_usage);
     964         [ -  + ]:          4 :         if (rc != SPDK_APP_PARSE_ARGS_SUCCESS) {
     965                 :          0 :                 exit(rc);
     966                 :            :         }
     967                 :            : 
     968                 :          4 :         rc = verify_args();
     969         [ -  + ]:          4 :         if (rc) {
     970                 :          0 :                 exit(rc);
     971                 :            :         }
     972                 :            : 
     973                 :          4 :         rc = spdk_app_start(&opts, dma_test_start, NULL);
     974         [ +  - ]:          4 :         if (rc == 0) {
     975                 :          4 :                 rc = verify_tasks();
     976                 :            :         }
     977                 :          4 :         destroy_tasks();
     978                 :          4 :         spdk_app_fini();
     979                 :            : 
     980                 :          4 :         return rc;
     981                 :            : }

Generated by: LCOV version 1.14