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/stdinc.h"
7 : :
8 : : #include "spdk/env.h"
9 : : #include "spdk/nvme.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/util.h"
12 : : #include "spdk/log.h"
13 : : #include "spdk/likely.h"
14 : : #include "spdk/sock.h"
15 : :
16 : : static int g_time_in_sec;
17 : :
18 : : static struct spdk_nvme_transport_id g_trid;
19 : :
20 : : static void
21 : 0 : usage(char *program_name)
22 : : {
23 [ # # ]: 0 : printf("%s options", program_name);
24 : 0 : printf("\n");
25 [ # # ]: 0 : printf("\t[-t, --time <sec> time in seconds]\n");
26 [ # # ]: 0 : printf("\t[-c, --core-mask <mask>]\n");
27 [ # # ]: 0 : printf("\t\t(default: 1)\n");
28 [ # # ]: 0 : printf("\t[-r, --transport <fmt> Transport ID for local PCIe NVMe or NVMeoF]\n");
29 [ # # ]: 0 : printf("\t Format: 'key:value [key:value] ...'\n");
30 [ # # ]: 0 : printf("\t Keys:\n");
31 [ # # ]: 0 : printf("\t trtype Transport type (e.g. PCIe, RDMA)\n");
32 [ # # ]: 0 : printf("\t adrfam Address family (e.g. IPv4, IPv6)\n");
33 [ # # ]: 0 : printf("\t traddr Transport address (e.g. 0000:04:00.0 for PCIe or 192.168.100.8 for RDMA)\n");
34 [ # # ]: 0 : printf("\t trsvcid Transport service identifier (e.g. 4420)\n");
35 [ # # ]: 0 : printf("\t subnqn Subsystem NQN\n");
36 [ # # ]: 0 : printf("\t Example: -r 'trtype:PCIe traddr:0000:04:00.0' for PCIe or\n");
37 [ # # ]: 0 : printf("\t -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420' for NVMeoF\n");
38 [ # # ]: 0 : printf("\t[-s, --hugemem-size <MB> DPDK huge memory size in MB.]\n");
39 [ # # ]: 0 : printf("\t\t(default: 0 - unlimited)\n");
40 [ # # ]: 0 : printf("\t[-i, --shmem-grp-id <id> shared memory group ID]\n");
41 : 0 : printf("\t");
42 : 0 : spdk_log_usage(stdout, "-T");
43 [ # # ]: 0 : printf("\t[-S, --default-sock-impl <impl> set the default sock impl, e.g. \"posix\"]\n");
44 : : #ifdef DEBUG
45 [ # # ]: 0 : printf("\t[-G, --enable-debug enable debug logging]\n");
46 : : #else
47 : : printf("\t[-G, --enable-debug enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n");
48 : : printf("\t[--iova-mode <mode> specify DPDK IOVA mode: va|pa]\n");
49 : : printf("\t[--no-huge, SPDK is run without hugepages\n");
50 : : #endif
51 : 0 : }
52 : :
53 : : static int
54 : 3 : add_trid(const char *trid_str)
55 : : {
56 : 3 : g_trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
57 [ - + ]: 3 : snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
58 : :
59 [ - + ]: 3 : if (spdk_nvme_transport_id_parse(&g_trid, trid_str) != 0) {
60 [ # # # # ]: 0 : fprintf(stderr, "Invalid transport ID format '%s'\n", trid_str);
61 : 0 : return 1;
62 : : }
63 : :
64 : 3 : spdk_nvme_transport_id_populate_trstring(&g_trid,
65 : : spdk_nvme_transport_id_trtype_str(g_trid.trtype));
66 : :
67 : 3 : return 0;
68 : : }
69 : :
70 : : #define PERF_GETOPT_SHORT "c:i:r:s:t:GS:T:"
71 : :
72 : : static const struct option g_cmdline_opts[] = {
73 : : #define PERF_CORE_MASK 'c'
74 : : {"core-mask", required_argument, NULL, PERF_CORE_MASK},
75 : : #define PERF_SHMEM_GROUP_ID 'i'
76 : : {"shmem-grp-id", required_argument, NULL, PERF_SHMEM_GROUP_ID},
77 : : #define PERF_TRANSPORT 'r'
78 : : {"transport", required_argument, NULL, PERF_TRANSPORT},
79 : : #define PERF_HUGEMEM_SIZE 's'
80 : : {"hugemem-size", required_argument, NULL, PERF_HUGEMEM_SIZE},
81 : : #define PERF_TIME 't'
82 : : {"time", required_argument, NULL, PERF_TIME},
83 : : #define PERF_ENABLE_DEBUG 'G'
84 : : {"enable-debug", no_argument, NULL, PERF_ENABLE_DEBUG},
85 : : #define PERF_DEFAULT_SOCK_IMPL 'S'
86 : : {"default-sock-impl", required_argument, NULL, PERF_DEFAULT_SOCK_IMPL},
87 : : #define PERF_LOG_FLAG 'T'
88 : : {"logflag", required_argument, NULL, PERF_LOG_FLAG},
89 : : #define PERF_IOVA_MODE 258
90 : : {"iova-mode", required_argument, NULL, PERF_IOVA_MODE},
91 : : #define PERF_NO_HUGE 259
92 : : {"no-huge", no_argument, NULL, PERF_NO_HUGE},
93 : : /* Should be the last element */
94 : : {0, 0, 0, 0}
95 : : };
96 : :
97 : : static int
98 : 3 : parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
99 : : {
100 : 3 : bool trid_set = false;
101 : 0 : int op, long_idx;
102 : : long int val;
103 : : int rc;
104 : :
105 [ - + + + ]: 12 : while ((op = getopt_long(argc, argv, PERF_GETOPT_SHORT, g_cmdline_opts, &long_idx)) != -1) {
106 [ + + + - : 9 : switch (op) {
- - - -
- ]
107 : 3 : case PERF_SHMEM_GROUP_ID:
108 : : case PERF_HUGEMEM_SIZE:
109 : : case PERF_TIME:
110 : 3 : val = spdk_strtol(optarg, 10);
111 [ - + ]: 3 : if (val < 0) {
112 [ # # ]: 0 : fprintf(stderr, "Converting a string to integer failed\n");
113 : 0 : return val;
114 : : }
115 : : switch (op) {
116 : 0 : case PERF_SHMEM_GROUP_ID:
117 : 0 : env_opts->shm_id = val;
118 : 0 : break;
119 : 0 : case PERF_HUGEMEM_SIZE:
120 : 0 : env_opts->mem_size = val;
121 : 0 : break;
122 : 3 : case PERF_TIME:
123 : 3 : g_time_in_sec = val;
124 : 3 : break;
125 : : }
126 : 3 : break;
127 : 3 : case PERF_CORE_MASK:
128 : 3 : env_opts->core_mask = optarg;
129 : 3 : break;
130 : 3 : case PERF_TRANSPORT:
131 [ - + ]: 3 : if (trid_set) {
132 [ # # ]: 0 : fprintf(stderr, "Only one trid can be specified\n");
133 : 0 : usage(argv[0]);
134 : 0 : return 1;
135 : : }
136 : 3 : trid_set = true;
137 [ - + ]: 3 : if (add_trid(optarg)) {
138 : 0 : usage(argv[0]);
139 : 0 : return 1;
140 : : }
141 : 3 : break;
142 : 0 : case PERF_ENABLE_DEBUG:
143 : : #ifndef DEBUG
144 : : fprintf(stderr, "%s must be configured with --enable-debug for -G flag\n",
145 : : argv[0]);
146 : : usage(argv[0]);
147 : : return 1;
148 : : #else
149 : 0 : spdk_log_set_flag("nvme");
150 : 0 : spdk_log_set_print_level(SPDK_LOG_DEBUG);
151 : 0 : break;
152 : : #endif
153 : 0 : case PERF_LOG_FLAG:
154 : 0 : rc = spdk_log_set_flag(optarg);
155 [ # # ]: 0 : if (rc < 0) {
156 [ # # ]: 0 : fprintf(stderr, "unknown flag\n");
157 : 0 : usage(argv[0]);
158 : 0 : exit(EXIT_FAILURE);
159 : : }
160 : : #ifdef DEBUG
161 : 0 : spdk_log_set_print_level(SPDK_LOG_DEBUG);
162 : : #endif
163 : 0 : break;
164 : 0 : case PERF_DEFAULT_SOCK_IMPL:
165 : 0 : rc = spdk_sock_set_default_impl(optarg);
166 [ # # ]: 0 : if (rc) {
167 [ # # ]: 0 : fprintf(stderr, "Failed to set sock impl %s, err %d (%s)\n", optarg, errno, strerror(errno));
168 : 0 : return 1;
169 : : }
170 : 0 : break;
171 : 0 : case PERF_IOVA_MODE:
172 : 0 : env_opts->iova_mode = optarg;
173 : 0 : break;
174 : 0 : case PERF_NO_HUGE:
175 : 0 : env_opts->no_huge = true;
176 : 0 : break;
177 : 0 : default:
178 : 0 : usage(argv[0]);
179 : 0 : return 1;
180 : : }
181 : : }
182 : :
183 [ - + ]: 3 : if (!g_time_in_sec) {
184 [ # # ]: 0 : fprintf(stderr, "missing -t (--time) operand\n");
185 : 0 : usage(argv[0]);
186 : 0 : return 1;
187 : : }
188 : :
189 [ - + ]: 3 : if (!trid_set) {
190 [ # # ]: 0 : fprintf(stderr, "missing -r operand\n");
191 : 0 : usage(argv[0]);
192 : 0 : return 1;
193 : : }
194 : :
195 : 3 : env_opts->no_pci = true;
196 [ - + ]: 3 : if (g_trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
197 : 0 : env_opts->no_pci = false;
198 : : }
199 : :
200 : 3 : return 0;
201 : : }
202 : :
203 : : static int
204 : 362 : test_controller(void)
205 : 362 : {
206 : 362 : const int LOOP_COUNT = 5;
207 [ - + ]: 362 : struct spdk_nvme_qpair *qpair[LOOP_COUNT];
208 : : union spdk_nvme_csts_register csts;
209 : : struct spdk_nvme_ctrlr *ctrlr;
210 : :
211 : 362 : ctrlr = spdk_nvme_connect(&g_trid, NULL, 0);
212 [ - + ]: 362 : if (ctrlr == NULL) {
213 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n",
214 : : g_trid.traddr);
215 : 0 : return -1;
216 : : }
217 [ - + ]: 362 : if (spdk_nvme_ctrlr_is_discovery(ctrlr)) {
218 [ # # # # ]: 0 : fprintf(stderr, "discovery controller not allowed for this test\n");
219 : 0 : spdk_nvme_detach(ctrlr);
220 : 0 : return -1;
221 : : }
222 : :
223 [ + + ]: 2172 : for (int i = 0; i < LOOP_COUNT; i++) {
224 : 1810 : csts = spdk_nvme_ctrlr_get_regs_csts(ctrlr);
225 [ - + ]: 1810 : if (csts.raw == 0xFFFFFFFF) {
226 [ # # # # ]: 0 : fprintf(stderr, "could not read csts\n");
227 : 0 : spdk_nvme_detach(ctrlr);
228 : 0 : return -1;
229 : : }
230 : 1810 : qpair[i] = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
231 [ - + ]: 1810 : if (qpair[i] == NULL) {
232 [ # # # # ]: 0 : fprintf(stderr, "could not allocate io qpair\n");
233 : 0 : spdk_nvme_detach(ctrlr);
234 : 0 : return -1;
235 : : }
236 : : }
237 [ + + ]: 2172 : for (int i = 0; i < LOOP_COUNT; i++) {
238 : 1810 : spdk_nvme_ctrlr_free_io_qpair(qpair[i]);
239 : : }
240 : :
241 : 362 : spdk_nvme_detach(ctrlr);
242 : :
243 : 362 : return 0;
244 : : }
245 : :
246 : : int
247 : 3 : main(int argc, char **argv)
248 : : {
249 : 0 : struct spdk_env_opts opts;
250 : : uint64_t tsc_end;
251 : : int rc;
252 : :
253 : 3 : spdk_env_opts_init(&opts);
254 : 3 : opts.name = "connect_stress";
255 : 3 : rc = parse_args(argc, argv, &opts);
256 [ - + ]: 3 : if (rc != 0) {
257 : 0 : return rc;
258 : : }
259 [ - + ]: 3 : if (spdk_env_init(&opts) < 0) {
260 [ # # # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
261 : 0 : return -1;
262 : : }
263 : :
264 [ + - ]: 3 : if (g_trid.trtype != SPDK_NVME_TRANSPORT_PCIE) {
265 [ - + ]: 3 : printf("Testing NVMe over Fabrics controller at %s:%s: %s\n",
266 : : g_trid.traddr, g_trid.trsvcid,
267 : : g_trid.subnqn);
268 : : } else {
269 [ # # ]: 0 : printf("Testing NVMe PCI controller at %s\n", g_trid.traddr);
270 : : }
271 : :
272 : 3 : tsc_end = spdk_get_ticks() + g_time_in_sec * spdk_get_ticks_hz();
273 [ + + + - ]: 365 : while (spdk_get_ticks() < tsc_end && rc == 0) {
274 : 362 : rc = test_controller();
275 : : }
276 : :
277 : 3 : return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
278 : : }
|