LCOV - code coverage report
Current view: top level - spdk/examples/ioat/verify - verify.c (source / functions) Hit Total Coverage
Test: Combined Lines: 182 241 75.5 %
Date: 2024-07-15 10:02:59 Functions: 19 20 95.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 84 189 44.4 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2015 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/ioat.h"
       9                 :            : #include "spdk/env.h"
      10                 :            : #include "spdk/queue.h"
      11                 :            : #include "spdk/string.h"
      12                 :            : #include "spdk/util.h"
      13                 :            : 
      14                 :            : #define SRC_BUFFER_SIZE (512*1024)
      15                 :            : 
      16                 :            : enum ioat_task_type {
      17                 :            :         IOAT_COPY_TYPE,
      18                 :            :         IOAT_FILL_TYPE,
      19                 :            : };
      20                 :            : 
      21                 :            : struct user_config {
      22                 :            :         int queue_depth;
      23                 :            :         int time_in_sec;
      24                 :            :         char *core_mask;
      25                 :            : };
      26                 :            : 
      27                 :            : struct ioat_device {
      28                 :            :         struct spdk_ioat_chan *ioat;
      29                 :            :         TAILQ_ENTRY(ioat_device) tailq;
      30                 :            : };
      31                 :            : 
      32                 :            : static TAILQ_HEAD(, ioat_device) g_devices = TAILQ_HEAD_INITIALIZER(g_devices);
      33                 :            : static struct ioat_device *g_next_device;
      34                 :            : 
      35                 :            : static struct user_config g_user_config;
      36                 :            : 
      37                 :            : struct thread_entry {
      38                 :            :         struct spdk_ioat_chan *chan;
      39                 :            :         uint64_t xfer_completed;
      40                 :            :         uint64_t xfer_failed;
      41                 :            :         uint64_t fill_completed;
      42                 :            :         uint64_t fill_failed;
      43                 :            :         uint64_t current_queue_depth;
      44                 :            :         unsigned lcore_id;
      45                 :            :         bool is_draining;
      46                 :            :         bool init_failed;
      47                 :            :         struct spdk_mempool *data_pool;
      48                 :            :         struct spdk_mempool *task_pool;
      49                 :            : };
      50                 :            : 
      51                 :            : struct ioat_task {
      52                 :            :         enum ioat_task_type type;
      53                 :            :         struct thread_entry *thread_entry;
      54                 :            :         void *buffer;
      55                 :            :         int len;
      56                 :            :         uint64_t fill_pattern;
      57                 :            :         void *src;
      58                 :            :         void *dst;
      59                 :            : };
      60                 :            : 
      61                 :            : static __thread unsigned int seed = 0;
      62                 :            : 
      63                 :            : static unsigned char *g_src;
      64                 :            : 
      65                 :            : static void submit_single_xfer(struct ioat_task *ioat_task);
      66                 :            : 
      67                 :            : static void
      68                 :          1 : construct_user_config(struct user_config *self)
      69                 :            : {
      70                 :          1 :         self->queue_depth = 32;
      71                 :          1 :         self->time_in_sec = 10;
      72                 :          1 :         self->core_mask = "0x1";
      73                 :          1 : }
      74                 :            : 
      75                 :            : static void
      76                 :          1 : dump_user_config(struct user_config *self)
      77                 :            : {
      78         [ -  + ]:          1 :         printf("User configuration:\n");
      79         [ -  + ]:          1 :         printf("Run time:       %u seconds\n", self->time_in_sec);
      80         [ -  + ]:          1 :         printf("Core mask:      %s\n", self->core_mask);
      81         [ -  + ]:          1 :         printf("Queue depth:    %u\n", self->queue_depth);
      82                 :          1 : }
      83                 :            : 
      84                 :            : static void
      85                 :          1 : ioat_exit(void)
      86                 :            : {
      87                 :            :         struct ioat_device *dev;
      88                 :            : 
      89         [ +  + ]:         17 :         while (!TAILQ_EMPTY(&g_devices)) {
      90                 :         16 :                 dev = TAILQ_FIRST(&g_devices);
      91         [ +  + ]:         16 :                 TAILQ_REMOVE(&g_devices, dev, tailq);
      92         [ +  - ]:         16 :                 if (dev->ioat) {
      93                 :         16 :                         spdk_ioat_detach(dev->ioat);
      94                 :            :                 }
      95                 :         16 :                 free(dev);
      96                 :            :         }
      97                 :          1 : }
      98                 :            : static void
      99                 :       1087 : prepare_ioat_task(struct thread_entry *thread_entry, struct ioat_task *ioat_task)
     100                 :            : {
     101                 :            :         int len;
     102                 :            :         uintptr_t src_offset;
     103                 :            :         uintptr_t dst_offset;
     104                 :            :         uint64_t fill_pattern;
     105                 :            : 
     106         [ +  + ]:       1087 :         if (ioat_task->type == IOAT_FILL_TYPE) {
     107                 :        544 :                 fill_pattern = rand_r(&seed);
     108                 :        544 :                 fill_pattern = fill_pattern << 32 | rand_r(&seed);
     109                 :            : 
     110                 :            :                 /* Ensure that the length of memset block is 8 Bytes aligned.
     111                 :            :                  * In case the buffer crosses hugepage boundary and must be split,
     112                 :            :                  * we also need to ensure 8 byte address alignment. We do it
     113                 :            :                  * unconditionally to keep things simple.
     114                 :            :                  */
     115                 :        544 :                 len = 8 + ((rand_r(&seed) % (SRC_BUFFER_SIZE - 16)) & ~0x7);
     116         [ -  + ]:        544 :                 dst_offset = 8 + rand_r(&seed) % (SRC_BUFFER_SIZE - 8 - len);
     117                 :        544 :                 ioat_task->fill_pattern = fill_pattern;
     118                 :        544 :                 ioat_task->dst = (void *)(((uintptr_t)ioat_task->buffer + dst_offset) & ~0x7);
     119                 :            :         } else {
     120                 :        543 :                 src_offset = rand_r(&seed) % SRC_BUFFER_SIZE;
     121         [ -  + ]:        543 :                 len = rand_r(&seed) % (SRC_BUFFER_SIZE - src_offset);
     122         [ -  + ]:        543 :                 dst_offset = rand_r(&seed) % (SRC_BUFFER_SIZE - len);
     123                 :            : 
     124         [ -  + ]:        543 :                 memset(ioat_task->buffer, 0, SRC_BUFFER_SIZE);
     125                 :        543 :                 ioat_task->src = (void *)((uintptr_t)g_src + src_offset);
     126                 :        543 :                 ioat_task->dst = (void *)((uintptr_t)ioat_task->buffer + dst_offset);
     127                 :            :         }
     128                 :       1087 :         ioat_task->len = len;
     129                 :       1087 :         ioat_task->thread_entry = thread_entry;
     130                 :       1087 : }
     131                 :            : 
     132                 :            : static void
     133                 :       1087 : ioat_done(void *cb_arg)
     134                 :            : {
     135                 :            :         char *value;
     136                 :       1087 :         int i, failed = 0;
     137                 :       1087 :         struct ioat_task *ioat_task = (struct ioat_task *)cb_arg;
     138                 :       1087 :         struct thread_entry *thread_entry = ioat_task->thread_entry;
     139                 :            : 
     140         [ +  + ]:       1087 :         if (ioat_task->type == IOAT_FILL_TYPE) {
     141                 :        544 :                 value = ioat_task->dst;
     142         [ +  + ]:   18723833 :                 for (i = 0; i < ioat_task->len / 8; i++) {
     143   [ -  +  -  +  :   18723289 :                         if (memcmp(value, &ioat_task->fill_pattern, 8) != 0) {
                   -  + ]
     144                 :          0 :                                 thread_entry->fill_failed++;
     145                 :          0 :                                 failed = 1;
     146                 :          0 :                                 break;
     147                 :            :                         }
     148                 :   18723289 :                         value += 8;
     149                 :            :                 }
     150         [ +  - ]:        544 :                 if (!failed) {
     151                 :        544 :                         thread_entry->fill_completed++;
     152                 :            :                 }
     153                 :            :         } else {
     154   [ -  +  -  +  :        543 :                 if (memcmp(ioat_task->src, ioat_task->dst, ioat_task->len)) {
                   -  + ]
     155                 :          0 :                         thread_entry->xfer_failed++;
     156                 :            :                 } else {
     157                 :        543 :                         thread_entry->xfer_completed++;
     158                 :            :                 }
     159                 :            :         }
     160                 :            : 
     161                 :       1087 :         thread_entry->current_queue_depth--;
     162   [ -  +  +  + ]:       1087 :         if (thread_entry->is_draining) {
     163                 :         32 :                 spdk_mempool_put(thread_entry->data_pool, ioat_task->buffer);
     164                 :         32 :                 spdk_mempool_put(thread_entry->task_pool, ioat_task);
     165                 :            :         } else {
     166                 :       1055 :                 prepare_ioat_task(thread_entry, ioat_task);
     167                 :       1055 :                 submit_single_xfer(ioat_task);
     168                 :            :         }
     169                 :       1087 : }
     170                 :            : 
     171                 :            : static bool
     172                 :         16 : probe_cb(void *cb_ctx, struct spdk_pci_device *pci_dev)
     173                 :            : {
     174         [ -  + ]:         16 :         printf(" Found matching device at %04x:%02x:%02x.%x "
     175                 :            :                "vendor:0x%04x device:0x%04x\n",
     176                 :            :                spdk_pci_device_get_domain(pci_dev),
     177                 :         16 :                spdk_pci_device_get_bus(pci_dev), spdk_pci_device_get_dev(pci_dev),
     178                 :         16 :                spdk_pci_device_get_func(pci_dev),
     179                 :         16 :                spdk_pci_device_get_vendor_id(pci_dev), spdk_pci_device_get_device_id(pci_dev));
     180                 :            : 
     181                 :         16 :         return true;
     182                 :            : }
     183                 :            : 
     184                 :            : static void
     185                 :         16 : attach_cb(void *cb_ctx, struct spdk_pci_device *pci_dev, struct spdk_ioat_chan *ioat)
     186                 :            : {
     187                 :            :         struct ioat_device *dev;
     188                 :            : 
     189                 :         16 :         dev = malloc(sizeof(*dev));
     190         [ -  + ]:         16 :         if (dev == NULL) {
     191         [ #  # ]:          0 :                 printf("Failed to allocate device struct\n");
     192                 :          0 :                 return;
     193                 :            :         }
     194         [ -  + ]:         16 :         memset(dev, 0, sizeof(*dev));
     195                 :            : 
     196                 :         16 :         dev->ioat = ioat;
     197                 :         16 :         TAILQ_INSERT_TAIL(&g_devices, dev, tailq);
     198                 :            : }
     199                 :            : 
     200                 :            : static int
     201                 :          1 : ioat_init(void)
     202                 :            : {
     203         [ -  + ]:          1 :         if (spdk_ioat_probe(NULL, probe_cb, attach_cb) != 0) {
     204   [ #  #  #  # ]:          0 :                 fprintf(stderr, "ioat_probe() failed\n");
     205                 :          0 :                 return 1;
     206                 :            :         }
     207                 :            : 
     208                 :          1 :         return 0;
     209                 :            : }
     210                 :            : 
     211                 :            : static void
     212                 :          0 : usage(char *program_name)
     213                 :            : {
     214         [ #  # ]:          0 :         printf("%s options\n", program_name);
     215         [ #  # ]:          0 :         printf("\t[-h help message]\n");
     216         [ #  # ]:          0 :         printf("\t[-c core mask for distributing I/O submission/completion work]\n");
     217         [ #  # ]:          0 :         printf("\t[-t time in seconds]\n");
     218         [ #  # ]:          0 :         printf("\t[-q queue depth]\n");
     219                 :          0 : }
     220                 :            : 
     221                 :            : static int
     222                 :          1 : parse_args(int argc, char **argv)
     223                 :            : {
     224                 :            :         int op;
     225                 :            : 
     226                 :          1 :         construct_user_config(&g_user_config);
     227   [ -  +  -  +  :          2 :         while ((op = getopt(argc, argv, "c:ht:q:")) != -1) {
                   +  + ]
     228   [ +  -  -  -  :          1 :                 switch (op) {
                      - ]
     229                 :          1 :                 case 't':
     230                 :          1 :                         g_user_config.time_in_sec = spdk_strtol(optarg, 10);
     231                 :          1 :                         break;
     232                 :          0 :                 case 'c':
     233                 :          0 :                         g_user_config.core_mask = optarg;
     234                 :          0 :                         break;
     235                 :          0 :                 case 'q':
     236                 :          0 :                         g_user_config.queue_depth = spdk_strtol(optarg, 10);
     237                 :          0 :                         break;
     238                 :          0 :                 case 'h':
     239                 :          0 :                         usage(argv[0]);
     240                 :          0 :                         exit(0);
     241                 :          0 :                 default:
     242                 :          0 :                         usage(argv[0]);
     243                 :          0 :                         return 1;
     244                 :            :                 }
     245                 :            :         }
     246   [ +  -  +  - ]:          1 :         if (g_user_config.time_in_sec <= 0 || !g_user_config.core_mask ||
     247         [ -  + ]:          1 :             g_user_config.queue_depth <= 0) {
     248                 :          0 :                 usage(argv[0]);
     249                 :          0 :                 return 1;
     250                 :            :         }
     251                 :            : 
     252                 :          1 :         return 0;
     253                 :            : }
     254                 :            : 
     255                 :            : static void
     256                 :          1 : drain_xfers(struct thread_entry *thread_entry)
     257                 :            : {
     258         [ +  + ]:          3 :         while (thread_entry->current_queue_depth > 0) {
     259                 :          2 :                 spdk_ioat_process_events(thread_entry->chan);
     260                 :            :         }
     261                 :          1 : }
     262                 :            : 
     263                 :            : static void
     264                 :       1087 : submit_single_xfer(struct ioat_task *ioat_task)
     265                 :            : {
     266         [ +  + ]:       1087 :         if (ioat_task->type == IOAT_FILL_TYPE)
     267                 :        544 :                 spdk_ioat_submit_fill(ioat_task->thread_entry->chan, ioat_task, ioat_done,
     268                 :        544 :                                       ioat_task->dst, ioat_task->fill_pattern, ioat_task->len);
     269                 :            :         else
     270                 :        543 :                 spdk_ioat_submit_copy(ioat_task->thread_entry->chan, ioat_task, ioat_done,
     271                 :        543 :                                       ioat_task->dst, ioat_task->src, ioat_task->len);
     272                 :       1087 :         ioat_task->thread_entry->current_queue_depth++;
     273                 :       1087 : }
     274                 :            : 
     275                 :            : static void
     276                 :          1 : submit_xfers(struct thread_entry *thread_entry, uint64_t queue_depth)
     277                 :            : {
     278         [ +  + ]:         33 :         while (queue_depth-- > 0) {
     279                 :         32 :                 struct ioat_task *ioat_task = NULL;
     280                 :         32 :                 ioat_task = spdk_mempool_get(thread_entry->task_pool);
     281         [ -  + ]:         32 :                 assert(ioat_task != NULL);
     282                 :         32 :                 ioat_task->buffer = spdk_mempool_get(thread_entry->data_pool);
     283         [ -  + ]:         32 :                 assert(ioat_task->buffer != NULL);
     284                 :            : 
     285                 :         32 :                 ioat_task->type = IOAT_COPY_TYPE;
     286         [ +  - ]:         32 :                 if (spdk_ioat_get_dma_capabilities(thread_entry->chan) & SPDK_IOAT_ENGINE_FILL_SUPPORTED) {
     287         [ +  + ]:         32 :                         if (queue_depth % 2) {
     288                 :         16 :                                 ioat_task->type = IOAT_FILL_TYPE;
     289                 :            :                         }
     290                 :            :                 }
     291                 :         32 :                 prepare_ioat_task(thread_entry, ioat_task);
     292                 :         32 :                 submit_single_xfer(ioat_task);
     293                 :            :         }
     294                 :          1 : }
     295                 :            : 
     296                 :            : static int
     297                 :          1 : work_fn(void *arg)
     298                 :            : {
     299                 :            :         uint64_t tsc_end;
     300                 :          0 :         char buf_pool_name[20], task_pool_name[20];
     301                 :          1 :         struct thread_entry *t = (struct thread_entry *)arg;
     302                 :            : 
     303         [ -  + ]:          1 :         if (!t->chan) {
     304                 :          0 :                 return 1;
     305                 :            :         }
     306                 :            : 
     307                 :          1 :         t->lcore_id = spdk_env_get_current_core();
     308                 :            : 
     309         [ -  + ]:          1 :         snprintf(buf_pool_name, sizeof(buf_pool_name), "buf_pool_%u", t->lcore_id);
     310         [ -  + ]:          1 :         snprintf(task_pool_name, sizeof(task_pool_name), "task_pool_%u", t->lcore_id);
     311                 :          1 :         t->data_pool = spdk_mempool_create(buf_pool_name, g_user_config.queue_depth, SRC_BUFFER_SIZE,
     312                 :            :                                            SPDK_MEMPOOL_DEFAULT_CACHE_SIZE,
     313                 :            :                                            SPDK_ENV_SOCKET_ID_ANY);
     314                 :          1 :         t->task_pool = spdk_mempool_create(task_pool_name, g_user_config.queue_depth,
     315                 :            :                                            sizeof(struct ioat_task),
     316                 :            :                                            SPDK_MEMPOOL_DEFAULT_CACHE_SIZE,
     317                 :            :                                            SPDK_ENV_SOCKET_ID_ANY);
     318   [ +  -  -  + ]:          1 :         if (!t->data_pool || !t->task_pool) {
     319   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not allocate buffer pool.\n");
     320                 :          0 :                 t->init_failed = true;
     321                 :          0 :                 return 1;
     322                 :            :         }
     323                 :            : 
     324                 :          1 :         tsc_end = spdk_get_ticks() + g_user_config.time_in_sec * spdk_get_ticks_hz();
     325                 :            : 
     326                 :          1 :         submit_xfers(t, g_user_config.queue_depth);
     327         [ +  + ]:         35 :         while (spdk_get_ticks() < tsc_end) {
     328                 :         34 :                 spdk_ioat_process_events(t->chan);
     329                 :            :         }
     330                 :            : 
     331                 :          1 :         t->is_draining = true;
     332                 :          1 :         drain_xfers(t);
     333                 :            : 
     334                 :          1 :         return 0;
     335                 :            : }
     336                 :            : 
     337                 :            : static int
     338                 :          1 : init_src_buffer(void)
     339                 :            : {
     340                 :            :         int i;
     341                 :            : 
     342                 :          1 :         g_src = spdk_dma_zmalloc(SRC_BUFFER_SIZE, 512, NULL);
     343         [ -  + ]:          1 :         if (g_src == NULL) {
     344   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Allocate src buffer failed\n");
     345                 :          0 :                 return 1;
     346                 :            :         }
     347                 :            : 
     348         [ +  + ]:     131073 :         for (i = 0; i < SRC_BUFFER_SIZE / 4; i++) {
     349         [ -  + ]:     131072 :                 memset((g_src + (4 * i)), i, 4);
     350                 :            :         }
     351                 :            : 
     352                 :          1 :         return 0;
     353                 :            : }
     354                 :            : 
     355                 :            : static int
     356                 :          1 : init(void)
     357                 :            : {
     358                 :          0 :         struct spdk_env_opts opts;
     359                 :            : 
     360                 :          1 :         spdk_env_opts_init(&opts);
     361                 :          1 :         opts.name = "verify";
     362                 :          1 :         opts.core_mask = g_user_config.core_mask;
     363         [ -  + ]:          1 :         if (spdk_env_init(&opts) < 0) {
     364   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to initialize SPDK env\n");
     365                 :          0 :                 return 1;
     366                 :            :         }
     367                 :            : 
     368         [ -  + ]:          1 :         if (init_src_buffer() != 0) {
     369   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not init src buffer\n");
     370                 :          0 :                 return 1;
     371                 :            :         }
     372         [ -  + ]:          1 :         if (ioat_init() != 0) {
     373   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not init ioat\n");
     374                 :          0 :                 return 1;
     375                 :            :         }
     376                 :            : 
     377                 :          1 :         return 0;
     378                 :            : }
     379                 :            : 
     380                 :            : static int
     381                 :          1 : dump_result(struct thread_entry *threads, uint32_t num_threads)
     382                 :            : {
     383                 :            :         uint32_t i;
     384                 :          1 :         uint64_t total_completed = 0;
     385                 :          1 :         uint64_t total_failed = 0;
     386                 :            : 
     387         [ +  + ]:          2 :         for (i = 0; i < num_threads; i++) {
     388                 :          1 :                 struct thread_entry *t = &threads[i];
     389                 :            : 
     390         [ -  + ]:          1 :                 if (!t->chan) {
     391                 :          0 :                         continue;
     392                 :            :                 }
     393                 :            : 
     394   [ -  +  -  + ]:          1 :                 if (t->init_failed) {
     395                 :          0 :                         total_failed++;
     396                 :          0 :                         continue;
     397                 :            :                 }
     398                 :            : 
     399                 :          1 :                 total_completed += t->xfer_completed;
     400                 :          1 :                 total_completed += t->fill_completed;
     401                 :          1 :                 total_failed += t->xfer_failed;
     402                 :          1 :                 total_failed += t->fill_failed;
     403   [ -  +  -  - ]:          1 :                 if (total_completed || total_failed)
     404         [ -  + ]:          1 :                         printf("lcore = %d, copy success = %" PRIu64 ", copy failed = %" PRIu64 ", fill success = %" PRIu64
     405                 :            :                                ", fill failed = %" PRIu64 "\n",
     406                 :            :                                t->lcore_id, t->xfer_completed, t->xfer_failed, t->fill_completed, t->fill_failed);
     407                 :            :         }
     408                 :          1 :         return total_failed ? 1 : 0;
     409                 :            : }
     410                 :            : 
     411                 :            : static struct spdk_ioat_chan *
     412                 :          1 : get_next_chan(void)
     413                 :            : {
     414                 :            :         struct spdk_ioat_chan *chan;
     415                 :            : 
     416         [ -  + ]:          1 :         if (g_next_device == NULL) {
     417   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Not enough ioat channels found. Check that ioat channels are bound\n");
     418   [ #  #  #  # ]:          0 :                 fprintf(stderr, "to uio_pci_generic or vfio-pci.  scripts/setup.sh can help with this.\n");
     419                 :          0 :                 return NULL;
     420                 :            :         }
     421                 :            : 
     422                 :          1 :         chan = g_next_device->ioat;
     423                 :            : 
     424                 :          1 :         g_next_device = TAILQ_NEXT(g_next_device, tailq);
     425                 :            : 
     426                 :          1 :         return chan;
     427                 :            : }
     428                 :            : 
     429                 :            : static uint32_t
     430                 :          1 : get_max_core(void)
     431                 :            : {
     432                 :            :         uint32_t i;
     433                 :          1 :         uint32_t max_core = 0;
     434                 :            : 
     435         [ +  + ]:          2 :         SPDK_ENV_FOREACH_CORE(i) {
     436         [ -  + ]:          1 :                 if (i > max_core) {
     437                 :          0 :                         max_core = i;
     438                 :            :                 }
     439                 :            :         }
     440                 :            : 
     441                 :          1 :         return max_core;
     442                 :            : }
     443                 :            : 
     444                 :            : int
     445                 :          1 : main(int argc, char **argv)
     446                 :            : {
     447                 :            :         uint32_t i, current_core;
     448                 :            :         struct thread_entry *threads;
     449                 :            :         uint32_t num_threads;
     450                 :            :         int rc;
     451                 :            : 
     452         [ -  + ]:          1 :         if (parse_args(argc, argv) != 0) {
     453                 :          0 :                 return 1;
     454                 :            :         }
     455                 :            : 
     456         [ -  + ]:          1 :         if (init() != 0) {
     457                 :          0 :                 return 1;
     458                 :            :         }
     459                 :            : 
     460                 :          1 :         dump_user_config(&g_user_config);
     461                 :            : 
     462                 :          1 :         g_next_device = TAILQ_FIRST(&g_devices);
     463                 :            : 
     464                 :          1 :         num_threads = get_max_core() + 1;
     465                 :          1 :         threads = calloc(num_threads, sizeof(*threads));
     466         [ -  + ]:          1 :         if (!threads) {
     467   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Thread memory allocation failed\n");
     468                 :          0 :                 rc = 1;
     469                 :          0 :                 goto cleanup;
     470                 :            :         }
     471                 :            : 
     472                 :          1 :         current_core = spdk_env_get_current_core();
     473         [ +  + ]:          2 :         SPDK_ENV_FOREACH_CORE(i) {
     474         [ -  + ]:          1 :                 if (i != current_core) {
     475                 :          0 :                         threads[i].chan = get_next_chan();
     476                 :          0 :                         spdk_env_thread_launch_pinned(i, work_fn, &threads[i]);
     477                 :            :                 }
     478                 :            :         }
     479                 :            : 
     480                 :          1 :         threads[current_core].chan = get_next_chan();
     481         [ -  + ]:          1 :         if (work_fn(&threads[current_core]) != 0) {
     482                 :          0 :                 rc = 1;
     483                 :          0 :                 goto cleanup;
     484                 :            :         }
     485                 :            : 
     486                 :          1 :         spdk_env_thread_wait_all();
     487                 :          1 :         rc = dump_result(threads, num_threads);
     488                 :            : 
     489                 :          1 : cleanup:
     490                 :          1 :         spdk_dma_free(g_src);
     491                 :          1 :         ioat_exit();
     492                 :          1 :         free(threads);
     493                 :            : 
     494                 :          1 :         spdk_env_fini();
     495                 :          1 :         return rc;
     496                 :            : }

Generated by: LCOV version 1.14