LCOV - code coverage report
Current view: top level - spdk/test/dma/test_dma - test_dma.c (source / functions) Hit Total Coverage
Test: Combined Lines: 361 504 71.6 %
Date: 2024-08-11 23:22:04 Functions: 30 34 88.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 179 427 41.9 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (c) 2021, 2024 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                 :          5 :                         total_min_lat = task_min_lat;
     127                 :            :                 }
     128         [ +  + ]:          8 :                 if (task_max_lat > total_max_lat) {
     129                 :          4 :                         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                 :    1370960 : dma_test_task_update_stats(struct dma_test_task *task, uint64_t submit_tsc)
     194                 :            : {
     195                 :    1370960 :         uint64_t tsc_diff = spdk_get_ticks() - submit_tsc;
     196                 :            : 
     197                 :    1370960 :         task->stats.io_completed++;
     198                 :    1370960 :         task->stats.total_tsc += tsc_diff;
     199         [ +  + ]:    1370960 :         if (spdk_unlikely(tsc_diff < task->stats.min_tsc)) {
     200                 :        195 :                 task->stats.min_tsc = tsc_diff;
     201                 :            :         }
     202         [ +  + ]:    1370960 :         if (spdk_unlikely(tsc_diff > task->stats.max_tsc)) {
     203                 :        109 :                 task->stats.max_tsc = tsc_diff;
     204                 :            :         }
     205                 :    1370960 : }
     206                 :            : 
     207                 :            : static void
     208                 :    1370960 : dma_test_bdev_io_completion_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     209                 :            : {
     210                 :    1370960 :         struct dma_test_req *req = cb_arg;
     211                 :    1370960 :         struct dma_test_task *task = req->task;
     212                 :            : 
     213         [ -  + ]:    1370960 :         assert(task->io_inflight > 0);
     214                 :    1370960 :         --task->io_inflight;
     215                 :    1370960 :         dma_test_task_update_stats(task, req->submit_tsc);
     216                 :            : 
     217         [ -  + ]:    1370960 :         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                 :    1370960 :         spdk_bdev_free_io(bdev_io);
     226                 :            : 
     227   [ -  +  +  + ]:    1370960 :         if (spdk_unlikely(task->is_draining)) {
     228                 :        128 :                 dma_test_check_and_signal_task_done(task);
     229                 :        128 :                 return;
     230                 :            :         }
     231                 :            : 
     232                 :    1370832 :         dma_test_submit_io(req);
     233                 :            : }
     234                 :            : 
     235                 :            : static inline uint64_t
     236                 :    1370960 : dma_test_get_offset_in_ios(struct dma_test_task *task)
     237                 :            : {
     238                 :            :         uint64_t offset;
     239                 :            : 
     240   [ -  +  +  - ]:    1370960 :         if (task->is_random) {
     241         [ -  + ]:    1370960 :                 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                 :    1370960 :         return offset;
     250                 :            : }
     251                 :            : 
     252                 :            : static inline bool
     253                 :    1370960 : dma_test_task_is_read(struct dma_test_task *task)
     254                 :            : {
     255         [ +  + ]:    1370960 :         if (task->rw_percentage == 100) {
     256                 :     818094 :                 return true;
     257                 :            :         }
     258   [ +  -  +  + ]:     552866 :         if (task->rw_percentage != 0 && (rand_r(&task->seed) % 100) <  task->rw_percentage) {
     259                 :     386986 :                 return true;
     260                 :            :         }
     261                 :     165880 :         return false;
     262                 :            : }
     263                 :            : 
     264                 :            : static void
     265                 :    1392269 : dma_test_data_cpl(void *ctx)
     266                 :            : {
     267                 :    1392269 :         struct dma_test_data_cpl_ctx *cpl_ctx = ctx;
     268                 :            : 
     269                 :    1392269 :         cpl_ctx->data_cpl(cpl_ctx->data_cpl_arg, 0);
     270                 :    1392269 :         free(cpl_ctx);
     271                 :    1392269 : }
     272                 :            : 
     273                 :            : static int
     274                 :     574072 : 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                 :     574072 :         cpl_ctx = calloc(1, sizeof(*cpl_ctx));
     280         [ -  + ]:     574072 :         if (!cpl_ctx) {
     281                 :          0 :                 return -ENOMEM;
     282                 :            :         }
     283                 :            : 
     284                 :     574072 :         cpl_ctx->data_cpl = cpl_cb;
     285                 :     574072 :         cpl_ctx->data_cpl_arg = cpl_cb_arg;
     286                 :            : 
     287                 :     574072 :         spdk_iovcpy(src_iov, src_iovcnt, dst_iov, dst_iovcnt);
     288                 :     574072 :         req->task->num_pull_push++;
     289                 :     574072 :         spdk_thread_send_msg(req->task->thread, dma_test_data_cpl, cpl_ctx);
     290                 :            : 
     291                 :     574072 :         return 0;
     292                 :            : }
     293                 :            : 
     294                 :            : static int
     295                 :     402020 : 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                 :     402020 :         struct dma_test_req *req = dst_domain_ctx;
     301                 :            : 
     302                 :     402020 :         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                 :     172052 : 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                 :     172052 :         struct dma_test_req *req = src_domain_ctx;
     312                 :            : 
     313                 :     172052 :         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                 :     818197 : 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                 :     818197 :         struct dma_test_req *req = src_domain_ctx;
     322                 :            :         struct dma_test_data_cpl_ctx *cpl_ctx;
     323                 :            :         uint32_t i;
     324                 :            : 
     325                 :     818197 :         cpl_ctx = calloc(1, sizeof(*cpl_ctx));
     326         [ -  + ]:     818197 :         if (!cpl_ctx) {
     327                 :          0 :                 return -ENOMEM;
     328                 :            :         }
     329                 :            : 
     330                 :     818197 :         cpl_ctx->data_cpl = cpl_cb;
     331                 :     818197 :         cpl_ctx->data_cpl_arg = cpl_cb_arg;
     332                 :            : 
     333         [ +  + ]:    1636394 :         for (i = 0; i < iovcnt; i++) {
     334         [ -  + ]:     818197 :                 memset(iov[i].iov_base, 0, iov[i].iov_len);
     335                 :            :         }
     336                 :     818197 :         req->task->num_mem_zero++;
     337                 :            : 
     338                 :     818197 :         spdk_thread_send_msg(req->task->thread, dma_test_data_cpl, cpl_ctx);
     339                 :            : 
     340                 :     818197 :         return 0;
     341                 :            : }
     342                 :            : 
     343                 :            : 
     344                 :            : static int
     345                 :     409245 : 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                 :     409245 :         struct dma_test_req *req = src_domain_ctx;
     350                 :     409245 :         struct ibv_qp *dst_domain_qp = (struct ibv_qp *)dst_domain_ctx->rdma.ibv_qp;
     351                 :            : 
     352   [ +  -  -  + ]:     409245 :         if (spdk_unlikely(addr < req->iov.iov_base ||
     353                 :            :                           (uint8_t *)addr + len > (uint8_t *)req->iov.iov_base + req->iov.iov_len)) {
     354         [ #  # ]:          0 :                 fprintf(stderr, "incorrect data %p, len %zu\n", addr, len);
     355                 :          0 :                 return -1;
     356                 :            :         }
     357                 :            : 
     358         [ +  + ]:     409245 :         if (spdk_unlikely(!req->mr)) {
     359         [ +  - ]:        128 :                 req->mr = ibv_reg_mr(dst_domain_qp->pd, req->iov.iov_base, req->iov.iov_len,
     360                 :            :                                      IBV_ACCESS_LOCAL_WRITE |
     361                 :            :                                      IBV_ACCESS_REMOTE_READ |
     362                 :            :                                      IBV_ACCESS_REMOTE_WRITE);
     363         [ -  + ]:         64 :                 if (!req->mr) {
     364         [ #  # ]:          0 :                         fprintf(stderr, "Failed to register memory region, errno %d\n", errno);
     365                 :          0 :                         return -1;
     366                 :            :                 }
     367                 :            :         }
     368                 :            : 
     369                 :     409245 :         result->iov.iov_base = addr;
     370                 :     409245 :         result->iov.iov_len = len;
     371                 :     409245 :         result->iov_count = 1;
     372                 :     409245 :         result->rdma.lkey = req->mr->lkey;
     373                 :     409245 :         result->rdma.rkey = req->mr->rkey;
     374                 :     409245 :         result->dst_domain = dst_domain;
     375                 :            : 
     376                 :     409245 :         req->task->num_translations++;
     377                 :            : 
     378                 :     409245 :         return 0;
     379                 :            : }
     380                 :            : 
     381                 :            : static int
     382                 :    1370960 : dma_test_submit_io(struct dma_test_req *req)
     383                 :            : {
     384                 :    1370960 :         struct dma_test_task *task = req->task;
     385                 :            :         uint64_t offset_in_ios;
     386                 :            :         int rc;
     387                 :            :         bool is_read;
     388                 :            : 
     389                 :    1370960 :         offset_in_ios = dma_test_get_offset_in_ios(task);
     390                 :    1370960 :         is_read = dma_test_task_is_read(task);
     391                 :    1370960 :         req->submit_tsc = spdk_get_ticks();
     392         [ +  + ]:    1370960 :         if (is_read) {
     393                 :    2410160 :                 rc = spdk_bdev_readv_blocks_ext(task->desc, task->channel, &req->iov, 1,
     394                 :    1205080 :                                                 offset_in_ios * task->num_blocks_per_io, task->num_blocks_per_io,
     395                 :            :                                                 dma_test_bdev_io_completion_cb, req, &req->io_opts);
     396                 :            :         } else {
     397                 :     331760 :                 rc = spdk_bdev_writev_blocks_ext(task->desc, task->channel, &req->iov, 1,
     398                 :     165880 :                                                  offset_in_ios * task->num_blocks_per_io, task->num_blocks_per_io,
     399                 :            :                                                  dma_test_bdev_io_completion_cb, req, &req->io_opts);
     400                 :            :         }
     401                 :            : 
     402         [ -  + ]:    1370960 :         if (spdk_unlikely(rc)) {
     403         [ #  # ]:          0 :                 if (!g_run_rc) {
     404                 :            :                         /* log an error only once */
     405   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to submit %s IO, rc %d, stop sending IO\n", is_read ? "read" : "write", rc);
     406                 :          0 :                         g_run_rc = rc;
     407                 :            :                 }
     408                 :          0 :                 task->is_draining = true;
     409                 :          0 :                 dma_test_check_and_signal_task_done(task);
     410                 :          0 :                 return rc;
     411                 :            :         }
     412                 :            : 
     413                 :    1370960 :         task->io_inflight++;
     414                 :            : 
     415                 :    1370960 :         return 0;
     416                 :            : }
     417                 :            : 
     418                 :            : static void
     419                 :          0 : dma_test_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
     420                 :            : {
     421                 :          0 :         struct dma_test_task *task = event_ctx;
     422                 :            : 
     423         [ #  # ]:          0 :         if (type == SPDK_BDEV_EVENT_REMOVE) {
     424                 :          0 :                 task->is_draining = true;
     425                 :            :         }
     426                 :          0 : }
     427                 :            : 
     428                 :            : static void
     429                 :          0 : dma_test_bdev_dummy_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
     430                 :            :                              void *event_ctx)
     431                 :            : {
     432                 :          0 : }
     433                 :            : 
     434                 :            : static void
     435                 :          8 : dma_test_task_run(void *ctx)
     436                 :            : {
     437                 :          8 :         struct dma_test_task *task = ctx;
     438                 :            :         uint32_t i;
     439                 :          8 :         int rc = 0;
     440                 :            : 
     441   [ +  +  +  - ]:        136 :         for (i = 0; i < g_queue_depth && rc == 0; i++) {
     442                 :        128 :                 rc = dma_test_submit_io(&task->reqs[i]);
     443                 :            :         }
     444                 :          8 : }
     445                 :            : 
     446                 :            : static void
     447                 :          8 : dma_test_drain_task(void *ctx)
     448                 :            : {
     449                 :          8 :         struct dma_test_task *task = ctx;
     450                 :            : 
     451                 :          8 :         task->is_draining = true;
     452                 :          8 : }
     453                 :            : 
     454                 :            : static void
     455                 :          4 : dma_test_shutdown_cb(void)
     456                 :            : {
     457                 :            :         struct dma_test_task *task;
     458                 :            : 
     459                 :          4 :         spdk_poller_unregister(&g_runtime_poller);
     460                 :            : 
     461         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     462                 :          8 :                 spdk_thread_send_msg(task->thread, dma_test_drain_task, task);
     463                 :            :         }
     464                 :          4 : }
     465                 :            : 
     466                 :            : static int
     467                 :         20 : dma_test_run_time_poller(void *ctx)
     468                 :            : {
     469                 :         20 :         g_run_count++;
     470                 :            : 
     471         [ +  + ]:         20 :         if (g_run_count < g_run_time_sec) {
     472         [ -  + ]:         16 :                 if (isatty(STDOUT_FILENO)) {
     473                 :          0 :                         print_periodic_stats();
     474                 :            :                 }
     475                 :            :         } else {
     476                 :          4 :                 dma_test_shutdown_cb();
     477                 :            :         }
     478                 :            : 
     479                 :         20 :         return SPDK_POLLER_BUSY;
     480                 :            : }
     481                 :            : 
     482                 :            : static void
     483                 :          8 : dma_test_construct_task_done(void *ctx)
     484                 :            : {
     485                 :            :         struct dma_test_task *task;
     486                 :            : 
     487         [ -  + ]:          8 :         assert(g_num_construct_tasks > 0);
     488                 :          8 :         --g_num_construct_tasks;
     489                 :            : 
     490         [ +  + ]:          8 :         if (g_num_construct_tasks != 0) {
     491                 :          4 :                 return;
     492                 :            :         }
     493                 :            : 
     494         [ -  + ]:          4 :         if (g_run_rc) {
     495   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Initialization failed with error %d\n", g_run_rc);
     496                 :          0 :                 spdk_app_stop(g_run_rc);
     497                 :          0 :                 return;
     498                 :            :         }
     499                 :            : 
     500                 :          4 :         g_runtime_poller = spdk_poller_register_named(dma_test_run_time_poller, NULL, 1 * 1000 * 1000,
     501                 :            :                            "dma_test_run_time_poller");
     502         [ -  + ]:          4 :         if (!g_runtime_poller) {
     503   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to run timer\n");
     504                 :          0 :                 spdk_app_stop(-1);
     505                 :          0 :                 return;
     506                 :            :         }
     507                 :            : 
     508         [ -  + ]:          4 :         printf("Initialization complete, running %s IO for %u sec on %u cores\n", g_rw_mode_str,
     509                 :            :                g_run_time_sec, spdk_env_get_core_count());
     510                 :          4 :         g_start_tsc = spdk_get_ticks();
     511         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     512                 :          8 :                 spdk_thread_send_msg(task->thread, dma_test_task_run, task);
     513                 :            :         }
     514                 :            : }
     515                 :            : 
     516                 :            : static void
     517                 :          8 : dma_test_construct_task_on_thread(void *ctx)
     518                 :            : {
     519                 :          8 :         struct dma_test_task *task = ctx;
     520                 :            :         int rc;
     521                 :            : 
     522                 :          8 :         rc = spdk_bdev_open_ext(task->bdev_name, true, dma_test_bdev_event_cb, task, &task->desc);
     523         [ -  + ]:          8 :         if (rc) {
     524   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to open bdev %s, rc %d\n", task->bdev_name, rc);
     525                 :          0 :                 g_run_rc = rc;
     526                 :          0 :                 spdk_thread_send_msg(g_main_thread, dma_test_construct_task_done, NULL);
     527                 :          0 :                 return;
     528                 :            :         }
     529                 :            : 
     530                 :          8 :         task->channel = spdk_bdev_get_io_channel(task->desc);
     531         [ -  + ]:          8 :         if (!task->channel) {
     532                 :          0 :                 spdk_bdev_close(task->desc);
     533                 :          0 :                 task->desc = NULL;
     534   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to open bdev %s, rc %d\n", task->bdev_name, rc);
     535                 :          0 :                 g_run_rc = rc;
     536                 :          0 :                 spdk_thread_send_msg(g_main_thread, dma_test_construct_task_done, NULL);
     537                 :          0 :                 return;
     538                 :            :         }
     539                 :            : 
     540         [ -  + ]:         16 :         task->max_offset_in_ios = spdk_bdev_get_num_blocks(spdk_bdev_desc_get_bdev(
     541                 :         16 :                                           task->desc)) / task->num_blocks_per_io;
     542                 :            : 
     543                 :          8 :         spdk_thread_send_msg(g_main_thread, dma_test_construct_task_done, task);
     544                 :            : }
     545                 :            : 
     546                 :            : static bool
     547                 :          4 : dma_test_check_bdev_supports_rdma_memory_domain(struct spdk_bdev *bdev)
     548                 :            : {
     549                 :            :         struct spdk_memory_domain **bdev_domains;
     550                 :            :         int bdev_domains_count, bdev_domains_count_tmp, i;
     551                 :          4 :         bool rdma_domain_supported = false;
     552                 :            : 
     553                 :          4 :         bdev_domains_count = spdk_bdev_get_memory_domains(bdev, NULL, 0);
     554                 :            : 
     555         [ -  + ]:          4 :         if (bdev_domains_count < 0) {
     556   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to get bdev memory domains count, rc %d\n", bdev_domains_count);
     557                 :          0 :                 return false;
     558         [ -  + ]:          4 :         } else if (bdev_domains_count == 0) {
     559   [ #  #  #  # ]:          0 :                 fprintf(stderr, "bdev %s doesn't support any memory domains\n", spdk_bdev_get_name(bdev));
     560                 :          0 :                 return false;
     561                 :            :         }
     562                 :            : 
     563   [ -  +  -  + ]:          4 :         fprintf(stdout, "bdev %s reports %d memory domains\n", spdk_bdev_get_name(bdev),
     564                 :            :                 bdev_domains_count);
     565                 :            : 
     566                 :          4 :         bdev_domains = calloc((size_t)bdev_domains_count, sizeof(*bdev_domains));
     567         [ -  + ]:          4 :         if (!bdev_domains) {
     568   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate memory domains\n");
     569                 :          0 :                 return false;
     570                 :            :         }
     571                 :            : 
     572                 :          4 :         bdev_domains_count_tmp = spdk_bdev_get_memory_domains(bdev, bdev_domains, bdev_domains_count);
     573         [ -  + ]:          4 :         if (bdev_domains_count_tmp != bdev_domains_count) {
     574   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unexpected bdev domains return value %d\n", bdev_domains_count_tmp);
     575                 :          0 :                 return false;
     576                 :            :         }
     577                 :            : 
     578         [ +  + ]:          6 :         for (i = 0; i < bdev_domains_count; i++) {
     579         [ +  + ]:          5 :                 if (spdk_memory_domain_get_dma_device_type(bdev_domains[i]) == SPDK_DMA_DEVICE_TYPE_RDMA) {
     580                 :            :                         /* Bdev supports memory domain of RDMA type, we can try to submit IO request to it using
     581                 :            :                          * bdev ext API */
     582                 :          3 :                         rdma_domain_supported = true;
     583                 :          3 :                         break;
     584                 :            :                 }
     585                 :            :         }
     586                 :            : 
     587   [ +  +  -  +  :          4 :         fprintf(stdout, "bdev %s %s RDMA memory domain\n", spdk_bdev_get_name(bdev),
                   -  + ]
     588                 :            :                 rdma_domain_supported ? "supports" : "doesn't support");
     589                 :          4 :         free(bdev_domains);
     590                 :            : 
     591                 :          4 :         return rdma_domain_supported;
     592                 :            : }
     593                 :            : 
     594                 :            : static int
     595                 :          8 : allocate_task(uint32_t core, const char *bdev_name)
     596                 :            : {
     597                 :          0 :         char thread_name[32];
     598                 :          0 :         struct spdk_cpuset cpu_set;
     599                 :            :         uint32_t i;
     600                 :            :         struct dma_test_task *task;
     601                 :            :         struct dma_test_req *req;
     602                 :            : 
     603                 :          8 :         task = calloc(1, sizeof(*task));
     604         [ -  + ]:          8 :         if (!task) {
     605   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate per thread task\n");
     606                 :          0 :                 return -ENOMEM;
     607                 :            :         }
     608                 :            : 
     609                 :          8 :         TAILQ_INSERT_TAIL(&g_tasks, task, link);
     610                 :            : 
     611                 :          8 :         task->reqs = calloc(g_queue_depth, sizeof(*task->reqs));
     612         [ -  + ]:          8 :         if (!task->reqs) {
     613   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate requests\n");
     614                 :          0 :                 return -ENOMEM;
     615                 :            :         }
     616                 :            : 
     617         [ +  + ]:        136 :         for (i = 0; i < g_queue_depth; i++) {
     618                 :        128 :                 req = &task->reqs[i];
     619                 :        128 :                 req->task = task;
     620                 :        128 :                 req->iov.iov_len = g_io_size;
     621                 :        128 :                 req->iov.iov_base = malloc(req->iov.iov_len);
     622         [ -  + ]:        128 :                 if (!req->iov.iov_base) {
     623   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to allocate request data buffer\n");
     624                 :          0 :                         return -ENOMEM;
     625                 :            :                 }
     626         [ -  + ]:        128 :                 memset(req->iov.iov_base, 0xc, req->iov.iov_len);
     627                 :        128 :                 req->io_opts.size = sizeof(req->io_opts);
     628                 :        128 :                 req->io_opts.memory_domain = g_domain;
     629                 :        128 :                 req->io_opts.memory_domain_ctx = req;
     630                 :            :         }
     631                 :            : 
     632         [ -  + ]:          8 :         snprintf(thread_name, 32, "task_%u", core);
     633                 :          8 :         spdk_cpuset_zero(&cpu_set);
     634                 :          8 :         spdk_cpuset_set_cpu(&cpu_set, core, true);
     635                 :          8 :         task->thread = spdk_thread_create(thread_name, &cpu_set);
     636         [ -  + ]:          8 :         if (!task->thread) {
     637   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to create SPDK thread, core %u, cpu_mask %s\n", core,
     638                 :            :                         spdk_cpuset_fmt(&cpu_set));
     639                 :          0 :                 return -ENOMEM;
     640                 :            :         }
     641                 :            : 
     642                 :          8 :         task->seed = core;
     643                 :          8 :         task->lcore = core;
     644                 :          8 :         task->bdev_name = bdev_name;
     645         [ -  + ]:          8 :         task->is_random = g_is_random;
     646                 :          8 :         task->rw_percentage = g_rw_percentage;
     647                 :          8 :         task->num_blocks_per_io = g_num_blocks_per_io;
     648                 :          8 :         task->stats.min_tsc = UINT64_MAX;
     649                 :            : 
     650                 :          8 :         return 0;
     651                 :            : }
     652                 :            : 
     653                 :            : static void
     654                 :          8 : destroy_task(struct dma_test_task *task)
     655                 :            : {
     656                 :            :         struct dma_test_req *req;
     657                 :            :         uint32_t i;
     658                 :            : 
     659         [ +  + ]:        136 :         for (i = 0; i < g_queue_depth; i++) {
     660                 :        128 :                 req = &task->reqs[i];
     661         [ +  + ]:        128 :                 if (req->mr) {
     662                 :         64 :                         ibv_dereg_mr(req->mr);
     663                 :            :                 }
     664                 :        128 :                 free(req->iov.iov_base);
     665                 :            :         }
     666                 :          8 :         free(task->reqs);
     667         [ +  + ]:          8 :         TAILQ_REMOVE(&g_tasks, task, link);
     668                 :          8 :         free(task);
     669                 :          8 : }
     670                 :            : 
     671                 :            : static void
     672                 :          4 : destroy_tasks(void)
     673                 :            : {
     674                 :            :         struct dma_test_task *task, *tmp_task;
     675                 :            : 
     676         [ +  + ]:         12 :         TAILQ_FOREACH_SAFE(task, &g_tasks, link, tmp_task) {
     677                 :          8 :                 destroy_task(task);
     678                 :            :         }
     679                 :          4 : }
     680                 :            : 
     681                 :            : static int
     682                 :          4 : verify_tasks(void)
     683                 :            : {
     684                 :            :         struct dma_test_task *task;
     685                 :          4 :         uint64_t total_requests = 0;
     686                 :          4 :         uint64_t num_translations = 0;
     687                 :          4 :         uint64_t num_pull_push = 0;
     688                 :          4 :         uint64_t num_memzero = 0;
     689                 :          4 :         int rc = 0;
     690                 :            : 
     691         [ -  + ]:          4 :         if (!g_test_ops) {
     692                 :            :                 /* No specific ops were requested, nothing to check */
     693                 :          0 :                 return rc;
     694                 :            :         }
     695                 :            : 
     696         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     697                 :          8 :                 total_requests += task->stats.io_completed;
     698                 :          8 :                 num_translations += task->num_translations;
     699                 :          8 :                 num_pull_push += task->num_pull_push;
     700                 :          8 :                 num_memzero += task->num_mem_zero;
     701                 :            :         }
     702                 :            : 
     703         [ +  + ]:          4 :         if (g_test_ops & DMA_TEST_DOMAIN_OP_TRANSLATE) {
     704         [ -  + ]:          2 :                 if (num_translations == 0) {
     705   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Requested \"translate\" operation, but it was not executed\n");
     706                 :          0 :                         rc = -EINVAL;
     707                 :            :                 }
     708                 :            :         }
     709         [ +  + ]:          4 :         if (g_test_ops & DMA_TEST_DOMAIN_OP_PULL_PUSH) {
     710         [ -  + ]:          1 :                 if (num_pull_push == 0) {
     711   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Requested \"pull_push\" operation, but it was not executed\n");
     712                 :          0 :                         rc = -EINVAL;
     713                 :            :                 }
     714                 :            :         }
     715         [ +  + ]:          4 :         if (g_test_ops & DMA_TEST_DOMAIN_OP_MEMZERO) {
     716         [ -  + ]:          1 :                 if (num_memzero == 0) {
     717   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Requested \"memzero\" operation, but it was not executed\n");
     718                 :          0 :                         rc = -EINVAL;
     719                 :            :                 }
     720                 :            :         }
     721                 :            : 
     722                 :            :         /* bdev request can be split, so the total number of pull_push +translate operations
     723                 :            :          * can be bigger than total_number of requests */
     724         [ -  + ]:          4 :         if (num_translations + num_pull_push + num_memzero < total_requests) {
     725   [ #  #  #  # ]:          0 :                 fprintf(stderr,
     726                 :            :                         "Operations number mismatch: translate %"PRIu64", pull_push %"PRIu64", mem_zero %"PRIu64" expected total %"PRIu64"\n",
     727                 :            :                         num_translations, num_pull_push, num_memzero, total_requests);
     728                 :          0 :                 rc = -EINVAL;
     729                 :            :         } else {
     730   [ -  +  -  + ]:          4 :                 fprintf(stdout,
     731                 :            :                         "Total operations: %"PRIu64", translate %"PRIu64" pull_push %"PRIu64" memzero %"PRIu64"\n",
     732                 :            :                         total_requests, num_translations, num_pull_push, num_memzero);
     733                 :            :         }
     734                 :            : 
     735                 :          4 :         return rc;
     736                 :            : }
     737                 :            : 
     738                 :            : static void
     739                 :          4 : dma_test_start(void *arg)
     740                 :            : {
     741                 :          0 :         struct spdk_bdev_desc *desc;
     742                 :            :         struct spdk_bdev *bdev;
     743                 :            :         struct dma_test_task *task;
     744                 :            :         uint32_t block_size, i;
     745                 :            :         int rc;
     746                 :            : 
     747                 :          4 :         rc = spdk_bdev_open_ext(g_bdev_name, true, dma_test_bdev_dummy_event_cb, NULL, &desc);
     748         [ -  + ]:          4 :         if (rc) {
     749   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Can't find bdev %s\n", g_bdev_name);
     750                 :          0 :                 spdk_app_stop(-ENODEV);
     751                 :          0 :                 return;
     752                 :            :         }
     753                 :          4 :         bdev = spdk_bdev_desc_get_bdev(desc);
     754                 :            :         /* This function checks if bdev supports memory domains. Test is not failed if there are
     755                 :            :          * no memory domains since bdev layer can pull/push data */
     756   [ +  +  -  +  :          4 :         if (!dma_test_check_bdev_supports_rdma_memory_domain(bdev) && g_force_memory_domains_support) {
                   -  + ]
     757   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Test aborted due to \"-f\" (force memory domains support) option\n");
     758                 :          0 :                 spdk_bdev_close(desc);
     759                 :          0 :                 spdk_app_stop(-ENODEV);
     760                 :          0 :                 return;
     761                 :            :         }
     762                 :            : 
     763                 :          4 :         g_main_thread = spdk_get_thread();
     764                 :            : 
     765                 :          4 :         block_size = spdk_bdev_get_block_size(bdev);
     766   [ +  -  -  +  :          4 :         if (g_io_size < block_size || g_io_size % block_size != 0) {
                   -  + ]
     767   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Invalid io_size %u requested, bdev block size %u\n", g_io_size, block_size);
     768                 :          0 :                 spdk_bdev_close(desc);
     769                 :          0 :                 spdk_app_stop(-EINVAL);
     770                 :          0 :                 return;
     771                 :            :         }
     772         [ -  + ]:          4 :         g_num_blocks_per_io = g_io_size / block_size;
     773                 :            : 
     774                 :            :         /* Create a memory domain to represent the source memory domain.
     775                 :            :          * Since we don't actually have a remote memory domain in this test, this will describe memory
     776                 :            :          * on the local system and the translation to the destination memory domain will be trivial.
     777                 :            :          * But this at least allows us to demonstrate the flow and test the functionality. */
     778                 :          4 :         rc = spdk_memory_domain_create(&g_domain, SPDK_DMA_DEVICE_TYPE_RDMA, NULL, "test_dma");
     779         [ -  + ]:          4 :         if (rc != 0) {
     780                 :          0 :                 spdk_bdev_close(desc);
     781                 :          0 :                 spdk_app_stop(rc);
     782                 :          0 :                 return;
     783                 :            :         }
     784                 :          4 :         spdk_memory_domain_set_translation(g_domain, dma_test_translate_memory_cb);
     785                 :          4 :         spdk_memory_domain_set_pull(g_domain, dma_test_pull_memory_cb);
     786                 :          4 :         spdk_memory_domain_set_push(g_domain, dma_test_push_memory_cb);
     787                 :          4 :         spdk_memory_domain_set_memzero(g_domain, dma_test_memzero_cb);
     788                 :            : 
     789         [ +  + ]:         12 :         SPDK_ENV_FOREACH_CORE(i) {
     790                 :          8 :                 rc = allocate_task(i, g_bdev_name);
     791         [ -  + ]:          8 :                 if (rc) {
     792                 :          0 :                         destroy_tasks();
     793                 :          0 :                         spdk_bdev_close(desc);
     794                 :          0 :                         spdk_app_stop(rc);
     795                 :          0 :                         return;
     796                 :            :                 }
     797                 :          8 :                 g_num_construct_tasks++;
     798                 :          8 :                 g_num_complete_tasks++;
     799                 :            :         }
     800                 :            : 
     801         [ +  + ]:         12 :         TAILQ_FOREACH(task, &g_tasks, link) {
     802                 :          8 :                 spdk_thread_send_msg(task->thread, dma_test_construct_task_on_thread, task);
     803                 :            :         }
     804                 :            : 
     805                 :          4 :         spdk_bdev_close(desc);
     806                 :            : }
     807                 :            : 
     808                 :            : static void
     809                 :          0 : print_usage(void)
     810                 :            : {
     811         [ #  # ]:          0 :         printf(" -b <bdev>         bdev name for test\n");
     812         [ #  # ]:          0 :         printf(" -f                force memory domains support - abort test if bdev doesn't report memory domains\n");
     813         [ #  # ]:          0 :         printf(" -q <val>          io depth\n");
     814         [ #  # ]:          0 :         printf(" -o <val>          io size in bytes\n");
     815         [ #  # ]:          0 :         printf(" -t <val>          run time in seconds\n");
     816         [ #  # ]:          0 :         printf(" -x <op,op>        Comma separated memory domain operations expected in the test. Values are \"translate\" and \"pull_push\"\n");
     817         [ #  # ]:          0 :         printf(" -w <str>          io pattern (read, write, randread, randwrite, randrw)\n");
     818         [ #  # ]:          0 :         printf(" -M <0-100>        rw percentage (100 for reads, 0 for writes)\n");
     819                 :          0 : }
     820                 :            : 
     821                 :            : static int
     822                 :          4 : parse_expected_ops(const char *_str)
     823                 :            : {
     824         [ -  + ]:          4 :         char *str = strdup(_str);
     825                 :            :         char *tok;
     826                 :          4 :         int rc = 0;
     827                 :            : 
     828         [ -  + ]:          4 :         if (!str) {
     829         [ #  # ]:          0 :                 fprintf(stderr, "Failed to dup args\n");
     830                 :          0 :                 return -ENOMEM;
     831                 :            :         }
     832                 :            : 
     833                 :          4 :         tok = strtok(str, ",");
     834         [ +  + ]:          8 :         while (tok) {
     835   [ -  +  +  + ]:          4 :                 if (strcmp(tok, "translate") == 0) {
     836                 :          2 :                         g_test_ops |= DMA_TEST_DOMAIN_OP_TRANSLATE;
     837   [ -  +  +  + ]:          2 :                 } else if (strcmp(tok, "pull_push") == 0) {
     838                 :          1 :                         g_test_ops |= DMA_TEST_DOMAIN_OP_PULL_PUSH;
     839   [ -  +  +  - ]:          1 :                 } else if (strcmp(tok, "memzero") == 0) {
     840                 :          1 :                         g_test_ops |= DMA_TEST_DOMAIN_OP_MEMZERO;
     841                 :            :                 } else {
     842         [ #  # ]:          0 :                         fprintf(stderr, "Unknown value %s\n", tok);
     843                 :          0 :                         rc = -EINVAL;
     844                 :          0 :                         break;
     845                 :            :                 }
     846                 :          4 :                 tok = strtok(NULL, ",");
     847                 :            :         }
     848                 :            : 
     849                 :          4 :         free(str);
     850                 :            : 
     851   [ +  -  -  + ]:          4 :         if (g_test_ops == 0 || rc) {
     852         [ #  # ]:          0 :                 fprintf(stderr, "-e \"%s\" specified but nothing was parsed\n", _str);
     853                 :          0 :                 return -EINVAL;
     854                 :            :         }
     855                 :            : 
     856                 :          4 :         return rc;
     857                 :            : }
     858                 :            : 
     859                 :            : static int
     860                 :         31 : parse_arg(int ch, char *arg)
     861                 :            : {
     862                 :            :         long tmp;
     863                 :            : 
     864   [ +  +  +  +  :         31 :         switch (ch) {
                   +  - ]
     865                 :         16 :         case 'q':
     866                 :            :         case 'o':
     867                 :            :         case 't':
     868                 :            :         case 'M':
     869                 :         16 :                 tmp = spdk_strtol(arg, 10);
     870         [ -  + ]:         16 :                 if (tmp < 0) {
     871   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Invalid option %c value %s\n", ch, arg);
     872                 :          0 :                         return 1;
     873                 :            :                 }
     874                 :            : 
     875   [ +  +  +  +  :         16 :                 switch (ch) {
                      - ]
     876                 :          4 :                 case 'q':
     877                 :          4 :                         g_queue_depth = (uint32_t) tmp;
     878                 :          4 :                         break;
     879                 :          4 :                 case 'o':
     880                 :          4 :                         g_io_size = (uint32_t) tmp;
     881                 :          4 :                         break;
     882                 :          4 :                 case 't':
     883                 :          4 :                         g_run_time_sec = (uint32_t) tmp;
     884                 :          4 :                         break;
     885                 :          4 :                 case 'M':
     886                 :          4 :                         g_rw_percentage = (uint32_t) tmp;
     887                 :          4 :                         break;
     888                 :            :                 }
     889                 :         16 :                 break;
     890                 :          4 :         case 'w':
     891                 :          4 :                 g_rw_mode_str = arg;
     892                 :          4 :                 break;
     893                 :          4 :         case 'b':
     894                 :          4 :                 g_bdev_name = arg;
     895                 :          4 :                 break;
     896                 :          3 :         case 'f':
     897                 :          3 :                 g_force_memory_domains_support = true;
     898                 :          3 :                 break;
     899                 :          4 :         case 'x':
     900         [ -  + ]:          4 :                 if (parse_expected_ops(arg)) {
     901                 :          0 :                         return 1;
     902                 :            :                 }
     903                 :          4 :                 break;
     904                 :          0 :         default:
     905   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unknown option %c\n", ch);
     906                 :          0 :                 return 1;
     907                 :            :         }
     908                 :            : 
     909                 :         31 :         return 0;
     910                 :            : }
     911                 :            : 
     912                 :            : static int
     913                 :          4 : verify_args(void)
     914                 :            : {
     915                 :          4 :         const char *rw_mode = g_rw_mode_str;
     916                 :            : 
     917         [ -  + ]:          4 :         if (g_queue_depth == 0) {
     918         [ #  # ]:          0 :                 fprintf(stderr, "queue depth (-q) is not set\n");
     919                 :          0 :                 return 1;
     920                 :            :         }
     921         [ -  + ]:          4 :         if (g_io_size == 0) {
     922         [ #  # ]:          0 :                 fprintf(stderr, "io size (-o) is not set\n");
     923                 :          0 :                 return 1;
     924                 :            :         }
     925         [ -  + ]:          4 :         if (g_run_time_sec == 0) {
     926         [ #  # ]:          0 :                 fprintf(stderr, "test run time (-t) is not set\n");
     927                 :          0 :                 return 1;
     928                 :            :         }
     929         [ -  + ]:          4 :         if (!rw_mode) {
     930         [ #  # ]:          0 :                 fprintf(stderr, "io pattern (-w) is not set\n");
     931                 :          0 :                 return 1;
     932                 :            :         }
     933   [ -  +  +  - ]:          4 :         if (strncmp(rw_mode, "rand", 4) == 0) {
     934                 :          4 :                 g_is_random = true;
     935                 :          4 :                 rw_mode = &rw_mode[4];
     936                 :            :         }
     937   [ -  +  +  +  :          4 :         if (strcmp(rw_mode, "read") == 0 || strcmp(rw_mode, "write") == 0) {
             -  +  -  + ]
     938         [ +  - ]:          1 :                 if (g_rw_percentage > 0) {
     939         [ -  + ]:          1 :                         fprintf(stderr, "Ignoring -M option\n");
     940                 :            :                 }
     941   [ -  +  +  - ]:          1 :                 g_rw_percentage = strcmp(rw_mode, "read") == 0 ? 100 : 0;
     942   [ -  +  +  - ]:          3 :         } else if (strcmp(rw_mode, "rw") == 0) {
     943   [ +  -  -  + ]:          3 :                 if (g_rw_percentage < 0 || g_rw_percentage > 100) {
     944         [ #  # ]:          0 :                         fprintf(stderr, "Invalid -M value (%d) must be 0..100\n", g_rw_percentage);
     945                 :          0 :                         return 1;
     946                 :            :                 }
     947                 :            :         } else {
     948         [ #  # ]:          0 :                 fprintf(stderr, "io pattern (-w) one of [read, write, randread, randwrite, rw, randrw]\n");
     949                 :          0 :                 return 1;
     950                 :            :         }
     951         [ -  + ]:          4 :         if (!g_bdev_name) {
     952         [ #  # ]:          0 :                 fprintf(stderr, "bdev name (-b) is not set\n");
     953                 :          0 :                 return 1;
     954                 :            :         }
     955                 :            : 
     956                 :          4 :         return 0;
     957                 :            : }
     958                 :            : 
     959                 :            : int
     960                 :          4 : main(int argc, char **argv)
     961                 :            : {
     962                 :          4 :         struct spdk_app_opts opts = {};
     963                 :            :         int rc;
     964                 :            : 
     965                 :          4 :         spdk_app_opts_init(&opts, sizeof(opts));
     966                 :          4 :         opts.name = "test_dma";
     967                 :          4 :         opts.shutdown_cb = dma_test_shutdown_cb;
     968                 :          4 :         opts.rpc_addr = NULL;
     969                 :            : 
     970                 :          4 :         rc = spdk_app_parse_args(argc, argv, &opts, "b:fq:o:t:x:w:M:", NULL, parse_arg, print_usage);
     971         [ -  + ]:          4 :         if (rc != SPDK_APP_PARSE_ARGS_SUCCESS) {
     972                 :          0 :                 exit(rc);
     973                 :            :         }
     974                 :            : 
     975                 :          4 :         rc = verify_args();
     976         [ -  + ]:          4 :         if (rc) {
     977                 :          0 :                 exit(rc);
     978                 :            :         }
     979                 :            : 
     980                 :          4 :         rc = spdk_app_start(&opts, dma_test_start, NULL);
     981         [ +  - ]:          4 :         if (rc == 0) {
     982                 :          4 :                 rc = verify_tasks();
     983                 :            :         }
     984                 :          4 :         destroy_tasks();
     985                 :          4 :         spdk_app_fini();
     986                 :            : 
     987                 :          4 :         return rc;
     988                 :            : }

Generated by: LCOV version 1.14