LCOV - code coverage report
Current view: top level - spdk/examples/idxd/perf - perf.c (source / functions) Hit Total Coverage
Test: Combined Lines: 0 565 0.0 %
Date: 2024-07-14 11:50:42 Functions: 0 27 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 497 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2021 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/idxd.h"
       7                 :            : #include "spdk/stdinc.h"
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/event.h"
      10                 :            : #include "spdk/log.h"
      11                 :            : #include "spdk/string.h"
      12                 :            : #include "spdk/crc32.h"
      13                 :            : #include "spdk/util.h"
      14                 :            : 
      15                 :            : enum idxd_capability {
      16                 :            :         IDXD_COPY = 1,
      17                 :            :         IDXD_FILL,
      18                 :            :         IDXD_DUALCAST,
      19                 :            :         IDXD_COMPARE,
      20                 :            :         IDXD_CRC32C,
      21                 :            :         IDXD_DIF,
      22                 :            :         IDXD_COPY_CRC32C,
      23                 :            : };
      24                 :            : 
      25                 :            : #define DATA_PATTERN 0x5a
      26                 :            : #define ALIGN_4K 0x1000
      27                 :            : 
      28                 :            : static int g_xfer_size_bytes = 4096;
      29                 :            : 
      30                 :            : /* g_allocate_depth indicates how many tasks we allocate per work_chan. It will
      31                 :            :  * be at least as much as the queue depth.
      32                 :            :  */
      33                 :            : static int g_queue_depth = 32;
      34                 :            : static int g_idxd_max_per_core = 1;
      35                 :            : static char *g_core_mask = "0x1";
      36                 :            : static bool g_idxd_kernel_mode = false;
      37                 :            : static int g_allocate_depth = 0;
      38                 :            : static int g_time_in_sec = 5;
      39                 :            : static uint32_t g_crc32c_seed = 0;
      40                 :            : static uint32_t g_crc32c_chained_count = 1;
      41                 :            : static int g_fail_percent_goal = 0;
      42                 :            : static uint8_t g_fill_pattern = 255;
      43                 :            : static bool g_verify = false;
      44                 :            : static const char *g_workload_type = NULL;
      45                 :            : static enum idxd_capability g_workload_selection;
      46                 :            : static struct worker_thread *g_workers = NULL;
      47                 :            : static int g_num_workers = 0;
      48                 :            : 
      49                 :            : struct worker_thread;
      50                 :            : struct idxd_chan_entry;
      51                 :            : static void idxd_done(void *ref, int status);
      52                 :            : 
      53                 :            : struct idxd_device {
      54                 :            :         struct                          spdk_idxd_device *idxd;
      55                 :            :         TAILQ_ENTRY(idxd_device)        tailq;
      56                 :            : };
      57                 :            : static uint32_t g_num_devices = 0;
      58                 :            : 
      59                 :            : static TAILQ_HEAD(, idxd_device) g_idxd_devices = TAILQ_HEAD_INITIALIZER(g_idxd_devices);
      60                 :            : static struct idxd_device *g_next_device;
      61                 :            : 
      62                 :            : struct idxd_task {
      63                 :            :         void                    *src;
      64                 :            :         struct iovec            *iovs;
      65                 :            :         uint32_t                iov_cnt;
      66                 :            :         void                    *dst;
      67                 :            :         void                    *dst2;
      68                 :            :         uint32_t                crc_dst;
      69                 :            :         struct idxd_chan_entry  *worker_chan;
      70                 :            :         int                     status;
      71                 :            :         int                     expected_status; /* used for the compare operation */
      72                 :            :         TAILQ_ENTRY(idxd_task)  link;
      73                 :            : };
      74                 :            : 
      75                 :            : struct idxd_chan_entry {
      76                 :            :         int                             idxd_chan_id;
      77                 :            :         struct spdk_idxd_io_channel     *ch;
      78                 :            :         uint64_t                        xfer_completed;
      79                 :            :         uint64_t                        xfer_failed;
      80                 :            :         uint64_t                        injected_miscompares;
      81                 :            :         uint64_t                        current_queue_depth;
      82                 :            :         TAILQ_HEAD(, idxd_task)         tasks_pool_head;
      83                 :            :         TAILQ_HEAD(, idxd_task)         resubmits;
      84                 :            :         unsigned                        core;
      85                 :            :         bool                            is_draining;
      86                 :            :         void                            *task_base;
      87                 :            :         struct idxd_chan_entry          *next;
      88                 :            : };
      89                 :            : 
      90                 :            : struct worker_thread {
      91                 :            :         struct idxd_chan_entry  *ctx;
      92                 :            :         struct worker_thread    *next;
      93                 :            :         int                     chan_num;
      94                 :            :         unsigned                core;
      95                 :            : };
      96                 :            : 
      97                 :            : static void
      98                 :          0 : dump_user_config(void)
      99                 :            : {
     100         [ #  # ]:          0 :         printf("SPDK Configuration:\n");
     101         [ #  # ]:          0 :         printf("Core mask:      %s\n\n", g_core_mask);
     102         [ #  # ]:          0 :         printf("Idxd Perf Configuration:\n");
     103         [ #  # ]:          0 :         printf("Workload Type:   %s\n", g_workload_type);
     104   [ #  #  #  # ]:          0 :         if (g_workload_selection == IDXD_CRC32C || g_workload_selection == IDXD_COPY_CRC32C) {
     105         [ #  # ]:          0 :                 printf("CRC-32C seed:    %u\n", g_crc32c_seed);
     106         [ #  # ]:          0 :                 printf("vector count     %u\n", g_crc32c_chained_count);
     107         [ #  # ]:          0 :         } else if (g_workload_selection == IDXD_FILL) {
     108         [ #  # ]:          0 :                 printf("Fill pattern:    0x%x\n", g_fill_pattern);
     109   [ #  #  #  # ]:          0 :         } else if ((g_workload_selection == IDXD_COMPARE) && g_fail_percent_goal > 0) {
     110         [ #  # ]:          0 :                 printf("Failure inject:  %u percent\n", g_fail_percent_goal);
     111                 :            :         }
     112         [ #  # ]:          0 :         if (g_workload_selection == IDXD_COPY_CRC32C) {
     113         [ #  # ]:          0 :                 printf("Vector size:     %u bytes\n", g_xfer_size_bytes);
     114         [ #  # ]:          0 :                 printf("Transfer size:   %u bytes\n", g_xfer_size_bytes * g_crc32c_chained_count);
     115                 :            :         } else {
     116         [ #  # ]:          0 :                 printf("Transfer size:   %u bytes\n", g_xfer_size_bytes);
     117                 :            :         }
     118         [ #  # ]:          0 :         printf("Queue depth:     %u\n", g_queue_depth);
     119         [ #  # ]:          0 :         printf("Allocated depth: %u\n", g_allocate_depth);
     120         [ #  # ]:          0 :         printf("Run time:        %u seconds\n", g_time_in_sec);
     121   [ #  #  #  #  :          0 :         printf("Verify:          %s\n\n", g_verify ? "Yes" : "No");
                   #  # ]
     122                 :          0 : }
     123                 :            : 
     124                 :            : static void
     125                 :          0 : attach_cb(void *cb_ctx, struct spdk_idxd_device *idxd)
     126                 :            : {
     127                 :            :         struct idxd_device *dev;
     128                 :            : 
     129                 :          0 :         dev = calloc(1, sizeof(*dev));
     130         [ #  # ]:          0 :         if (dev == NULL) {
     131   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to allocate device struct\n");
     132                 :          0 :                 return;
     133                 :            :         }
     134                 :            : 
     135                 :          0 :         dev->idxd = idxd;
     136                 :            : 
     137                 :          0 :         TAILQ_INSERT_TAIL(&g_idxd_devices, dev, tailq);
     138                 :          0 :         g_num_devices++;
     139                 :            : }
     140                 :            : 
     141                 :            : static bool
     142                 :          0 : probe_cb(void *cb_ctx, struct spdk_pci_device *dev)
     143                 :            : {
     144                 :            :         /* this tool will gladly claim all types of IDXD devices. */
     145                 :          0 :         return true;
     146                 :            : }
     147                 :            : 
     148                 :            : static int
     149                 :          0 : idxd_init(void)
     150                 :            : {
     151         [ #  # ]:          0 :         spdk_idxd_set_config(g_idxd_kernel_mode);
     152                 :            : 
     153         [ #  # ]:          0 :         if (spdk_idxd_probe(NULL, attach_cb, probe_cb) != 0) {
     154   [ #  #  #  # ]:          0 :                 fprintf(stderr, "spdk_idxd_probe() failed\n");
     155                 :          0 :                 return 1;
     156                 :            :         }
     157                 :            : 
     158                 :          0 :         return 0;
     159                 :            : }
     160                 :            : 
     161                 :            : static void
     162                 :          0 : idxd_exit(void)
     163                 :            : {
     164                 :            :         struct idxd_device *dev;
     165                 :            : 
     166         [ #  # ]:          0 :         while (!TAILQ_EMPTY(&g_idxd_devices)) {
     167                 :          0 :                 dev = TAILQ_FIRST(&g_idxd_devices);
     168         [ #  # ]:          0 :                 TAILQ_REMOVE(&g_idxd_devices, dev, tailq);
     169         [ #  # ]:          0 :                 if (dev->idxd) {
     170                 :          0 :                         spdk_idxd_detach(dev->idxd);
     171                 :            :                 }
     172                 :          0 :                 free(dev);
     173                 :            :         }
     174                 :          0 : }
     175                 :            : 
     176                 :            : static void
     177                 :          0 : usage(void)
     178                 :            : {
     179         [ #  # ]:          0 :         printf("idxd_perf options:\n");
     180         [ #  # ]:          0 :         printf("\t[-h help message]\n");
     181         [ #  # ]:          0 :         printf("\t[-a tasks to allocate per core (default: same value as -q)]\n");
     182         [ #  # ]:          0 :         printf("\t[-C for crc32c workload, use this value to configure the io vector size to test (default 1)\n");
     183         [ #  # ]:          0 :         printf("\t[-f for fill workload, use this BYTE value (default 255)\n");
     184         [ #  # ]:          0 :         printf("\t[-k use kernel idxd driver]\n");
     185         [ #  # ]:          0 :         printf("\t[-m core mask for distributing I/O submission/completion work]\n");
     186         [ #  # ]:          0 :         printf("\t[-o transfer size in bytes]\n");
     187         [ #  # ]:          0 :         printf("\t[-P for compare workload, percentage of operations that should miscompare (percent, default 0)\n");
     188         [ #  # ]:          0 :         printf("\t[-q queue depth per core]\n");
     189         [ #  # ]:          0 :         printf("\t[-r max idxd devices per core can drive (default 1)]\n");
     190         [ #  # ]:          0 :         printf("\t[-s for crc32c workload, use this seed value (default 0)\n");
     191         [ #  # ]:          0 :         printf("\t[-t time in seconds]\n");
     192         [ #  # ]:          0 :         printf("\t[-w workload type must be one of these: copy, fill, crc32c, copy_crc32c, compare, dualcast\n");
     193         [ #  # ]:          0 :         printf("\t[-y verify result if this switch is on]\n");
     194         [ #  # ]:          0 :         printf("\t\tCan be used to spread operations across a wider range of memory.\n");
     195                 :          0 : }
     196                 :            : 
     197                 :            : static int
     198                 :          0 : parse_args(int argc, char **argv)
     199                 :            : {
     200                 :          0 :         int argval = 0;
     201                 :            :         int op;
     202                 :            : 
     203   [ #  #  #  # ]:          0 :         while ((op = getopt(argc, argv, "a:C:f:hkm:o:P:q:r:t:yw:")) != -1) {
     204         [ #  # ]:          0 :                 switch (op) {
     205                 :          0 :                 case 'a':
     206                 :            :                 case 'C':
     207                 :            :                 case 'f':
     208                 :            :                 case 'o':
     209                 :            :                 case 'P':
     210                 :            :                 case 'q':
     211                 :            :                 case 'r':
     212                 :            :                 case 's':
     213                 :            :                 case 't':
     214                 :          0 :                         argval = spdk_strtol(optarg, 10);
     215         [ #  # ]:          0 :                         if (argval < 0) {
     216         [ #  # ]:          0 :                                 fprintf(stderr, "-%c option must be non-negative.\n", argc);
     217                 :          0 :                                 usage();
     218                 :          0 :                                 return 1;
     219                 :            :                         }
     220                 :          0 :                         break;
     221                 :          0 :                 default:
     222                 :          0 :                         break;
     223                 :            :                 };
     224                 :            : 
     225   [ #  #  #  #  :          0 :                 switch (op) {
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     226                 :          0 :                 case 'a':
     227                 :          0 :                         g_allocate_depth = argval;
     228                 :          0 :                         break;
     229                 :          0 :                 case 'C':
     230                 :          0 :                         g_crc32c_chained_count = argval;
     231                 :          0 :                         break;
     232                 :          0 :                 case 'f':
     233                 :          0 :                         g_fill_pattern = (uint8_t)argval;
     234                 :          0 :                         break;
     235                 :          0 :                 case 'k':
     236                 :          0 :                         g_idxd_kernel_mode = true;
     237                 :          0 :                         break;
     238                 :          0 :                 case 'm':
     239                 :          0 :                         g_core_mask = optarg;
     240                 :          0 :                         break;
     241                 :          0 :                 case 'o':
     242                 :          0 :                         g_xfer_size_bytes = argval;
     243                 :          0 :                         break;
     244                 :          0 :                 case 'P':
     245                 :          0 :                         g_fail_percent_goal = argval;
     246                 :          0 :                         break;
     247                 :          0 :                 case 'q':
     248                 :          0 :                         g_queue_depth = argval;
     249                 :          0 :                         break;
     250                 :          0 :                 case 'r':
     251                 :          0 :                         g_idxd_max_per_core = argval;
     252                 :          0 :                         break;
     253                 :          0 :                 case 's':
     254                 :          0 :                         g_crc32c_seed = argval;
     255                 :          0 :                         break;
     256                 :          0 :                 case 't':
     257                 :          0 :                         g_time_in_sec = argval;
     258                 :          0 :                         break;
     259                 :          0 :                 case 'y':
     260                 :          0 :                         g_verify = true;
     261                 :          0 :                         break;
     262                 :          0 :                 case 'w':
     263                 :          0 :                         g_workload_type = optarg;
     264   [ #  #  #  # ]:          0 :                         if (!strcmp(g_workload_type, "copy")) {
     265                 :          0 :                                 g_workload_selection = IDXD_COPY;
     266   [ #  #  #  # ]:          0 :                         } else if (!strcmp(g_workload_type, "fill")) {
     267                 :          0 :                                 g_workload_selection = IDXD_FILL;
     268   [ #  #  #  # ]:          0 :                         } else if (!strcmp(g_workload_type, "crc32c")) {
     269                 :          0 :                                 g_workload_selection = IDXD_CRC32C;
     270   [ #  #  #  # ]:          0 :                         } else if (!strcmp(g_workload_type, "copy_crc32c")) {
     271                 :          0 :                                 g_workload_selection = IDXD_COPY_CRC32C;
     272   [ #  #  #  # ]:          0 :                         } else if (!strcmp(g_workload_type, "compare")) {
     273                 :          0 :                                 g_workload_selection = IDXD_COMPARE;
     274   [ #  #  #  # ]:          0 :                         } else if (!strcmp(g_workload_type, "dualcast")) {
     275                 :          0 :                                 g_workload_selection = IDXD_DUALCAST;
     276                 :            :                         }
     277                 :          0 :                         break;
     278                 :          0 :                 case 'h':
     279                 :          0 :                         usage();
     280                 :          0 :                         exit(0);
     281                 :          0 :                 default:
     282                 :          0 :                         usage();
     283                 :          0 :                         return 1;
     284                 :            :                 }
     285                 :            :         }
     286                 :            : 
     287                 :          0 :         return 0;
     288                 :            : }
     289                 :            : 
     290                 :            : static int
     291                 :          0 : register_workers(void)
     292                 :            : {
     293                 :            :         uint32_t i;
     294                 :            :         struct worker_thread *worker;
     295                 :            : 
     296                 :          0 :         g_workers = NULL;
     297                 :          0 :         g_num_workers = 0;
     298                 :            : 
     299         [ #  # ]:          0 :         SPDK_ENV_FOREACH_CORE(i) {
     300                 :          0 :                 worker = calloc(1, sizeof(*worker));
     301         [ #  # ]:          0 :                 if (worker == NULL) {
     302   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to allocate worker\n");
     303                 :          0 :                         return 1;
     304                 :            :                 }
     305                 :            : 
     306                 :          0 :                 worker->core = i;
     307                 :          0 :                 worker->next = g_workers;
     308                 :          0 :                 g_workers = worker;
     309                 :          0 :                 g_num_workers++;
     310                 :            :         }
     311                 :            : 
     312                 :          0 :         return 0;
     313                 :            : }
     314                 :            : 
     315                 :            : static void
     316                 :          0 : _free_task_buffers(struct idxd_task *task)
     317                 :            : {
     318                 :            :         uint32_t i;
     319                 :            : 
     320         [ #  # ]:          0 :         if (g_workload_selection == IDXD_CRC32C) {
     321         [ #  # ]:          0 :                 if (task->iovs) {
     322         [ #  # ]:          0 :                         for (i = 0; i < task->iov_cnt; i++) {
     323         [ #  # ]:          0 :                                 if (task->iovs[i].iov_base) {
     324                 :          0 :                                         spdk_dma_free(task->iovs[i].iov_base);
     325                 :            :                                 }
     326                 :            :                         }
     327                 :          0 :                         free(task->iovs);
     328                 :            :                 }
     329                 :            :         } else {
     330                 :          0 :                 spdk_dma_free(task->src);
     331                 :            :         }
     332                 :            : 
     333                 :          0 :         spdk_dma_free(task->dst);
     334         [ #  # ]:          0 :         if (g_workload_selection == IDXD_DUALCAST) {
     335                 :          0 :                 spdk_dma_free(task->dst2);
     336                 :            :         }
     337                 :          0 : }
     338                 :            : 
     339                 :            : static inline void
     340                 :          0 : _free_task_buffers_in_pool(struct idxd_chan_entry *t)
     341                 :            : {
     342                 :            :         struct idxd_task *task;
     343                 :            : 
     344         [ #  # ]:          0 :         assert(t);
     345         [ #  # ]:          0 :         while ((task = TAILQ_FIRST(&t->tasks_pool_head))) {
     346         [ #  # ]:          0 :                 TAILQ_REMOVE(&t->tasks_pool_head, task, link);
     347                 :          0 :                 _free_task_buffers(task);
     348                 :            :         }
     349                 :          0 : }
     350                 :            : 
     351                 :            : static void
     352                 :          0 : free_idxd_chan_entry_resource(struct idxd_chan_entry *entry)
     353                 :            : {
     354         [ #  # ]:          0 :         assert(entry != NULL);
     355                 :            : 
     356         [ #  # ]:          0 :         if (entry->ch) {
     357                 :          0 :                 spdk_idxd_put_channel(entry->ch);
     358                 :            :         }
     359                 :            : 
     360                 :          0 :         _free_task_buffers_in_pool(entry);
     361                 :          0 :         free(entry->task_base);
     362                 :          0 :         free(entry);
     363                 :          0 : }
     364                 :            : 
     365                 :            : static void
     366                 :          0 : unregister_workers(void)
     367                 :            : {
     368                 :          0 :         struct worker_thread *worker = g_workers, *next_worker;
     369                 :            :         struct idxd_chan_entry *entry, *entry1;
     370                 :            : 
     371                 :            :         /* Free worker thread */
     372         [ #  # ]:          0 :         while (worker) {
     373                 :          0 :                 next_worker = worker->next;
     374                 :            : 
     375                 :          0 :                 entry = worker->ctx;
     376         [ #  # ]:          0 :                 while (entry) {
     377                 :          0 :                         entry1 = entry->next;
     378                 :          0 :                         free_idxd_chan_entry_resource(entry);
     379                 :          0 :                         entry = entry1;
     380                 :            :                 }
     381                 :            : 
     382                 :          0 :                 free(worker);
     383                 :          0 :                 worker = next_worker;
     384                 :          0 :                 g_num_workers--;
     385                 :            :         }
     386                 :            : 
     387         [ #  # ]:          0 :         assert(g_num_workers == 0);
     388                 :          0 : }
     389                 :            : 
     390                 :            : static int
     391                 :          0 : _get_task_data_bufs(struct idxd_task *task)
     392                 :            : {
     393                 :          0 :         uint32_t align = 0;
     394                 :          0 :         uint32_t i = 0;
     395                 :          0 :         int dst_buff_len = g_xfer_size_bytes;
     396                 :            : 
     397                 :            :         /* For dualcast, the DSA HW requires 4K alignment on destination addresses but
     398                 :            :          * we do this for all engines to keep it simple.
     399                 :            :          */
     400         [ #  # ]:          0 :         if (g_workload_selection == IDXD_DUALCAST) {
     401                 :          0 :                 align = ALIGN_4K;
     402                 :            :         }
     403                 :            : 
     404   [ #  #  #  # ]:          0 :         if (g_workload_selection == IDXD_CRC32C || g_workload_selection == IDXD_COPY_CRC32C) {
     405         [ #  # ]:          0 :                 assert(g_crc32c_chained_count > 0);
     406                 :          0 :                 task->iov_cnt = g_crc32c_chained_count;
     407                 :          0 :                 task->iovs = calloc(task->iov_cnt, sizeof(struct iovec));
     408         [ #  # ]:          0 :                 if (!task->iovs) {
     409   [ #  #  #  # ]:          0 :                         fprintf(stderr, "cannot allocated task->iovs fot task=%p\n", task);
     410                 :          0 :                         return -ENOMEM;
     411                 :            :                 }
     412                 :            : 
     413         [ #  # ]:          0 :                 if (g_workload_selection == IDXD_COPY_CRC32C) {
     414                 :          0 :                         dst_buff_len = g_xfer_size_bytes * g_crc32c_chained_count;
     415                 :            :                 }
     416                 :            : 
     417         [ #  # ]:          0 :                 for (i = 0; i < task->iov_cnt; i++) {
     418                 :          0 :                         task->iovs[i].iov_base = spdk_dma_zmalloc(g_xfer_size_bytes, 0, NULL);
     419         [ #  # ]:          0 :                         if (task->iovs[i].iov_base == NULL) {
     420                 :          0 :                                 return -ENOMEM;
     421                 :            :                         }
     422         [ #  # ]:          0 :                         memset(task->iovs[i].iov_base, DATA_PATTERN, g_xfer_size_bytes);
     423                 :          0 :                         task->iovs[i].iov_len = g_xfer_size_bytes;
     424                 :            :                 }
     425                 :            : 
     426                 :            :         } else {
     427                 :          0 :                 task->src = spdk_dma_zmalloc(g_xfer_size_bytes, 0, NULL);
     428         [ #  # ]:          0 :                 if (task->src == NULL) {
     429   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to alloc src buffer\n");
     430                 :          0 :                         return -ENOMEM;
     431                 :            :                 }
     432                 :            : 
     433                 :            :                 /* For fill, set the entire src buffer so we can check if verify is enabled. */
     434         [ #  # ]:          0 :                 if (g_workload_selection == IDXD_FILL) {
     435         [ #  # ]:          0 :                         memset(task->src, g_fill_pattern, g_xfer_size_bytes);
     436                 :            :                 } else {
     437         [ #  # ]:          0 :                         memset(task->src, DATA_PATTERN, g_xfer_size_bytes);
     438                 :            :                 }
     439                 :            :         }
     440                 :            : 
     441         [ #  # ]:          0 :         if (g_workload_selection != IDXD_CRC32C) {
     442                 :          0 :                 task->dst = spdk_dma_zmalloc(dst_buff_len, align, NULL);
     443         [ #  # ]:          0 :                 if (task->dst == NULL) {
     444   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to alloc dst buffer\n");
     445                 :          0 :                         return -ENOMEM;
     446                 :            :                 }
     447                 :            : 
     448                 :            :                 /* For compare we want the buffers to match, otherwise not. */
     449         [ #  # ]:          0 :                 if (g_workload_selection == IDXD_COMPARE) {
     450         [ #  # ]:          0 :                         memset(task->dst, DATA_PATTERN, dst_buff_len);
     451                 :            :                 } else {
     452         [ #  # ]:          0 :                         memset(task->dst, ~DATA_PATTERN, dst_buff_len);
     453                 :            :                 }
     454                 :            :         }
     455                 :            : 
     456         [ #  # ]:          0 :         if (g_workload_selection == IDXD_DUALCAST) {
     457                 :          0 :                 task->dst2 = spdk_dma_zmalloc(g_xfer_size_bytes, align, NULL);
     458         [ #  # ]:          0 :                 if (task->dst2 == NULL) {
     459   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to alloc dst buffer\n");
     460                 :          0 :                         return -ENOMEM;
     461                 :            :                 }
     462         [ #  # ]:          0 :                 memset(task->dst2, ~DATA_PATTERN, g_xfer_size_bytes);
     463                 :            :         }
     464                 :            : 
     465                 :          0 :         return 0;
     466                 :            : }
     467                 :            : 
     468                 :            : inline static struct idxd_task *
     469                 :          0 : _get_task(struct idxd_chan_entry *t)
     470                 :            : {
     471                 :            :         struct idxd_task *task;
     472                 :            : 
     473         [ #  # ]:          0 :         if (!TAILQ_EMPTY(&t->tasks_pool_head)) {
     474                 :          0 :                 task = TAILQ_FIRST(&t->tasks_pool_head);
     475         [ #  # ]:          0 :                 TAILQ_REMOVE(&t->tasks_pool_head, task, link);
     476                 :            :         } else {
     477   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to get idxd_task\n");
     478                 :          0 :                 return NULL;
     479                 :            :         }
     480                 :            : 
     481                 :          0 :         return task;
     482                 :            : }
     483                 :            : 
     484                 :            : static int idxd_chan_poll(struct idxd_chan_entry *chan);
     485                 :            : 
     486                 :            : static void
     487                 :          0 : drain_io(struct idxd_chan_entry *t)
     488                 :            : {
     489         [ #  # ]:          0 :         while (t->current_queue_depth > 0) {
     490                 :          0 :                 idxd_chan_poll(t);
     491                 :            :         }
     492                 :          0 : }
     493                 :            : 
     494                 :            : /* Submit one operation using the same idxd task that just completed. */
     495                 :            : static void
     496                 :          0 : _submit_single(struct idxd_chan_entry *t, struct idxd_task *task)
     497                 :            : {
     498                 :            :         int random_num;
     499                 :          0 :         int rc = 0;
     500                 :          0 :         struct iovec siov = {};
     501                 :          0 :         struct iovec diov = {};
     502                 :          0 :         int flags = 0;
     503                 :            : 
     504         [ #  # ]:          0 :         assert(t);
     505                 :            : 
     506                 :          0 :         t->current_queue_depth++;
     507                 :            : 
     508         [ #  # ]:          0 :         if (!TAILQ_EMPTY(&t->resubmits)) {
     509                 :          0 :                 rc = -EBUSY;
     510                 :          0 :                 goto queue;
     511                 :            :         }
     512                 :            : 
     513   [ #  #  #  #  :          0 :         switch (g_workload_selection) {
                #  #  # ]
     514                 :          0 :         case IDXD_COPY:
     515                 :          0 :                 siov.iov_base = task->src;
     516                 :          0 :                 siov.iov_len = g_xfer_size_bytes;
     517                 :          0 :                 diov.iov_base = task->dst;
     518                 :          0 :                 diov.iov_len = g_xfer_size_bytes;
     519                 :          0 :                 rc = spdk_idxd_submit_copy(t->ch, &diov, 1, &siov, 1, flags,
     520                 :            :                                            idxd_done, task);
     521                 :          0 :                 break;
     522                 :          0 :         case IDXD_FILL:
     523                 :            :                 /* For fill use the first byte of the task->dst buffer */
     524                 :          0 :                 diov.iov_base = task->dst;
     525                 :          0 :                 diov.iov_len = g_xfer_size_bytes;
     526                 :          0 :                 rc = spdk_idxd_submit_fill(t->ch, &diov, 1, *(uint64_t *)task->src,
     527                 :            :                                            flags, idxd_done, task);
     528                 :          0 :                 break;
     529                 :          0 :         case IDXD_CRC32C:
     530         [ #  # ]:          0 :                 assert(task->iovs != NULL);
     531         [ #  # ]:          0 :                 assert(task->iov_cnt > 0);
     532                 :          0 :                 rc = spdk_idxd_submit_crc32c(t->ch, task->iovs, task->iov_cnt,
     533                 :            :                                              g_crc32c_seed, &task->crc_dst,
     534                 :            :                                              flags, idxd_done, task);
     535                 :          0 :                 break;
     536                 :          0 :         case IDXD_COMPARE:
     537                 :          0 :                 random_num = rand() % 100;
     538         [ #  # ]:          0 :                 assert(task->dst != NULL);
     539         [ #  # ]:          0 :                 if (random_num < g_fail_percent_goal) {
     540                 :          0 :                         task->expected_status = -EILSEQ;
     541                 :          0 :                         *(uint8_t *)task->dst = ~DATA_PATTERN;
     542                 :            :                 } else {
     543                 :          0 :                         task->expected_status = 0;
     544                 :          0 :                         *(uint8_t *)task->dst = DATA_PATTERN;
     545                 :            :                 }
     546                 :          0 :                 siov.iov_base = task->src;
     547                 :          0 :                 siov.iov_len = g_xfer_size_bytes;
     548                 :          0 :                 diov.iov_base = task->dst;
     549                 :          0 :                 diov.iov_len = g_xfer_size_bytes;
     550                 :          0 :                 rc = spdk_idxd_submit_compare(t->ch, &siov, 1, &diov, 1, flags, idxd_done, task);
     551                 :          0 :                 break;
     552                 :          0 :         case IDXD_DUALCAST:
     553                 :          0 :                 rc = spdk_idxd_submit_dualcast(t->ch, task->dst, task->dst2,
     554                 :          0 :                                                task->src, g_xfer_size_bytes, flags, idxd_done, task);
     555                 :          0 :                 break;
     556                 :          0 :         case IDXD_COPY_CRC32C:
     557                 :          0 :                 diov.iov_base = task->dst;
     558                 :          0 :                 diov.iov_len = g_xfer_size_bytes;
     559                 :          0 :                 rc = spdk_idxd_submit_copy_crc32c(t->ch, &diov, 1, task->iovs, task->iov_cnt, g_crc32c_seed,
     560                 :            :                                                   &task->crc_dst,
     561                 :            :                                                   flags, idxd_done, task);
     562                 :          0 :                 break;
     563                 :          0 :         default:
     564                 :          0 :                 assert(false);
     565                 :            :                 break;
     566                 :            :         }
     567                 :            : 
     568                 :          0 : queue:
     569         [ #  # ]:          0 :         if (rc) {
     570                 :            :                 /* Queue the task to be resubmitted on the next poll. */
     571   [ #  #  #  # ]:          0 :                 if (rc != -EBUSY && rc != -EAGAIN) {
     572                 :          0 :                         t->xfer_failed++;
     573                 :            :                 }
     574                 :            : 
     575                 :          0 :                 TAILQ_INSERT_TAIL(&t->resubmits, task, link);
     576                 :            :         }
     577                 :          0 : }
     578                 :            : 
     579                 :            : static int
     580                 :          0 : _vector_memcmp(void *_dst, struct iovec *src_iovs, uint32_t iovcnt)
     581                 :            : {
     582                 :            :         uint32_t i;
     583                 :          0 :         uint32_t ttl_len = 0;
     584                 :          0 :         uint8_t *dst = (uint8_t *)_dst;
     585                 :            : 
     586         [ #  # ]:          0 :         for (i = 0; i < iovcnt; i++) {
     587   [ #  #  #  #  :          0 :                 if (memcmp(dst, src_iovs[i].iov_base, src_iovs[i].iov_len)) {
                   #  # ]
     588                 :          0 :                         return -1;
     589                 :            :                 }
     590                 :          0 :                 dst += src_iovs[i].iov_len;
     591                 :          0 :                 ttl_len += src_iovs[i].iov_len;
     592                 :            :         }
     593                 :            : 
     594         [ #  # ]:          0 :         if (ttl_len != iovcnt * g_xfer_size_bytes) {
     595                 :          0 :                 return -1;
     596                 :            :         }
     597                 :            : 
     598                 :          0 :         return 0;
     599                 :            : }
     600                 :            : 
     601                 :            : static void
     602                 :          0 : idxd_done(void *arg1, int status)
     603                 :            : {
     604                 :          0 :         struct idxd_task *task = arg1;
     605                 :          0 :         struct idxd_chan_entry *chan = task->worker_chan;
     606                 :            :         uint32_t sw_crc32c;
     607                 :            : 
     608         [ #  # ]:          0 :         assert(chan);
     609         [ #  # ]:          0 :         assert(chan->current_queue_depth > 0);
     610                 :            : 
     611   [ #  #  #  #  :          0 :         if (g_verify && status == 0) {
                   #  # ]
     612   [ #  #  #  #  :          0 :                 switch (g_workload_selection) {
                #  #  # ]
     613                 :          0 :                 case IDXD_COPY_CRC32C:
     614                 :          0 :                         sw_crc32c = spdk_crc32c_iov_update(task->iovs, task->iov_cnt, ~g_crc32c_seed);
     615         [ #  # ]:          0 :                         if (task->crc_dst != sw_crc32c) {
     616                 :          0 :                                 SPDK_NOTICELOG("CRC-32C miscompare\n");
     617                 :          0 :                                 chan->xfer_failed++;
     618                 :            :                         }
     619         [ #  # ]:          0 :                         if (_vector_memcmp(task->dst, task->iovs, task->iov_cnt)) {
     620                 :          0 :                                 SPDK_NOTICELOG("Data miscompare\n");
     621                 :          0 :                                 chan->xfer_failed++;
     622                 :            :                         }
     623                 :          0 :                         break;
     624                 :          0 :                 case IDXD_CRC32C:
     625                 :          0 :                         sw_crc32c = spdk_crc32c_iov_update(task->iovs, task->iov_cnt, ~g_crc32c_seed);
     626         [ #  # ]:          0 :                         if (task->crc_dst != sw_crc32c) {
     627                 :          0 :                                 SPDK_NOTICELOG("CRC-32C miscompare\n");
     628                 :          0 :                                 chan->xfer_failed++;
     629                 :            :                         }
     630                 :          0 :                         break;
     631                 :          0 :                 case IDXD_COPY:
     632   [ #  #  #  #  :          0 :                         if (memcmp(task->src, task->dst, g_xfer_size_bytes)) {
                   #  # ]
     633                 :          0 :                                 SPDK_NOTICELOG("Data miscompare\n");
     634                 :          0 :                                 chan->xfer_failed++;
     635                 :            :                         }
     636                 :          0 :                         break;
     637                 :          0 :                 case IDXD_DUALCAST:
     638   [ #  #  #  #  :          0 :                         if (memcmp(task->src, task->dst, g_xfer_size_bytes)) {
                   #  # ]
     639                 :          0 :                                 SPDK_NOTICELOG("Data miscompare, first destination\n");
     640                 :          0 :                                 chan->xfer_failed++;
     641                 :            :                         }
     642   [ #  #  #  #  :          0 :                         if (memcmp(task->src, task->dst2, g_xfer_size_bytes)) {
                   #  # ]
     643                 :          0 :                                 SPDK_NOTICELOG("Data miscompare, second destination\n");
     644                 :          0 :                                 chan->xfer_failed++;
     645                 :            :                         }
     646                 :          0 :                         break;
     647                 :          0 :                 case IDXD_FILL:
     648   [ #  #  #  #  :          0 :                         if (memcmp(task->dst, task->src, g_xfer_size_bytes)) {
                   #  # ]
     649                 :          0 :                                 SPDK_NOTICELOG("Data miscompare\n");
     650                 :          0 :                                 chan->xfer_failed++;
     651                 :            :                         }
     652                 :          0 :                         break;
     653                 :          0 :                 case IDXD_COMPARE:
     654                 :          0 :                         break;
     655                 :          0 :                 default:
     656                 :          0 :                         assert(false);
     657                 :            :                         break;
     658                 :            :                 }
     659                 :          0 :         }
     660                 :            : 
     661         [ #  # ]:          0 :         if (task->expected_status == -EILSEQ) {
     662         [ #  # ]:          0 :                 assert(status != 0);
     663                 :          0 :                 chan->injected_miscompares++;
     664         [ #  # ]:          0 :         } else if (status) {
     665                 :            :                 /* Expected to pass but the idxd module reported an error (ex: COMPARE operation). */
     666                 :          0 :                 chan->xfer_failed++;
     667                 :            :         }
     668                 :            : 
     669                 :          0 :         chan->xfer_completed++;
     670                 :          0 :         chan->current_queue_depth--;
     671                 :            : 
     672   [ #  #  #  # ]:          0 :         if (!chan->is_draining) {
     673                 :          0 :                 _submit_single(chan, task);
     674                 :            :         } else {
     675                 :          0 :                 TAILQ_INSERT_TAIL(&chan->tasks_pool_head, task, link);
     676                 :            :         }
     677                 :          0 : }
     678                 :            : 
     679                 :            : static int
     680                 :          0 : dump_result(void)
     681                 :            : {
     682                 :          0 :         uint64_t total_completed = 0;
     683                 :          0 :         uint64_t total_failed = 0;
     684                 :          0 :         uint64_t total_miscompared = 0;
     685                 :            :         uint64_t total_xfer_per_sec, total_bw_in_MiBps;
     686                 :          0 :         struct worker_thread *worker = g_workers;
     687                 :            :         struct idxd_chan_entry *t;
     688                 :            : 
     689         [ #  # ]:          0 :         printf("\nIDXD_ChanID   Core      Transfers      Bandwidth     Failed     Miscompares\n");
     690         [ #  # ]:          0 :         printf("---------------------------------------------------------------------------\n");
     691         [ #  # ]:          0 :         while (worker != NULL) {
     692                 :          0 :                 t = worker->ctx;
     693         [ #  # ]:          0 :                 while (t) {
     694         [ #  # ]:          0 :                         uint64_t xfer_per_sec = t->xfer_completed / g_time_in_sec;
     695         [ #  # ]:          0 :                         uint64_t bw_in_MiBps = (t->xfer_completed * g_xfer_size_bytes) /
     696                 :          0 :                                                (g_time_in_sec * 1024 * 1024);
     697                 :            : 
     698                 :          0 :                         total_completed += t->xfer_completed;
     699                 :          0 :                         total_failed += t->xfer_failed;
     700                 :          0 :                         total_miscompared += t->injected_miscompares;
     701                 :            : 
     702         [ #  # ]:          0 :                         if (xfer_per_sec) {
     703         [ #  # ]:          0 :                                 printf("%10d%5u%16" PRIu64 "/s%9" PRIu64 " MiB/s%11" PRIu64 " %15" PRIu64 "\n",
     704                 :            :                                        t->idxd_chan_id, worker->core, xfer_per_sec, bw_in_MiBps, t->xfer_failed,
     705                 :            :                                        t->injected_miscompares);
     706                 :            :                         }
     707                 :          0 :                         t = t->next;
     708                 :            :                 }
     709                 :            : 
     710                 :          0 :                 worker = worker->next;
     711                 :            :         }
     712                 :            : 
     713         [ #  # ]:          0 :         total_xfer_per_sec = total_completed / g_time_in_sec;
     714                 :          0 :         total_bw_in_MiBps = (total_completed * g_xfer_size_bytes) /
     715         [ #  # ]:          0 :                             (g_time_in_sec * 1024 * 1024);
     716                 :            : 
     717         [ #  # ]:          0 :         printf("===========================================================================\n");
     718         [ #  # ]:          0 :         printf("Total:%25" PRIu64 "/s%9" PRIu64 " MiB/s%11" PRIu64 " %15" PRIu64"\n\n",
     719                 :            :                total_xfer_per_sec, total_bw_in_MiBps, total_failed, total_miscompared);
     720                 :            : 
     721                 :          0 :         return total_failed ? 1 : 0;
     722                 :            : }
     723                 :            : 
     724                 :            : static int
     725                 :          0 : submit_all(struct idxd_chan_entry *t)
     726                 :            : {
     727                 :            :         int i;
     728                 :          0 :         int remaining = g_queue_depth;
     729                 :            :         struct idxd_task *task;
     730                 :            : 
     731         [ #  # ]:          0 :         for (i = 0; i < remaining; i++) {
     732                 :          0 :                 task = _get_task(t);
     733         [ #  # ]:          0 :                 if (task == NULL) {
     734                 :          0 :                         _free_task_buffers_in_pool(t);
     735                 :          0 :                         return -1;
     736                 :            :                 }
     737                 :            : 
     738                 :            :                 /* Submit as single task */
     739                 :          0 :                 _submit_single(t, task);
     740                 :            :         }
     741                 :            : 
     742                 :          0 :         return 0;
     743                 :            : }
     744                 :            : 
     745                 :            : static int
     746                 :          0 : idxd_chan_poll(struct idxd_chan_entry *chan)
     747                 :            : {
     748                 :            :         int                     rc;
     749                 :            :         struct idxd_task        *task, *tmp;
     750                 :          0 :         TAILQ_HEAD(, idxd_task) swap;
     751                 :            : 
     752                 :          0 :         rc = spdk_idxd_process_events(chan->ch);
     753         [ #  # ]:          0 :         if (rc < 0) {
     754                 :          0 :                 return rc;
     755                 :            :         }
     756                 :            : 
     757         [ #  # ]:          0 :         if (!TAILQ_EMPTY(&chan->resubmits)) {
     758                 :          0 :                 TAILQ_INIT(&swap);
     759   [ #  #  #  # ]:          0 :                 TAILQ_SWAP(&swap, &chan->resubmits, idxd_task, link);
     760         [ #  # ]:          0 :                 TAILQ_FOREACH_SAFE(task, &swap, link, tmp) {
     761         [ #  # ]:          0 :                         TAILQ_REMOVE(&swap, task, link);
     762                 :          0 :                         chan->current_queue_depth--;
     763   [ #  #  #  # ]:          0 :                         if (!chan->is_draining) {
     764                 :          0 :                                 _submit_single(chan, task);
     765                 :            :                         } else {
     766                 :          0 :                                 TAILQ_INSERT_TAIL(&chan->tasks_pool_head, task, link);
     767                 :            :                         }
     768                 :            :                 }
     769                 :            :         }
     770                 :            : 
     771                 :          0 :         return rc;
     772                 :            : }
     773                 :            : 
     774                 :            : static int
     775                 :          0 : work_fn(void *arg)
     776                 :            : {
     777                 :            :         uint64_t tsc_end;
     778                 :          0 :         struct worker_thread *worker = (struct worker_thread *)arg;
     779                 :          0 :         struct idxd_chan_entry *t = NULL;
     780                 :            : 
     781         [ #  # ]:          0 :         printf("Starting thread on core %u\n", worker->core);
     782                 :            : 
     783                 :          0 :         tsc_end = spdk_get_ticks() + g_time_in_sec * spdk_get_ticks_hz();
     784                 :            : 
     785                 :          0 :         t = worker->ctx;
     786         [ #  # ]:          0 :         while (t != NULL) {
     787         [ #  # ]:          0 :                 if (submit_all(t) != 0) {
     788                 :          0 :                         return -1;
     789                 :            :                 }
     790                 :          0 :                 t = t->next;
     791                 :            :         }
     792                 :            : 
     793                 :            :         while (1) {
     794                 :          0 :                 t = worker->ctx;
     795         [ #  # ]:          0 :                 while (t != NULL) {
     796                 :          0 :                         idxd_chan_poll(t);
     797                 :          0 :                         t = t->next;
     798                 :            :                 }
     799                 :            : 
     800         [ #  # ]:          0 :                 if (spdk_get_ticks() > tsc_end) {
     801                 :          0 :                         break;
     802                 :            :                 }
     803                 :            :         }
     804                 :            : 
     805                 :          0 :         t = worker->ctx;
     806         [ #  # ]:          0 :         while (t != NULL) {
     807                 :            :                 /* begin to drain io */
     808                 :          0 :                 t->is_draining = true;
     809                 :          0 :                 drain_io(t);
     810                 :          0 :                 t = t->next;
     811                 :            :         }
     812                 :            : 
     813                 :          0 :         return 0;
     814                 :            : }
     815                 :            : 
     816                 :            : static int
     817                 :          0 : init_env(void)
     818                 :            : {
     819                 :          0 :         struct spdk_env_opts opts;
     820                 :            : 
     821                 :          0 :         spdk_env_opts_init(&opts);
     822                 :          0 :         opts.name = "idxd_perf";
     823                 :          0 :         opts.core_mask = g_core_mask;
     824         [ #  # ]:          0 :         if (spdk_env_init(&opts) < 0) {
     825                 :          0 :                 return 1;
     826                 :            :         }
     827                 :            : 
     828                 :          0 :         return 0;
     829                 :            : }
     830                 :            : 
     831                 :            : static struct spdk_idxd_device *
     832                 :          0 : get_next_idxd(void)
     833                 :            : {
     834                 :            :         struct spdk_idxd_device *idxd;
     835                 :            : 
     836         [ #  # ]:          0 :         if (g_next_device == NULL) {
     837                 :          0 :                 return NULL;
     838                 :            :         }
     839                 :            : 
     840                 :          0 :         idxd = g_next_device->idxd;
     841                 :            : 
     842                 :          0 :         g_next_device = TAILQ_NEXT(g_next_device, tailq);
     843                 :            : 
     844                 :          0 :         return idxd;
     845                 :            : }
     846                 :            : 
     847                 :            : static int
     848                 :          0 : init_idxd_chan_entry(struct idxd_chan_entry *t, struct spdk_idxd_device *idxd)
     849                 :            : {
     850                 :          0 :         int num_tasks = g_allocate_depth;
     851                 :            :         struct idxd_task *task;
     852                 :            :         int i;
     853                 :            : 
     854         [ #  # ]:          0 :         assert(t != NULL);
     855                 :            : 
     856                 :          0 :         TAILQ_INIT(&t->tasks_pool_head);
     857                 :          0 :         TAILQ_INIT(&t->resubmits);
     858                 :          0 :         t->ch = spdk_idxd_get_channel(idxd);
     859         [ #  # ]:          0 :         if (t->ch == NULL) {
     860   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to get channel\n");
     861                 :          0 :                 goto err;
     862                 :            :         }
     863                 :            : 
     864                 :          0 :         t->task_base = calloc(g_allocate_depth, sizeof(struct idxd_task));
     865         [ #  # ]:          0 :         if (t->task_base == NULL) {
     866   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not allocate task base.\n");
     867                 :          0 :                 goto err;
     868                 :            :         }
     869                 :            : 
     870                 :          0 :         task = t->task_base;
     871         [ #  # ]:          0 :         for (i = 0; i < num_tasks; i++) {
     872                 :          0 :                 TAILQ_INSERT_TAIL(&t->tasks_pool_head, task, link);
     873                 :          0 :                 task->worker_chan = t;
     874         [ #  # ]:          0 :                 if (_get_task_data_bufs(task)) {
     875   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to get data bufs\n");
     876                 :          0 :                         goto err;
     877                 :            :                 }
     878                 :          0 :                 task++;
     879                 :            :         }
     880                 :            : 
     881                 :          0 :         return 0;
     882                 :            : 
     883                 :          0 : err:
     884                 :          0 :         free_idxd_chan_entry_resource(t);
     885                 :          0 :         return -1;
     886                 :            : }
     887                 :            : 
     888                 :            : static int
     889                 :          0 : associate_workers_with_idxd_device(void)
     890                 :            : {
     891                 :          0 :         struct spdk_idxd_device *idxd = get_next_idxd();
     892                 :          0 :         struct worker_thread    *worker = g_workers;
     893                 :          0 :         int i = 0;
     894                 :            :         struct idxd_chan_entry  *t;
     895                 :            : 
     896         [ #  # ]:          0 :         while (idxd != NULL) {
     897         [ #  # ]:          0 :                 if (worker->chan_num >= g_idxd_max_per_core) {
     898   [ #  #  #  # ]:          0 :                         fprintf(stdout, "Notice: we cannot let single worker assign idxd devices\n"
     899                 :            :                                 "more than %d, you need use -r while starting app to change this value\n",
     900                 :            :                                 g_idxd_max_per_core);
     901                 :          0 :                         break;
     902                 :            :                 }
     903                 :            : 
     904                 :          0 :                 t = calloc(1, sizeof(struct idxd_chan_entry));
     905         [ #  # ]:          0 :                 if (!t) {
     906                 :          0 :                         return -1;
     907                 :            :                 }
     908                 :            : 
     909                 :          0 :                 t->idxd_chan_id = i;
     910                 :            : 
     911         [ #  # ]:          0 :                 if (init_idxd_chan_entry(t, idxd)) {
     912   [ #  #  #  # ]:          0 :                         fprintf(stdout, "idxd device=%p is bound on core=%d\n", idxd, worker->core);
     913                 :          0 :                         return -1;
     914                 :            : 
     915                 :            :                 }
     916   [ #  #  #  # ]:          0 :                 fprintf(stdout, "idxd device=%p is bound on core=%d\n", idxd, worker->core);
     917                 :            : 
     918                 :          0 :                 t->next = worker->ctx;
     919                 :          0 :                 worker->ctx = t;
     920                 :          0 :                 worker->chan_num++;
     921                 :            : 
     922                 :          0 :                 worker = worker->next;
     923         [ #  # ]:          0 :                 if (worker == NULL) {
     924                 :          0 :                         worker = g_workers;
     925                 :            :                 }
     926                 :            : 
     927                 :          0 :                 idxd = get_next_idxd();
     928                 :          0 :                 i++;
     929                 :            :         }
     930                 :            : 
     931                 :          0 :         return 0;
     932                 :            : }
     933                 :            : 
     934                 :            : int
     935                 :          0 : main(int argc, char **argv)
     936                 :            : {
     937                 :            :         int rc;
     938                 :            :         struct worker_thread *worker, *main_worker;
     939                 :            :         unsigned main_core;
     940                 :            : 
     941         [ #  # ]:          0 :         if (parse_args(argc, argv) != 0) {
     942                 :          0 :                 return -1;
     943                 :            :         }
     944                 :            : 
     945         [ #  # ]:          0 :         if (init_env() != 0) {
     946                 :          0 :                 return -1;
     947                 :            :         }
     948                 :            : 
     949         [ #  # ]:          0 :         if (register_workers() != 0) {
     950                 :          0 :                 rc = -1;
     951                 :          0 :                 goto cleanup;
     952                 :            :         }
     953                 :            : 
     954         [ #  # ]:          0 :         if (idxd_init() != 0) {
     955                 :          0 :                 rc = -1;
     956                 :          0 :                 goto cleanup;
     957                 :            :         }
     958                 :            : 
     959         [ #  # ]:          0 :         if (g_num_devices == 0) {
     960         [ #  # ]:          0 :                 printf("No idxd device found\n");
     961                 :          0 :                 rc = -1;
     962                 :          0 :                 goto cleanup;
     963                 :            :         }
     964                 :            : 
     965         [ #  # ]:          0 :         if ((g_workload_selection != IDXD_COPY) &&
     966         [ #  # ]:          0 :             (g_workload_selection != IDXD_FILL) &&
     967         [ #  # ]:          0 :             (g_workload_selection != IDXD_CRC32C) &&
     968         [ #  # ]:          0 :             (g_workload_selection != IDXD_COPY_CRC32C) &&
     969         [ #  # ]:          0 :             (g_workload_selection != IDXD_COMPARE) &&
     970         [ #  # ]:          0 :             (g_workload_selection != IDXD_DUALCAST)) {
     971                 :          0 :                 usage();
     972                 :          0 :                 rc = -1;
     973                 :          0 :                 goto cleanup;
     974                 :            :         }
     975                 :            : 
     976   [ #  #  #  # ]:          0 :         if (g_allocate_depth > 0 && g_queue_depth > g_allocate_depth) {
     977   [ #  #  #  # ]:          0 :                 fprintf(stdout, "allocate depth must be at least as big as queue depth\n");
     978                 :          0 :                 usage();
     979                 :          0 :                 rc = -1;
     980                 :          0 :                 goto cleanup;
     981                 :            :         }
     982                 :            : 
     983         [ #  # ]:          0 :         if (g_allocate_depth == 0) {
     984                 :          0 :                 g_allocate_depth = g_queue_depth;
     985                 :            :         }
     986                 :            : 
     987   [ #  #  #  # ]:          0 :         if ((g_workload_selection == IDXD_CRC32C || g_workload_selection == IDXD_COPY_CRC32C) &&
     988         [ #  # ]:          0 :             g_crc32c_chained_count == 0) {
     989                 :          0 :                 usage();
     990                 :          0 :                 rc = -1;
     991                 :          0 :                 goto cleanup;
     992                 :            :         }
     993                 :            : 
     994                 :          0 :         g_next_device = TAILQ_FIRST(&g_idxd_devices);
     995         [ #  # ]:          0 :         if (associate_workers_with_idxd_device() != 0) {
     996                 :          0 :                 rc = -1;
     997                 :          0 :                 goto cleanup;
     998                 :            :         }
     999                 :            : 
    1000                 :          0 :         dump_user_config();
    1001                 :            :         /* Launch all of the secondary workers */
    1002                 :          0 :         main_core = spdk_env_get_current_core();
    1003                 :          0 :         main_worker = NULL;
    1004                 :          0 :         worker = g_workers;
    1005         [ #  # ]:          0 :         while (worker != NULL) {
    1006         [ #  # ]:          0 :                 if (worker->core != main_core) {
    1007                 :          0 :                         spdk_env_thread_launch_pinned(worker->core, work_fn, worker);
    1008                 :            :                 } else {
    1009         [ #  # ]:          0 :                         assert(main_worker == NULL);
    1010                 :          0 :                         main_worker = worker;
    1011                 :            :                 }
    1012                 :          0 :                 worker = worker->next;
    1013                 :            :         }
    1014                 :            : 
    1015         [ #  # ]:          0 :         assert(main_worker != NULL);
    1016                 :          0 :         rc = work_fn(main_worker);
    1017         [ #  # ]:          0 :         if (rc != 0) {
    1018                 :          0 :                 goto cleanup;
    1019                 :            :         }
    1020                 :            : 
    1021                 :          0 :         spdk_env_thread_wait_all();
    1022                 :            : 
    1023                 :          0 :         rc = dump_result();
    1024                 :          0 : cleanup:
    1025                 :          0 :         unregister_workers();
    1026                 :          0 :         idxd_exit();
    1027                 :            : 
    1028                 :          0 :         spdk_env_fini();
    1029                 :          0 :         return rc;
    1030                 :            : }

Generated by: LCOV version 1.14