1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2015 Intel Corporation. 3d4ab30baSDaniel Verkamp * All rights reserved. 4d4ab30baSDaniel Verkamp */ 5d4ab30baSDaniel Verkamp 6b961d9ccSBen Walker #include "spdk/stdinc.h" 718a2cc11SBen Walker 8d4ab30baSDaniel Verkamp #include "spdk/ioat.h" 90dd80395SBen Walker #include "spdk/env.h" 107f5b671dSBen Walker #include "spdk/queue.h" 11d4ab30baSDaniel Verkamp #include "spdk/string.h" 12d4ab30baSDaniel Verkamp 13d4ab30baSDaniel Verkamp struct user_config { 14d4ab30baSDaniel Verkamp int xfer_size_bytes; 15d4ab30baSDaniel Verkamp int queue_depth; 16d4ab30baSDaniel Verkamp int time_in_sec; 17d4ab30baSDaniel Verkamp bool verify; 18d4ab30baSDaniel Verkamp char *core_mask; 19294e743bSZiye Yang int ioat_chan_num; 20d4ab30baSDaniel Verkamp }; 21d4ab30baSDaniel Verkamp 22d4ab30baSDaniel Verkamp struct ioat_device { 235cab054fSDaniel Verkamp struct spdk_ioat_chan *ioat; 24d4ab30baSDaniel Verkamp TAILQ_ENTRY(ioat_device) tailq; 25d4ab30baSDaniel Verkamp }; 26d4ab30baSDaniel Verkamp 27a3d1419bSyidong0635 static TAILQ_HEAD(, ioat_device) g_devices = TAILQ_HEAD_INITIALIZER(g_devices); 28cf0871a5SDaniel Verkamp static struct ioat_device *g_next_device; 29d4ab30baSDaniel Verkamp 30d4ab30baSDaniel Verkamp static struct user_config g_user_config; 31d4ab30baSDaniel Verkamp 32294e743bSZiye Yang struct ioat_chan_entry { 33cf0871a5SDaniel Verkamp struct spdk_ioat_chan *chan; 34294e743bSZiye Yang int ioat_chan_id; 35d4ab30baSDaniel Verkamp uint64_t xfer_completed; 36d4ab30baSDaniel Verkamp uint64_t xfer_failed; 37d4ab30baSDaniel Verkamp uint64_t current_queue_depth; 386728c1b8SJim Harris uint64_t waiting_for_flush; 396728c1b8SJim Harris uint64_t flush_threshold; 40d4ab30baSDaniel Verkamp bool is_draining; 417f5b671dSBen Walker struct spdk_mempool *data_pool; 427f5b671dSBen Walker struct spdk_mempool *task_pool; 43294e743bSZiye Yang struct ioat_chan_entry *next; 44294e743bSZiye Yang }; 45294e743bSZiye Yang 46294e743bSZiye Yang struct worker_thread { 47294e743bSZiye Yang struct ioat_chan_entry *ctx; 48294e743bSZiye Yang struct worker_thread *next; 4987d242f9SBen Walker unsigned core; 50d4ab30baSDaniel Verkamp }; 51d4ab30baSDaniel Verkamp 52d4ab30baSDaniel Verkamp struct ioat_task { 53294e743bSZiye Yang struct ioat_chan_entry *ioat_chan_entry; 54d4ab30baSDaniel Verkamp void *src; 55d4ab30baSDaniel Verkamp void *dst; 56d4ab30baSDaniel Verkamp }; 57d4ab30baSDaniel Verkamp 58294e743bSZiye Yang static struct worker_thread *g_workers = NULL; 59294e743bSZiye Yang static int g_num_workers = 0; 60294e743bSZiye Yang static int g_ioat_chan_num = 0; 61294e743bSZiye Yang 62294e743bSZiye Yang static void submit_single_xfer(struct ioat_chan_entry *ioat_chan_entry, struct ioat_task *ioat_task, 63d4ab30baSDaniel Verkamp void *dst, void *src); 64d4ab30baSDaniel Verkamp 65d4ab30baSDaniel Verkamp static void 66d4ab30baSDaniel Verkamp construct_user_config(struct user_config *self) 67d4ab30baSDaniel Verkamp { 68d4ab30baSDaniel Verkamp self->xfer_size_bytes = 4096; 69294e743bSZiye Yang self->ioat_chan_num = 1; 70d4ab30baSDaniel Verkamp self->queue_depth = 256; 71d4ab30baSDaniel Verkamp self->time_in_sec = 10; 72d4ab30baSDaniel Verkamp self->verify = false; 73d4ab30baSDaniel Verkamp self->core_mask = "0x1"; 74d4ab30baSDaniel Verkamp } 75d4ab30baSDaniel Verkamp 76d4ab30baSDaniel Verkamp static void 77d4ab30baSDaniel Verkamp dump_user_config(struct user_config *self) 78d4ab30baSDaniel Verkamp { 79d4ab30baSDaniel Verkamp printf("User configuration:\n"); 80294e743bSZiye Yang printf("Number of channels: %u\n", self->ioat_chan_num); 81d4ab30baSDaniel Verkamp printf("Transfer size: %u bytes\n", self->xfer_size_bytes); 82d4ab30baSDaniel Verkamp printf("Queue depth: %u\n", self->queue_depth); 83d4ab30baSDaniel Verkamp printf("Run time: %u seconds\n", self->time_in_sec); 84d4ab30baSDaniel Verkamp printf("Core mask: %s\n", self->core_mask); 85d4ab30baSDaniel Verkamp printf("Verify: %s\n\n", self->verify ? "Yes" : "No"); 86d4ab30baSDaniel Verkamp } 87d4ab30baSDaniel Verkamp 88d4ab30baSDaniel Verkamp static void 89d4ab30baSDaniel Verkamp ioat_exit(void) 90d4ab30baSDaniel Verkamp { 91d4ab30baSDaniel Verkamp struct ioat_device *dev; 92d4ab30baSDaniel Verkamp 93d4ab30baSDaniel Verkamp while (!TAILQ_EMPTY(&g_devices)) { 94d4ab30baSDaniel Verkamp dev = TAILQ_FIRST(&g_devices); 95d4ab30baSDaniel Verkamp TAILQ_REMOVE(&g_devices, dev, tailq); 9625cad6ffSDaniel Verkamp if (dev->ioat) { 975cab054fSDaniel Verkamp spdk_ioat_detach(dev->ioat); 9825cad6ffSDaniel Verkamp } 998a44220bSJohn Meneghini spdk_dma_free(dev); 100d4ab30baSDaniel Verkamp } 101d4ab30baSDaniel Verkamp } 102d4ab30baSDaniel Verkamp 103d4ab30baSDaniel Verkamp static void 104d4ab30baSDaniel Verkamp ioat_done(void *cb_arg) 105d4ab30baSDaniel Verkamp { 106d4ab30baSDaniel Verkamp struct ioat_task *ioat_task = (struct ioat_task *)cb_arg; 107294e743bSZiye Yang struct ioat_chan_entry *ioat_chan_entry = ioat_task->ioat_chan_entry; 108d4ab30baSDaniel Verkamp 109d4ab30baSDaniel Verkamp if (g_user_config.verify && memcmp(ioat_task->src, ioat_task->dst, g_user_config.xfer_size_bytes)) { 110294e743bSZiye Yang ioat_chan_entry->xfer_failed++; 111d4ab30baSDaniel Verkamp } else { 112294e743bSZiye Yang ioat_chan_entry->xfer_completed++; 113d4ab30baSDaniel Verkamp } 114d4ab30baSDaniel Verkamp 115294e743bSZiye Yang ioat_chan_entry->current_queue_depth--; 116d4ab30baSDaniel Verkamp 117294e743bSZiye Yang if (ioat_chan_entry->is_draining) { 118294e743bSZiye Yang spdk_mempool_put(ioat_chan_entry->data_pool, ioat_task->src); 119294e743bSZiye Yang spdk_mempool_put(ioat_chan_entry->data_pool, ioat_task->dst); 120294e743bSZiye Yang spdk_mempool_put(ioat_chan_entry->task_pool, ioat_task); 121d4ab30baSDaniel Verkamp } else { 122294e743bSZiye Yang submit_single_xfer(ioat_chan_entry, ioat_task, ioat_task->dst, ioat_task->src); 123294e743bSZiye Yang } 124294e743bSZiye Yang } 125294e743bSZiye Yang 126294e743bSZiye Yang static int 127294e743bSZiye Yang register_workers(void) 128294e743bSZiye Yang { 1297f7c03a9SBen Walker uint32_t i; 130294e743bSZiye Yang struct worker_thread *worker; 131294e743bSZiye Yang 13284230409SBen Walker g_workers = NULL; 13384230409SBen Walker g_num_workers = 0; 13484230409SBen Walker 1357f7c03a9SBen Walker SPDK_ENV_FOREACH_CORE(i) { 13684230409SBen Walker worker = calloc(1, sizeof(*worker)); 137294e743bSZiye Yang if (worker == NULL) { 13884230409SBen Walker fprintf(stderr, "Unable to allocate worker\n"); 139454ff172STomasz Zawadzki return 1; 140294e743bSZiye Yang } 141294e743bSZiye Yang 14287d242f9SBen Walker worker->core = i; 14384230409SBen Walker worker->next = g_workers; 14484230409SBen Walker g_workers = worker; 145294e743bSZiye Yang g_num_workers++; 146294e743bSZiye Yang } 147294e743bSZiye Yang 148294e743bSZiye Yang return 0; 149294e743bSZiye Yang } 150294e743bSZiye Yang 151294e743bSZiye Yang static void 152294e743bSZiye Yang unregister_workers(void) 153294e743bSZiye Yang { 154294e743bSZiye Yang struct worker_thread *worker = g_workers; 155294e743bSZiye Yang struct ioat_chan_entry *entry, *entry1; 156294e743bSZiye Yang 157294e743bSZiye Yang /* Free ioat_chan_entry and worker thread */ 158294e743bSZiye Yang while (worker) { 159294e743bSZiye Yang struct worker_thread *next_worker = worker->next; 160294e743bSZiye Yang entry = worker->ctx; 161294e743bSZiye Yang while (entry) { 162294e743bSZiye Yang entry1 = entry->next; 163294e743bSZiye Yang spdk_mempool_free(entry->data_pool); 164294e743bSZiye Yang spdk_mempool_free(entry->task_pool); 165294e743bSZiye Yang free(entry); 166294e743bSZiye Yang entry = entry1; 167294e743bSZiye Yang } 168294e743bSZiye Yang free(worker); 169294e743bSZiye Yang worker = next_worker; 170d4ab30baSDaniel Verkamp } 171d4ab30baSDaniel Verkamp } 172d4ab30baSDaniel Verkamp 173047c5aaaSDaniel Verkamp static bool 17493933831SDaniel Verkamp probe_cb(void *cb_ctx, struct spdk_pci_device *pci_dev) 175d4ab30baSDaniel Verkamp { 176b4572d45SDaniel Verkamp printf(" Found matching device at %04x:%02x:%02x.%x " 177dca887b7SDaniel Verkamp "vendor:0x%04x device:0x%04x\n", 178b4572d45SDaniel Verkamp spdk_pci_device_get_domain(pci_dev), 17993933831SDaniel Verkamp spdk_pci_device_get_bus(pci_dev), spdk_pci_device_get_dev(pci_dev), 18093933831SDaniel Verkamp spdk_pci_device_get_func(pci_dev), 181dca887b7SDaniel Verkamp spdk_pci_device_get_vendor_id(pci_dev), spdk_pci_device_get_device_id(pci_dev)); 182d4ab30baSDaniel Verkamp 183047c5aaaSDaniel Verkamp return true; 184047c5aaaSDaniel Verkamp } 185047c5aaaSDaniel Verkamp 186047c5aaaSDaniel Verkamp static void 1875cab054fSDaniel Verkamp attach_cb(void *cb_ctx, struct spdk_pci_device *pci_dev, struct spdk_ioat_chan *ioat) 188047c5aaaSDaniel Verkamp { 189047c5aaaSDaniel Verkamp struct ioat_device *dev; 190d4ab30baSDaniel Verkamp 191294e743bSZiye Yang if (g_ioat_chan_num >= g_user_config.ioat_chan_num) { 192294e743bSZiye Yang return; 193294e743bSZiye Yang } 194294e743bSZiye Yang 1958a44220bSJohn Meneghini dev = spdk_dma_zmalloc(sizeof(*dev), 0, NULL); 196d4ab30baSDaniel Verkamp if (dev == NULL) { 197d4ab30baSDaniel Verkamp printf("Failed to allocate device struct\n"); 198047c5aaaSDaniel Verkamp return; 199d4ab30baSDaniel Verkamp } 200d4ab30baSDaniel Verkamp 201047c5aaaSDaniel Verkamp dev->ioat = ioat; 202294e743bSZiye Yang g_ioat_chan_num++; 203d4ab30baSDaniel Verkamp TAILQ_INSERT_TAIL(&g_devices, dev, tailq); 204d4ab30baSDaniel Verkamp } 205d4ab30baSDaniel Verkamp 206047c5aaaSDaniel Verkamp static int 207047c5aaaSDaniel Verkamp ioat_init(void) 208047c5aaaSDaniel Verkamp { 2095cab054fSDaniel Verkamp if (spdk_ioat_probe(NULL, probe_cb, attach_cb) != 0) { 210047c5aaaSDaniel Verkamp fprintf(stderr, "ioat_probe() failed\n"); 211047c5aaaSDaniel Verkamp return 1; 212d4ab30baSDaniel Verkamp } 213047c5aaaSDaniel Verkamp 214047c5aaaSDaniel Verkamp return 0; 215d4ab30baSDaniel Verkamp } 216d4ab30baSDaniel Verkamp 217d4ab30baSDaniel Verkamp static void 218d4ab30baSDaniel Verkamp usage(char *program_name) 219d4ab30baSDaniel Verkamp { 220d4ab30baSDaniel Verkamp printf("%s options\n", program_name); 221d4ab30baSDaniel Verkamp printf("\t[-h help message]\n"); 222d4ab30baSDaniel Verkamp printf("\t[-c core mask for distributing I/O submission/completion work]\n"); 223d4ab30baSDaniel Verkamp printf("\t[-q queue depth]\n"); 224294e743bSZiye Yang printf("\t[-n number of channels]\n"); 225b5616804SDariusz Stojaczyk printf("\t[-o transfer size in bytes]\n"); 226d4ab30baSDaniel Verkamp printf("\t[-t time in seconds]\n"); 227d4ab30baSDaniel Verkamp printf("\t[-v verify copy result if this switch is on]\n"); 228d4ab30baSDaniel Verkamp } 229d4ab30baSDaniel Verkamp 230d4ab30baSDaniel Verkamp static int 231d4ab30baSDaniel Verkamp parse_args(int argc, char **argv) 232d4ab30baSDaniel Verkamp { 233d4ab30baSDaniel Verkamp int op; 234d4ab30baSDaniel Verkamp 235d4ab30baSDaniel Verkamp construct_user_config(&g_user_config); 236b5616804SDariusz Stojaczyk while ((op = getopt(argc, argv, "c:hn:o:q:t:v")) != -1) { 237d4ab30baSDaniel Verkamp switch (op) { 238b5616804SDariusz Stojaczyk case 'o': 23947fadb7fSShuhei Matsumoto g_user_config.xfer_size_bytes = spdk_strtol(optarg, 10); 240d4ab30baSDaniel Verkamp break; 241294e743bSZiye Yang case 'n': 24247fadb7fSShuhei Matsumoto g_user_config.ioat_chan_num = spdk_strtol(optarg, 10); 243294e743bSZiye Yang break; 244d4ab30baSDaniel Verkamp case 'q': 24547fadb7fSShuhei Matsumoto g_user_config.queue_depth = spdk_strtol(optarg, 10); 246d4ab30baSDaniel Verkamp break; 247d4ab30baSDaniel Verkamp case 't': 24847fadb7fSShuhei Matsumoto g_user_config.time_in_sec = spdk_strtol(optarg, 10); 249d4ab30baSDaniel Verkamp break; 250d4ab30baSDaniel Verkamp case 'c': 251d4ab30baSDaniel Verkamp g_user_config.core_mask = optarg; 252d4ab30baSDaniel Verkamp break; 253d4ab30baSDaniel Verkamp case 'v': 254d4ab30baSDaniel Verkamp g_user_config.verify = true; 255d4ab30baSDaniel Verkamp break; 256d4ab30baSDaniel Verkamp case 'h': 257d4ab30baSDaniel Verkamp usage(argv[0]); 258d4ab30baSDaniel Verkamp exit(0); 259d4ab30baSDaniel Verkamp default: 260d4ab30baSDaniel Verkamp usage(argv[0]); 261d4ab30baSDaniel Verkamp return 1; 262d4ab30baSDaniel Verkamp } 263d4ab30baSDaniel Verkamp } 26447fadb7fSShuhei Matsumoto if (g_user_config.xfer_size_bytes <= 0 || g_user_config.queue_depth <= 0 || 26547fadb7fSShuhei Matsumoto g_user_config.time_in_sec <= 0 || !g_user_config.core_mask || 26647fadb7fSShuhei Matsumoto g_user_config.ioat_chan_num <= 0) { 267d4ab30baSDaniel Verkamp usage(argv[0]); 268d4ab30baSDaniel Verkamp return 1; 269d4ab30baSDaniel Verkamp } 2709f237eacSDaniel Verkamp 271d4ab30baSDaniel Verkamp return 0; 272d4ab30baSDaniel Verkamp } 273d4ab30baSDaniel Verkamp 274d4ab30baSDaniel Verkamp static void 275294e743bSZiye Yang drain_io(struct ioat_chan_entry *ioat_chan_entry) 276d4ab30baSDaniel Verkamp { 2776728c1b8SJim Harris spdk_ioat_flush(ioat_chan_entry->chan); 278294e743bSZiye Yang while (ioat_chan_entry->current_queue_depth > 0) { 279294e743bSZiye Yang spdk_ioat_process_events(ioat_chan_entry->chan); 280d4ab30baSDaniel Verkamp } 281d4ab30baSDaniel Verkamp } 282d4ab30baSDaniel Verkamp 283d4ab30baSDaniel Verkamp static void 284294e743bSZiye Yang submit_single_xfer(struct ioat_chan_entry *ioat_chan_entry, struct ioat_task *ioat_task, void *dst, 285d4ab30baSDaniel Verkamp void *src) 286d4ab30baSDaniel Verkamp { 287294e743bSZiye Yang ioat_task->ioat_chan_entry = ioat_chan_entry; 288d4ab30baSDaniel Verkamp ioat_task->src = src; 289d4ab30baSDaniel Verkamp ioat_task->dst = dst; 290d4ab30baSDaniel Verkamp 2916728c1b8SJim Harris spdk_ioat_build_copy(ioat_chan_entry->chan, ioat_task, ioat_done, dst, src, 292cf0871a5SDaniel Verkamp g_user_config.xfer_size_bytes); 2936728c1b8SJim Harris ioat_chan_entry->waiting_for_flush++; 2946728c1b8SJim Harris if (ioat_chan_entry->waiting_for_flush >= ioat_chan_entry->flush_threshold) { 2956728c1b8SJim Harris spdk_ioat_flush(ioat_chan_entry->chan); 2966728c1b8SJim Harris ioat_chan_entry->waiting_for_flush = 0; 2976728c1b8SJim Harris } 298d4ab30baSDaniel Verkamp 299294e743bSZiye Yang ioat_chan_entry->current_queue_depth++; 300d4ab30baSDaniel Verkamp } 301d4ab30baSDaniel Verkamp 30233c517c5STomasz Zawadzki static int 303294e743bSZiye Yang submit_xfers(struct ioat_chan_entry *ioat_chan_entry, uint64_t queue_depth) 304d4ab30baSDaniel Verkamp { 305d4ab30baSDaniel Verkamp while (queue_depth-- > 0) { 306d4ab30baSDaniel Verkamp void *src = NULL, *dst = NULL; 307d4ab30baSDaniel Verkamp struct ioat_task *ioat_task = NULL; 308d4ab30baSDaniel Verkamp 309294e743bSZiye Yang src = spdk_mempool_get(ioat_chan_entry->data_pool); 310294e743bSZiye Yang dst = spdk_mempool_get(ioat_chan_entry->data_pool); 311294e743bSZiye Yang ioat_task = spdk_mempool_get(ioat_chan_entry->task_pool); 31233c517c5STomasz Zawadzki if (!ioat_task) { 31333c517c5STomasz Zawadzki fprintf(stderr, "Unable to get ioat_task\n"); 314454ff172STomasz Zawadzki return 1; 31533c517c5STomasz Zawadzki } 316d4ab30baSDaniel Verkamp 317294e743bSZiye Yang submit_single_xfer(ioat_chan_entry, ioat_task, dst, src); 318d4ab30baSDaniel Verkamp } 31933c517c5STomasz Zawadzki return 0; 320d4ab30baSDaniel Verkamp } 321d4ab30baSDaniel Verkamp 322d4ab30baSDaniel Verkamp static int 323d4ab30baSDaniel Verkamp work_fn(void *arg) 324d4ab30baSDaniel Verkamp { 325d4ab30baSDaniel Verkamp uint64_t tsc_end; 326294e743bSZiye Yang struct worker_thread *worker = (struct worker_thread *)arg; 327294e743bSZiye Yang struct ioat_chan_entry *t = NULL; 328d4ab30baSDaniel Verkamp 32987d242f9SBen Walker printf("Starting thread on core %u\n", worker->core); 330d4ab30baSDaniel Verkamp 3310aa29864SBen Walker tsc_end = spdk_get_ticks() + g_user_config.time_in_sec * spdk_get_ticks_hz(); 332d4ab30baSDaniel Verkamp 333294e743bSZiye Yang t = worker->ctx; 334294e743bSZiye Yang while (t != NULL) { 3355ed610f6SShuhei Matsumoto /* begin to submit transfers */ 3366728c1b8SJim Harris t->waiting_for_flush = 0; 3376728c1b8SJim Harris t->flush_threshold = g_user_config.queue_depth / 2; 338454ff172STomasz Zawadzki if (submit_xfers(t, g_user_config.queue_depth) != 0) { 339454ff172STomasz Zawadzki return 1; 34033c517c5STomasz Zawadzki } 341294e743bSZiye Yang t = t->next; 342d4ab30baSDaniel Verkamp } 343d4ab30baSDaniel Verkamp 344294e743bSZiye Yang while (1) { 345294e743bSZiye Yang t = worker->ctx; 346294e743bSZiye Yang while (t != NULL) { 347294e743bSZiye Yang spdk_ioat_process_events(t->chan); 348294e743bSZiye Yang t = t->next; 349294e743bSZiye Yang } 350294e743bSZiye Yang 351294e743bSZiye Yang if (spdk_get_ticks() > tsc_end) { 352294e743bSZiye Yang break; 353294e743bSZiye Yang } 354294e743bSZiye Yang } 355294e743bSZiye Yang 356294e743bSZiye Yang t = worker->ctx; 357294e743bSZiye Yang while (t != NULL) { 3585ed610f6SShuhei Matsumoto /* begin to drain io */ 359d4ab30baSDaniel Verkamp t->is_draining = true; 360d4ab30baSDaniel Verkamp drain_io(t); 361294e743bSZiye Yang t = t->next; 362294e743bSZiye Yang } 363d4ab30baSDaniel Verkamp 364d4ab30baSDaniel Verkamp return 0; 365d4ab30baSDaniel Verkamp } 366d4ab30baSDaniel Verkamp 367d4ab30baSDaniel Verkamp static int 368d4ab30baSDaniel Verkamp init(void) 369d4ab30baSDaniel Verkamp { 37018d26e42SBen Walker struct spdk_env_opts opts; 371d4ab30baSDaniel Verkamp 37257fd99b9SJim Harris opts.opts_size = sizeof(opts); 37318d26e42SBen Walker spdk_env_opts_init(&opts); 3749018dd60SJim Harris opts.name = "ioat_perf"; 37518d26e42SBen Walker opts.core_mask = g_user_config.core_mask; 376095f4254SLance Hartmann if (spdk_env_init(&opts) < 0) { 377454ff172STomasz Zawadzki return 1; 378095f4254SLance Hartmann } 379d4ab30baSDaniel Verkamp 380d4ab30baSDaniel Verkamp return 0; 381d4ab30baSDaniel Verkamp } 382d4ab30baSDaniel Verkamp 383d4ab30baSDaniel Verkamp static int 384294e743bSZiye Yang dump_result(void) 385d4ab30baSDaniel Verkamp { 386d4ab30baSDaniel Verkamp uint64_t total_completed = 0; 387d4ab30baSDaniel Verkamp uint64_t total_failed = 0; 388294e743bSZiye Yang uint64_t total_xfer_per_sec, total_bw_in_MiBps; 389294e743bSZiye Yang struct worker_thread *worker = g_workers; 390d4ab30baSDaniel Verkamp 39187d242f9SBen Walker printf("Channel_ID Core Transfers Bandwidth Failed\n"); 392294e743bSZiye Yang printf("-----------------------------------------------------------\n"); 393294e743bSZiye Yang while (worker != NULL) { 394294e743bSZiye Yang struct ioat_chan_entry *t = worker->ctx; 395294e743bSZiye Yang while (t) { 396d4ab30baSDaniel Verkamp uint64_t xfer_per_sec = t->xfer_completed / g_user_config.time_in_sec; 397294e743bSZiye Yang uint64_t bw_in_MiBps = (t->xfer_completed * g_user_config.xfer_size_bytes) / 398d4ab30baSDaniel Verkamp (g_user_config.time_in_sec * 1024 * 1024); 399d4ab30baSDaniel Verkamp 400d4ab30baSDaniel Verkamp total_completed += t->xfer_completed; 401d4ab30baSDaniel Verkamp total_failed += t->xfer_failed; 402d4ab30baSDaniel Verkamp 403d4ab30baSDaniel Verkamp if (xfer_per_sec) { 404294e743bSZiye Yang printf("%10d%10d%12" PRIu64 "/s%8" PRIu64 " MiB/s%11" PRIu64 "\n", 40587d242f9SBen Walker t->ioat_chan_id, worker->core, xfer_per_sec, 406294e743bSZiye Yang bw_in_MiBps, t->xfer_failed); 407d4ab30baSDaniel Verkamp } 408294e743bSZiye Yang t = t->next; 409294e743bSZiye Yang } 410294e743bSZiye Yang worker = worker->next; 411d4ab30baSDaniel Verkamp } 412d4ab30baSDaniel Verkamp 413d4ab30baSDaniel Verkamp total_xfer_per_sec = total_completed / g_user_config.time_in_sec; 414294e743bSZiye Yang total_bw_in_MiBps = (total_completed * g_user_config.xfer_size_bytes) / 415d4ab30baSDaniel Verkamp (g_user_config.time_in_sec * 1024 * 1024); 416d4ab30baSDaniel Verkamp 417294e743bSZiye Yang printf("===========================================================\n"); 418294e743bSZiye Yang printf("Total:%26" PRIu64 "/s%8" PRIu64 " MiB/s%11" PRIu64 "\n", 419294e743bSZiye Yang total_xfer_per_sec, total_bw_in_MiBps, total_failed); 420294e743bSZiye Yang 421d4ab30baSDaniel Verkamp return total_failed ? 1 : 0; 422d4ab30baSDaniel Verkamp } 423d4ab30baSDaniel Verkamp 424cf0871a5SDaniel Verkamp static struct spdk_ioat_chan * 425cf0871a5SDaniel Verkamp get_next_chan(void) 426cf0871a5SDaniel Verkamp { 427cf0871a5SDaniel Verkamp struct spdk_ioat_chan *chan; 428cf0871a5SDaniel Verkamp 429cf0871a5SDaniel Verkamp if (g_next_device == NULL) { 430cf0871a5SDaniel Verkamp return NULL; 431cf0871a5SDaniel Verkamp } 432cf0871a5SDaniel Verkamp 433cf0871a5SDaniel Verkamp chan = g_next_device->ioat; 434cf0871a5SDaniel Verkamp 435cf0871a5SDaniel Verkamp g_next_device = TAILQ_NEXT(g_next_device, tailq); 436cf0871a5SDaniel Verkamp 437cf0871a5SDaniel Verkamp return chan; 438cf0871a5SDaniel Verkamp } 439cf0871a5SDaniel Verkamp 440294e743bSZiye Yang static int 441294e743bSZiye Yang associate_workers_with_chan(void) 442294e743bSZiye Yang { 443294e743bSZiye Yang struct spdk_ioat_chan *chan = get_next_chan(); 444294e743bSZiye Yang struct worker_thread *worker = g_workers; 445294e743bSZiye Yang struct ioat_chan_entry *t; 4469699e32dSDaniel Verkamp char buf_pool_name[30], task_pool_name[30]; 447294e743bSZiye Yang int i = 0; 448294e743bSZiye Yang 449294e743bSZiye Yang while (chan != NULL) { 450294e743bSZiye Yang t = calloc(1, sizeof(struct ioat_chan_entry)); 451294e743bSZiye Yang if (!t) { 452454ff172STomasz Zawadzki return 1; 453294e743bSZiye Yang } 454294e743bSZiye Yang 455294e743bSZiye Yang t->ioat_chan_id = i; 456294e743bSZiye Yang snprintf(buf_pool_name, sizeof(buf_pool_name), "buf_pool_%d", i); 457294e743bSZiye Yang snprintf(task_pool_name, sizeof(task_pool_name), "task_pool_%d", i); 4585ec6b08eSJim Harris t->data_pool = spdk_mempool_create(buf_pool_name, 4595ec6b08eSJim Harris g_user_config.queue_depth * 2, /* src + dst */ 4605ec6b08eSJim Harris g_user_config.xfer_size_bytes, 461053d5733SBen Walker SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 462*186b109dSJim Harris SPDK_ENV_NUMA_ID_ANY); 4635ec6b08eSJim Harris t->task_pool = spdk_mempool_create(task_pool_name, 4645ec6b08eSJim Harris g_user_config.queue_depth, 4655ec6b08eSJim Harris sizeof(struct ioat_task), 466053d5733SBen Walker SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 467*186b109dSJim Harris SPDK_ENV_NUMA_ID_ANY); 468294e743bSZiye Yang if (!t->data_pool || !t->task_pool) { 469294e743bSZiye Yang fprintf(stderr, "Could not allocate buffer pool.\n"); 470294e743bSZiye Yang spdk_mempool_free(t->data_pool); 471294e743bSZiye Yang spdk_mempool_free(t->task_pool); 472294e743bSZiye Yang free(t); 473294e743bSZiye Yang return 1; 474294e743bSZiye Yang } 47587d242f9SBen Walker printf("Associating ioat_channel %d with core %d\n", i, worker->core); 476294e743bSZiye Yang t->chan = chan; 477294e743bSZiye Yang t->next = worker->ctx; 478294e743bSZiye Yang worker->ctx = t; 479294e743bSZiye Yang 480294e743bSZiye Yang worker = worker->next; 481294e743bSZiye Yang if (worker == NULL) { 482294e743bSZiye Yang worker = g_workers; 483294e743bSZiye Yang } 484294e743bSZiye Yang 485294e743bSZiye Yang chan = get_next_chan(); 486294e743bSZiye Yang i++; 487294e743bSZiye Yang } 488294e743bSZiye Yang 489294e743bSZiye Yang return 0; 490294e743bSZiye Yang } 491294e743bSZiye Yang 492d4ab30baSDaniel Verkamp int 493d4ab30baSDaniel Verkamp main(int argc, char **argv) 494d4ab30baSDaniel Verkamp { 49525cad6ffSDaniel Verkamp int rc; 49687b21afdSJim Harris struct worker_thread *worker, *main_worker; 49787b21afdSJim Harris unsigned main_core; 498d4ab30baSDaniel Verkamp 499d4ab30baSDaniel Verkamp if (parse_args(argc, argv) != 0) { 500d4ab30baSDaniel Verkamp return 1; 501d4ab30baSDaniel Verkamp } 502d4ab30baSDaniel Verkamp 503d4ab30baSDaniel Verkamp if (init() != 0) { 504d4ab30baSDaniel Verkamp return 1; 505d4ab30baSDaniel Verkamp } 506d4ab30baSDaniel Verkamp 507294e743bSZiye Yang if (register_workers() != 0) { 508454ff172STomasz Zawadzki rc = 1; 509294e743bSZiye Yang goto cleanup; 510294e743bSZiye Yang } 511294e743bSZiye Yang 512294e743bSZiye Yang if (ioat_init() != 0) { 513454ff172STomasz Zawadzki rc = 1; 514294e743bSZiye Yang goto cleanup; 515294e743bSZiye Yang } 516294e743bSZiye Yang 5176a939460SDaniel Verkamp if (g_ioat_chan_num == 0) { 5186a939460SDaniel Verkamp printf("No channels found\n"); 519454ff172STomasz Zawadzki rc = 1; 5206a939460SDaniel Verkamp goto cleanup; 5216a939460SDaniel Verkamp } 5226a939460SDaniel Verkamp 523294e743bSZiye Yang if (g_user_config.ioat_chan_num > g_ioat_chan_num) { 524294e743bSZiye Yang printf("%d channels are requested, but only %d are found," 525294e743bSZiye Yang "so only test %d channels\n", g_user_config.ioat_chan_num, 526294e743bSZiye Yang g_ioat_chan_num, g_ioat_chan_num); 527294e743bSZiye Yang g_user_config.ioat_chan_num = g_ioat_chan_num; 528294e743bSZiye Yang } 529d4ab30baSDaniel Verkamp 530cf0871a5SDaniel Verkamp g_next_device = TAILQ_FIRST(&g_devices); 531294e743bSZiye Yang dump_user_config(&g_user_config); 532d4ab30baSDaniel Verkamp 533294e743bSZiye Yang if (associate_workers_with_chan() != 0) { 534454ff172STomasz Zawadzki rc = 1; 53525cad6ffSDaniel Verkamp goto cleanup; 536d4ab30baSDaniel Verkamp } 537d4ab30baSDaniel Verkamp 53887b21afdSJim Harris /* Launch all of the secondary workers */ 53987b21afdSJim Harris main_core = spdk_env_get_current_core(); 54087b21afdSJim Harris main_worker = NULL; 54184230409SBen Walker worker = g_workers; 542294e743bSZiye Yang while (worker != NULL) { 54387b21afdSJim Harris if (worker->core != main_core) { 544939df28eSDaniel Verkamp spdk_env_thread_launch_pinned(worker->core, work_fn, worker); 54584230409SBen Walker } else { 54687b21afdSJim Harris assert(main_worker == NULL); 54787b21afdSJim Harris main_worker = worker; 54884230409SBen Walker } 549294e743bSZiye Yang worker = worker->next; 550d4ab30baSDaniel Verkamp } 551d4ab30baSDaniel Verkamp 55287b21afdSJim Harris assert(main_worker != NULL); 55387b21afdSJim Harris rc = work_fn(main_worker); 554454ff172STomasz Zawadzki if (rc != 0) { 555294e743bSZiye Yang goto cleanup; 556294e743bSZiye Yang } 557294e743bSZiye Yang 558939df28eSDaniel Verkamp spdk_env_thread_wait_all(); 559294e743bSZiye Yang 560294e743bSZiye Yang rc = dump_result(); 56125cad6ffSDaniel Verkamp 56225cad6ffSDaniel Verkamp cleanup: 563294e743bSZiye Yang unregister_workers(); 56425cad6ffSDaniel Verkamp ioat_exit(); 56525cad6ffSDaniel Verkamp 566abcc84acSChangpeng Liu spdk_env_fini(); 56725cad6ffSDaniel Verkamp return rc; 568d4ab30baSDaniel Verkamp } 569