4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "spdk/stdinc.h"
38 #include "spdk/nvme.h"
39 #include "spdk/queue.h"
40 #include "spdk/string.h"
41 #include "spdk/util.h"
42 #include "spdk/likely.h"
45 struct spdk_nvme_ctrlr
*ctrlr
;
46 enum spdk_nvme_transport_type trtype
;
48 struct ctrlr_entry
*next
;
53 struct spdk_nvme_ctrlr
*ctrlr
;
54 struct spdk_nvme_ns
*ns
;
56 struct ns_entry
*next
;
57 uint32_t io_size_blocks
;
58 uint32_t num_io_requests
;
64 struct ctrlr_worker_ctx
{
65 pthread_mutex_t mutex
;
66 struct ctrlr_entry
*entry
;
67 uint64_t abort_submitted
;
68 uint64_t abort_submit_failed
;
69 uint64_t successful_abort
;
70 uint64_t unsuccessful_abort
;
71 uint64_t abort_failed
;
72 uint64_t current_queue_depth
;
73 struct spdk_nvme_ctrlr
*ctrlr
;
74 struct ctrlr_worker_ctx
*next
;
77 struct ns_worker_ctx
{
78 struct ns_entry
*entry
;
79 uint64_t io_submitted
;
80 uint64_t io_completed
;
83 uint64_t current_queue_depth
;
84 uint64_t offset_in_ios
;
86 struct spdk_nvme_qpair
*qpair
;
87 struct ctrlr_worker_ctx
*ctrlr_ctx
;
88 struct ns_worker_ctx
*next
;
92 struct ns_worker_ctx
*ns_ctx
;
96 struct worker_thread
{
97 struct ns_worker_ctx
*ns_ctx
;
98 struct ctrlr_worker_ctx
*ctrlr_ctx
;
99 struct worker_thread
*next
;
103 static const char *g_workload_type
= "read";
104 static struct ctrlr_entry
*g_controllers
;
105 static struct ns_entry
*g_namespaces
;
106 static int g_num_namespaces
;
107 static struct worker_thread
*g_workers
;
108 static int g_num_workers
;
109 static uint32_t g_master_core
;
111 static int g_abort_interval
= 1;
113 static uint64_t g_tsc_rate
;
115 static uint32_t g_io_size_bytes
= 131072;
116 static uint32_t g_max_io_size_blocks
;
117 static int g_rw_percentage
= -1;
118 static int g_is_random
;
119 static int g_queue_depth
= 128;
120 static int g_time_in_sec
= 3;
121 static int g_dpdk_mem
;
122 static int g_shm_id
= -1;
123 static bool g_no_pci
;
125 static bool g_mix_specified
;
127 static const char *g_core_mask
;
130 struct spdk_nvme_transport_id trid
;
132 TAILQ_ENTRY(trid_entry
) tailq
;
135 static TAILQ_HEAD(, trid_entry
) g_trid_list
= TAILQ_HEAD_INITIALIZER(g_trid_list
);
137 static void io_complete(void *ctx
, const struct spdk_nvme_cpl
*cpl
);
140 build_nvme_name(char *name
, size_t length
, struct spdk_nvme_ctrlr
*ctrlr
)
142 const struct spdk_nvme_transport_id
*trid
;
145 trid
= spdk_nvme_ctrlr_get_transport_id(ctrlr
);
147 switch (trid
->trtype
) {
148 case SPDK_NVME_TRANSPORT_PCIE
:
149 res
= snprintf(name
, length
, "PCIE (%s)", trid
->traddr
);
151 case SPDK_NVME_TRANSPORT_RDMA
:
152 res
= snprintf(name
, length
, "RDMA (addr:%s subnqn:%s)", trid
->traddr
, trid
->subnqn
);
154 case SPDK_NVME_TRANSPORT_TCP
:
155 res
= snprintf(name
, length
, "TCP (addr:%s subnqn:%s)", trid
->traddr
, trid
->subnqn
);
159 fprintf(stderr
, "Unknown transport type %d\n", trid
->trtype
);
166 build_nvme_ns_name(char *name
, size_t length
, struct spdk_nvme_ctrlr
*ctrlr
, uint32_t nsid
)
170 res
= build_nvme_name(name
, length
, ctrlr
);
172 snprintf(name
+ res
, length
- res
, " NSID %u", nsid
);
178 register_ns(struct spdk_nvme_ctrlr
*ctrlr
, struct spdk_nvme_ns
*ns
)
180 struct ns_entry
*entry
;
181 const struct spdk_nvme_ctrlr_data
*cdata
;
182 uint32_t max_xfer_size
, entries
, sector_size
;
184 struct spdk_nvme_io_qpair_opts opts
;
186 cdata
= spdk_nvme_ctrlr_get_data(ctrlr
);
188 if (!spdk_nvme_ns_is_active(ns
)) {
189 printf("Controller %-20.20s (%-20.20s): Skipping inactive NS %u\n",
190 cdata
->mn
, cdata
->sn
,
191 spdk_nvme_ns_get_id(ns
));
196 ns_size
= spdk_nvme_ns_get_size(ns
);
197 sector_size
= spdk_nvme_ns_get_sector_size(ns
);
199 if (ns_size
< g_io_size_bytes
|| sector_size
> g_io_size_bytes
) {
200 printf("WARNING: controller %-20.20s (%-20.20s) ns %u has invalid "
201 "ns size %" PRIu64
" / block size %u for I/O size %u\n",
202 cdata
->mn
, cdata
->sn
, spdk_nvme_ns_get_id(ns
),
203 ns_size
, spdk_nvme_ns_get_sector_size(ns
), g_io_size_bytes
);
208 max_xfer_size
= spdk_nvme_ns_get_max_io_xfer_size(ns
);
209 spdk_nvme_ctrlr_get_default_io_qpair_opts(ctrlr
, &opts
, sizeof(opts
));
210 /* NVMe driver may add additional entries based on
211 * stripe size and maximum transfer size, we assume
212 * 1 more entry be used for stripe.
214 entries
= (g_io_size_bytes
- 1) / max_xfer_size
+ 2;
215 if ((g_queue_depth
* entries
) > opts
.io_queue_size
) {
216 printf("controller IO queue size %u less than required\n",
218 printf("Consider using lower queue depth or small IO size because "
219 "IO requests may be queued at the NVMe driver.\n");
221 /* For requests which have children requests, parent request itself
222 * will also occupy 1 entry.
226 entry
= calloc(1, sizeof(struct ns_entry
));
228 perror("ns_entry malloc");
232 entry
->ctrlr
= ctrlr
;
234 entry
->num_io_requests
= g_queue_depth
* entries
;
236 entry
->size_in_ios
= ns_size
/ g_io_size_bytes
;
237 entry
->io_size_blocks
= g_io_size_bytes
/ sector_size
;
239 entry
->block_size
= spdk_nvme_ns_get_sector_size(ns
);
241 if (g_max_io_size_blocks
< entry
->io_size_blocks
) {
242 g_max_io_size_blocks
= entry
->io_size_blocks
;
245 build_nvme_ns_name(entry
->name
, sizeof(entry
->name
), ctrlr
, spdk_nvme_ns_get_id(ns
));
248 entry
->next
= g_namespaces
;
249 g_namespaces
= entry
;
253 unregister_namespaces(void)
255 struct ns_entry
*entry
= g_namespaces
;
258 struct ns_entry
*next
= entry
->next
;
265 register_ctrlr(struct spdk_nvme_ctrlr
*ctrlr
, struct trid_entry
*trid_entry
)
267 struct spdk_nvme_ns
*ns
;
268 struct ctrlr_entry
*entry
= malloc(sizeof(struct ctrlr_entry
));
272 perror("ctrlr_entry malloc");
276 build_nvme_name(entry
->name
, sizeof(entry
->name
), ctrlr
);
278 entry
->ctrlr
= ctrlr
;
279 entry
->trtype
= trid_entry
->trid
.trtype
;
280 entry
->next
= g_controllers
;
281 g_controllers
= entry
;
283 if (trid_entry
->nsid
== 0) {
284 for (nsid
= spdk_nvme_ctrlr_get_first_active_ns(ctrlr
);
285 nsid
!= 0; nsid
= spdk_nvme_ctrlr_get_next_active_ns(ctrlr
, nsid
)) {
286 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, nsid
);
290 register_ns(ctrlr
, ns
);
293 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, trid_entry
->nsid
);
295 perror("Namespace does not exist.");
299 register_ns(ctrlr
, ns
);
304 abort_complete(void *ctx
, const struct spdk_nvme_cpl
*cpl
)
306 struct ctrlr_worker_ctx
*ctrlr_ctx
= ctx
;
308 ctrlr_ctx
->current_queue_depth
--;
309 if (spdk_unlikely(spdk_nvme_cpl_is_error(cpl
))) {
310 ctrlr_ctx
->abort_failed
++;
311 } else if ((cpl
->cdw0
& 0x1) == 0) {
312 ctrlr_ctx
->successful_abort
++;
314 ctrlr_ctx
->unsuccessful_abort
++;
319 abort_task(struct perf_task
*task
)
321 struct ns_worker_ctx
*ns_ctx
= task
->ns_ctx
;
322 struct ctrlr_worker_ctx
*ctrlr_ctx
= ns_ctx
->ctrlr_ctx
;
325 /* Hold mutex to guard ctrlr_ctx->current_queue_depth. */
326 pthread_mutex_lock(&ctrlr_ctx
->mutex
);
328 rc
= spdk_nvme_ctrlr_cmd_abort_ext(ctrlr_ctx
->ctrlr
, ns_ctx
->qpair
, task
, abort_complete
,
331 if (spdk_unlikely(rc
!= 0)) {
332 ctrlr_ctx
->abort_submit_failed
++;
334 ctrlr_ctx
->current_queue_depth
++;
335 ctrlr_ctx
->abort_submitted
++;
338 pthread_mutex_unlock(&ctrlr_ctx
->mutex
);
341 static __thread
unsigned int seed
= 0;
344 submit_single_io(struct perf_task
*task
)
346 uint64_t offset_in_ios
, lba
;
348 struct ns_worker_ctx
*ns_ctx
= task
->ns_ctx
;
349 struct ns_entry
*entry
= ns_ctx
->entry
;
352 offset_in_ios
= rand_r(&seed
) % entry
->size_in_ios
;
354 offset_in_ios
= ns_ctx
->offset_in_ios
++;
355 if (ns_ctx
->offset_in_ios
== entry
->size_in_ios
) {
356 ns_ctx
->offset_in_ios
= 0;
360 lba
= offset_in_ios
* entry
->io_size_blocks
;
362 if ((g_rw_percentage
== 100) ||
363 (g_rw_percentage
!= 0 && (rand_r(&seed
) % 100) < g_rw_percentage
)) {
364 rc
= spdk_nvme_ns_cmd_read(entry
->ns
, ns_ctx
->qpair
, task
->buf
,
365 lba
, entry
->io_size_blocks
, io_complete
, task
, 0);
367 rc
= spdk_nvme_ns_cmd_write(entry
->ns
, ns_ctx
->qpair
, task
->buf
,
368 lba
, entry
->io_size_blocks
, io_complete
, task
, 0);
371 if (spdk_unlikely(rc
!= 0)) {
372 fprintf(stderr
, "I/O submission failed\n");
374 ns_ctx
->current_queue_depth
++;
375 ns_ctx
->io_submitted
++;
377 if ((ns_ctx
->io_submitted
% g_abort_interval
) == 0) {
385 io_complete(void *ctx
, const struct spdk_nvme_cpl
*cpl
)
387 struct perf_task
*task
= ctx
;
388 struct ns_worker_ctx
*ns_ctx
= task
->ns_ctx
;
390 ns_ctx
->current_queue_depth
--;
391 if (spdk_unlikely(spdk_nvme_cpl_is_error(cpl
))) {
394 ns_ctx
->io_completed
++;
397 /* is_draining indicates when time has expired for the test run and we are
398 * just waiting for the previously submitted I/O to complete. In this case,
399 * do not submit a new I/O to replace the one just completed.
401 if (spdk_unlikely(ns_ctx
->is_draining
)) {
402 spdk_dma_free(task
->buf
);
405 submit_single_io(task
);
409 static struct perf_task
*
410 allocate_task(struct ns_worker_ctx
*ns_ctx
)
412 struct perf_task
*task
;
414 task
= calloc(1, sizeof(*task
));
416 fprintf(stderr
, "Failed to allocate task\n");
420 task
->buf
= spdk_dma_zmalloc(g_io_size_bytes
, 0x200, NULL
);
421 if (task
->buf
== NULL
) {
423 fprintf(stderr
, "Failed to allocate task->buf\n");
427 task
->ns_ctx
= ns_ctx
;
433 submit_io(struct ns_worker_ctx
*ns_ctx
, int queue_depth
)
435 struct perf_task
*task
;
437 while (queue_depth
-- > 0) {
438 task
= allocate_task(ns_ctx
);
439 submit_single_io(task
);
446 struct worker_thread
*worker
= (struct worker_thread
*)arg
;
447 struct ns_worker_ctx
*ns_ctx
;
448 struct ctrlr_worker_ctx
*ctrlr_ctx
;
449 struct ns_entry
*ns_entry
;
450 struct spdk_nvme_io_qpair_opts opts
;
452 uint32_t unfinished_ctx
;
454 /* Allocate queue pair for each namespace. */
455 ns_ctx
= worker
->ns_ctx
;
456 while (ns_ctx
!= NULL
) {
457 ns_entry
= ns_ctx
->entry
;
459 spdk_nvme_ctrlr_get_default_io_qpair_opts(ns_entry
->ctrlr
, &opts
, sizeof(opts
));
460 if (opts
.io_queue_requests
< ns_entry
->num_io_requests
) {
461 opts
.io_queue_requests
= ns_entry
->num_io_requests
;
464 ns_ctx
->qpair
= spdk_nvme_ctrlr_alloc_io_qpair(ns_entry
->ctrlr
, &opts
, sizeof(opts
));
465 if (ns_ctx
->qpair
== NULL
) {
466 fprintf(stderr
, "spdk_nvme_ctrlr_alloc_io_qpair failed\n");
470 ns_ctx
= ns_ctx
->next
;
473 tsc_end
= spdk_get_ticks() + g_time_in_sec
* g_tsc_rate
;
475 /* Submit initial I/O for each namespace. */
476 ns_ctx
= worker
->ns_ctx
;
477 while (ns_ctx
!= NULL
) {
478 submit_io(ns_ctx
, g_queue_depth
);
479 ns_ctx
= ns_ctx
->next
;
483 ns_ctx
= worker
->ns_ctx
;
484 while (ns_ctx
!= NULL
) {
485 spdk_nvme_qpair_process_completions(ns_ctx
->qpair
, 0);
486 ns_ctx
= ns_ctx
->next
;
489 if (worker
->lcore
== g_master_core
) {
490 ctrlr_ctx
= worker
->ctrlr_ctx
;
492 /* Hold mutex to guard ctrlr_ctx->current_queue_depth. */
493 pthread_mutex_lock(&ctrlr_ctx
->mutex
);
494 spdk_nvme_ctrlr_process_admin_completions(ctrlr_ctx
->ctrlr
);
495 pthread_mutex_unlock(&ctrlr_ctx
->mutex
);
496 ctrlr_ctx
= ctrlr_ctx
->next
;
500 if (spdk_get_ticks() > tsc_end
) {
508 ns_ctx
= worker
->ns_ctx
;
509 while (ns_ctx
!= NULL
) {
510 if (!ns_ctx
->is_draining
) {
511 ns_ctx
->is_draining
= true;
513 if (ns_ctx
->current_queue_depth
> 0) {
514 spdk_nvme_qpair_process_completions(ns_ctx
->qpair
, 0);
515 if (ns_ctx
->current_queue_depth
== 0) {
516 spdk_nvme_ctrlr_free_io_qpair(ns_ctx
->qpair
);
521 ns_ctx
= ns_ctx
->next
;
523 } while (unfinished_ctx
> 0);
525 if (worker
->lcore
== g_master_core
) {
529 ctrlr_ctx
= worker
->ctrlr_ctx
;
530 while (ctrlr_ctx
!= NULL
) {
531 pthread_mutex_lock(&ctrlr_ctx
->mutex
);
532 if (ctrlr_ctx
->current_queue_depth
> 0) {
533 spdk_nvme_ctrlr_process_admin_completions(ctrlr_ctx
->ctrlr
);
534 if (ctrlr_ctx
->current_queue_depth
> 0) {
538 pthread_mutex_unlock(&ctrlr_ctx
->mutex
);
539 ctrlr_ctx
= ctrlr_ctx
->next
;
541 } while (unfinished_ctx
> 0);
548 usage(char *program_name
)
550 printf("%s options", program_name
);
553 printf("\t[-q io depth]\n");
554 printf("\t[-o io size in bytes]\n");
555 printf("\t[-w io pattern type, must be one of\n");
556 printf("\t\t(read, write, randread, randwrite, rw, randrw)]\n");
557 printf("\t[-M rwmixread (100 for reads, 0 for writes)]\n");
558 printf("\t[-t time in seconds]\n");
559 printf("\t[-c core mask for I/O submission/completion.]\n");
560 printf("\t\t(default: 1)\n");
561 printf("\t[-r Transport ID for local PCIe NVMe or NVMeoF]\n");
562 printf("\t Format: 'key:value [key:value] ...'\n");
563 printf("\t Keys:\n");
564 printf("\t trtype Transport type (e.g. PCIe, RDMA)\n");
565 printf("\t adrfam Address family (e.g. IPv4, IPv6)\n");
566 printf("\t traddr Transport address (e.g. 0000:04:00.0 for PCIe or 192.168.100.8 for RDMA)\n");
567 printf("\t trsvcid Transport service identifier (e.g. 4420)\n");
568 printf("\t subnqn Subsystem NQN (default: %s)\n", SPDK_NVMF_DISCOVERY_NQN
);
569 printf("\t Example: -r 'trtype:PCIe traddr:0000:04:00.0' for PCIe or\n");
570 printf("\t -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420' for NVMeoF\n");
571 printf("\t[-s DPDK huge memory size in MB.]\n");
572 printf("\t[-i shared memory group ID]\n");
573 printf("\t[-a abort interval.]\n");
575 spdk_log_usage(stdout
, "-T");
577 printf("\t[-G enable debug logging]\n");
579 printf("\t[-G enable debug logging (flag disabled, must reconfigure with --enable-debug)\n");
584 unregister_trids(void)
586 struct trid_entry
*trid_entry
, *tmp
;
588 TAILQ_FOREACH_SAFE(trid_entry
, &g_trid_list
, tailq
, tmp
) {
589 TAILQ_REMOVE(&g_trid_list
, trid_entry
, tailq
);
595 add_trid(const char *trid_str
)
597 struct trid_entry
*trid_entry
;
598 struct spdk_nvme_transport_id
*trid
;
601 trid_entry
= calloc(1, sizeof(*trid_entry
));
602 if (trid_entry
== NULL
) {
606 trid
= &trid_entry
->trid
;
607 trid
->trtype
= SPDK_NVME_TRANSPORT_PCIE
;
608 snprintf(trid
->subnqn
, sizeof(trid
->subnqn
), "%s", SPDK_NVMF_DISCOVERY_NQN
);
610 if (spdk_nvme_transport_id_parse(trid
, trid_str
) != 0) {
611 fprintf(stderr
, "Invalid transport ID format '%s'\n", trid_str
);
616 spdk_nvme_transport_id_populate_trstring(trid
,
617 spdk_nvme_transport_id_trtype_str(trid
->trtype
));
619 ns
= strcasestr(trid_str
, "ns:");
621 char nsid_str
[6]; /* 5 digits maximum in an nsid */
627 len
= strcspn(ns
, " \t\n");
629 fprintf(stderr
, "NVMe namespace IDs must be 5 digits or less\n");
634 memcpy(nsid_str
, ns
, len
);
635 nsid_str
[len
] = '\0';
637 nsid
= spdk_strtol(nsid_str
, 10);
638 if (nsid
<= 0 || nsid
> 65535) {
639 fprintf(stderr
, "NVMe namespace IDs must be less than 65536 and greater than 0\n");
644 trid_entry
->nsid
= (uint16_t)nsid
;
647 TAILQ_INSERT_TAIL(&g_trid_list
, trid_entry
, tailq
);
652 parse_args(int argc
, char **argv
)
658 while ((op
= getopt(argc
, argv
, "a:c:i:o:q:r:s:t:w:M:")) != -1) {
667 val
= spdk_strtol(optarg
, 10);
669 fprintf(stderr
, "Converting a string to integer failed\n");
674 g_abort_interval
= val
;
680 g_io_size_bytes
= val
;
692 g_rw_percentage
= val
;
693 g_mix_specified
= true;
698 g_core_mask
= optarg
;
701 if (add_trid(optarg
)) {
707 g_workload_type
= optarg
;
711 fprintf(stderr
, "%s must be configured with --enable-debug for -G flag\n",
716 spdk_log_set_flag("nvme");
717 spdk_log_set_print_level(SPDK_LOG_DEBUG
);
721 rc
= spdk_log_set_flag(optarg
);
723 fprintf(stderr
, "unknown flag\n");
727 spdk_log_set_print_level(SPDK_LOG_DEBUG
);
729 fprintf(stderr
, "%s must be rebuilt with CONFIG_DEBUG=y for -T flag.\n",
741 if (!g_queue_depth
) {
742 fprintf(stderr
, "missing -q (queue size) operand\n");
746 if (!g_io_size_bytes
) {
747 fprintf(stderr
, "missing -o (block size) operand\n");
751 if (!g_workload_type
) {
752 fprintf(stderr
, "missing -t (test time in seconds) operand\n");
757 if (!g_time_in_sec
) {
762 if (strncmp(g_workload_type
, "rand", 4) == 0) {
764 g_workload_type
= &g_workload_type
[4];
767 if (strcmp(g_workload_type
, "read") == 0 || strcmp(g_workload_type
, "write") == 0) {
768 g_rw_percentage
= strcmp(g_workload_type
, "read") == 0 ? 100 : 0;
769 if (g_mix_specified
) {
770 fprintf(stderr
, "Ignoring -M option... Please use -M option"
771 " only when using rw or randrw.\n");
773 } else if (strcmp(g_workload_type
, "rw") == 0) {
774 if (g_rw_percentage
< 0 || g_rw_percentage
> 100) {
776 "-M must be specified to value from 0 to 100 "
777 "for rw or randrw.\n");
782 "io pattern type must be one of\n"
783 "(read, write, randread, randwrite, rw, randrw)\n");
787 if (TAILQ_EMPTY(&g_trid_list
)) {
788 /* If no transport IDs specified, default to enumerating all local PCIe devices */
789 add_trid("trtype:PCIe");
791 struct trid_entry
*trid_entry
, *trid_entry_tmp
;
794 /* check whether there is local PCIe type */
795 TAILQ_FOREACH_SAFE(trid_entry
, &g_trid_list
, tailq
, trid_entry_tmp
) {
796 if (trid_entry
->trid
.trtype
== SPDK_NVME_TRANSPORT_PCIE
) {
807 register_workers(void)
810 struct worker_thread
*worker
;
815 SPDK_ENV_FOREACH_CORE(i
) {
816 worker
= calloc(1, sizeof(*worker
));
817 if (worker
== NULL
) {
818 fprintf(stderr
, "Unable to allocate worker\n");
823 worker
->next
= g_workers
;
832 unregister_workers(void)
834 struct worker_thread
*worker
= g_workers
;
836 /* Free namespace context and worker thread */
838 struct worker_thread
*next_worker
= worker
->next
;
839 struct ns_worker_ctx
*ns_ctx
= worker
->ns_ctx
;
842 struct ns_worker_ctx
*next_ns_ctx
= ns_ctx
->next
;
844 printf("NS: %s I/O completed: %lu, failed: %lu\n",
845 ns_ctx
->entry
->name
, ns_ctx
->io_completed
, ns_ctx
->io_failed
);
847 ns_ctx
= next_ns_ctx
;
850 struct ctrlr_worker_ctx
*ctrlr_ctx
= worker
->ctrlr_ctx
;
853 struct ctrlr_worker_ctx
*next_ctrlr_ctx
= ctrlr_ctx
->next
;
855 printf("CTRLR: %s abort submitted %lu, failed to submit %lu\n",
856 ctrlr_ctx
->entry
->name
, ctrlr_ctx
->abort_submitted
,
857 ctrlr_ctx
->abort_submit_failed
);
858 printf("\t success %lu, unsuccess %lu, failed %lu\n",
859 ctrlr_ctx
->successful_abort
, ctrlr_ctx
->unsuccessful_abort
,
860 ctrlr_ctx
->abort_failed
);
862 ctrlr_ctx
= next_ctrlr_ctx
;
866 worker
= next_worker
;
871 probe_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
872 struct spdk_nvme_ctrlr_opts
*opts
)
878 attach_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
879 struct spdk_nvme_ctrlr
*ctrlr
, const struct spdk_nvme_ctrlr_opts
*opts
)
881 struct trid_entry
*trid_entry
= cb_ctx
;
882 struct spdk_pci_addr pci_addr
;
883 struct spdk_pci_device
*pci_dev
;
884 struct spdk_pci_id pci_id
;
886 if (trid
->trtype
!= SPDK_NVME_TRANSPORT_PCIE
) {
887 printf("Attached to NVMe over Fabrics controller at %s:%s: %s\n",
888 trid
->traddr
, trid
->trsvcid
,
891 if (spdk_pci_addr_parse(&pci_addr
, trid
->traddr
)) {
895 pci_dev
= spdk_nvme_ctrlr_get_pci_device(ctrlr
);
900 pci_id
= spdk_pci_device_get_id(pci_dev
);
902 printf("Attached to NVMe Controller at %s [%04x:%04x]\n",
904 pci_id
.vendor_id
, pci_id
.device_id
);
907 register_ctrlr(ctrlr
, trid_entry
);
911 register_controllers(void)
913 struct trid_entry
*trid_entry
;
915 printf("Initializing NVMe Controllers\n");
917 TAILQ_FOREACH(trid_entry
, &g_trid_list
, tailq
) {
918 if (spdk_nvme_probe(&trid_entry
->trid
, trid_entry
, probe_cb
, attach_cb
, NULL
) != 0) {
919 fprintf(stderr
, "spdk_nvme_probe() failed for transport address '%s'\n",
920 trid_entry
->trid
.traddr
);
929 unregister_controllers(void)
931 struct ctrlr_entry
*entry
= g_controllers
;
934 struct ctrlr_entry
*next
= entry
->next
;
935 spdk_nvme_detach(entry
->ctrlr
);
942 associate_master_worker_with_ctrlr(void)
944 struct ctrlr_entry
*entry
= g_controllers
;
945 struct worker_thread
*worker
= g_workers
;
946 struct ctrlr_worker_ctx
*ctrlr_ctx
;
949 if (worker
->lcore
== g_master_core
) {
952 worker
= worker
->next
;
960 ctrlr_ctx
= calloc(1, sizeof(struct ctrlr_worker_ctx
));
965 pthread_mutex_init(&ctrlr_ctx
->mutex
, NULL
);
966 ctrlr_ctx
->entry
= entry
;
967 ctrlr_ctx
->ctrlr
= entry
->ctrlr
;
968 ctrlr_ctx
->next
= worker
->ctrlr_ctx
;
969 worker
->ctrlr_ctx
= ctrlr_ctx
;
977 static struct ctrlr_worker_ctx
*
978 get_ctrlr_worker_ctx(struct spdk_nvme_ctrlr
*ctrlr
)
980 struct worker_thread
*worker
= g_workers
;
981 struct ctrlr_worker_ctx
*ctrlr_ctx
;
983 while (worker
!= NULL
) {
984 if (worker
->lcore
== g_master_core
) {
987 worker
= worker
->next
;
994 ctrlr_ctx
= worker
->ctrlr_ctx
;
996 while (ctrlr_ctx
!= NULL
) {
997 if (ctrlr_ctx
->ctrlr
== ctrlr
) {
1000 ctrlr_ctx
= ctrlr_ctx
->next
;
1007 associate_workers_with_ns(void)
1009 struct ns_entry
*entry
= g_namespaces
;
1010 struct worker_thread
*worker
= g_workers
;
1011 struct ns_worker_ctx
*ns_ctx
;
1014 count
= g_num_namespaces
> g_num_workers
? g_num_namespaces
: g_num_workers
;
1016 for (i
= 0; i
< count
; i
++) {
1017 if (entry
== NULL
) {
1021 ns_ctx
= calloc(1, sizeof(struct ns_worker_ctx
));
1026 printf("Associating %s with lcore %d\n", entry
->name
, worker
->lcore
);
1027 ns_ctx
->entry
= entry
;
1028 ns_ctx
->ctrlr_ctx
= get_ctrlr_worker_ctx(entry
->ctrlr
);
1029 if (!ns_ctx
->ctrlr_ctx
) {
1034 ns_ctx
->next
= worker
->ns_ctx
;
1035 worker
->ns_ctx
= ns_ctx
;
1037 worker
= worker
->next
;
1038 if (worker
== NULL
) {
1042 entry
= entry
->next
;
1043 if (entry
== NULL
) {
1044 entry
= g_namespaces
;
1051 int main(int argc
, char **argv
)
1054 struct worker_thread
*worker
, *master_worker
;
1055 struct spdk_env_opts opts
;
1057 rc
= parse_args(argc
, argv
);
1062 spdk_env_opts_init(&opts
);
1063 opts
.name
= "abort";
1064 opts
.shm_id
= g_shm_id
;
1066 opts
.core_mask
= g_core_mask
;
1070 opts
.mem_size
= g_dpdk_mem
;
1073 opts
.no_pci
= g_no_pci
;
1075 if (spdk_env_init(&opts
) < 0) {
1076 fprintf(stderr
, "Unable to initialize SPDK env\n");
1081 g_tsc_rate
= spdk_get_ticks_hz();
1083 if (register_workers() != 0) {
1088 if (register_controllers() != 0) {
1094 printf("WARNING: Some requested NVMe devices were skipped\n");
1097 if (g_num_namespaces
== 0) {
1098 fprintf(stderr
, "No valid NVMe controllers found\n");
1102 if (associate_master_worker_with_ctrlr() != 0) {
1107 if (associate_workers_with_ns() != 0) {
1112 printf("Initialization complete. Launching workers.\n");
1114 /* Launch all of the slave workers */
1115 g_master_core
= spdk_env_get_current_core();
1116 master_worker
= NULL
;
1118 while (worker
!= NULL
) {
1119 if (worker
->lcore
!= g_master_core
) {
1120 spdk_env_thread_launch_pinned(worker
->lcore
, work_fn
, worker
);
1122 assert(master_worker
== NULL
);
1123 master_worker
= worker
;
1125 worker
= worker
->next
;
1128 assert(master_worker
!= NULL
);
1129 rc
= work_fn(master_worker
);
1131 spdk_env_thread_wait_all();
1135 unregister_workers();
1136 unregister_namespaces();
1137 unregister_controllers();
1140 fprintf(stderr
, "%s: errors occured\n", argv
[0]);