LCOV - code coverage report
Current view: top level - spdk/test/dma/test_dma - test_dma.c (source / functions) Hit Total Coverage
Test: Combined Lines: 379 707 53.6 %
Date: 2024-12-14 05:47:25 Functions: 31 37 83.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 195 1543 12.6 %

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

Generated by: LCOV version 1.15