xref: /spdk/examples/ioat/perf/perf.c (revision 25cad6ffcfe59a2801bdabcc72154d57a30e3a26)
1d4ab30baSDaniel Verkamp /*-
2d4ab30baSDaniel Verkamp  *   BSD LICENSE
3d4ab30baSDaniel Verkamp  *
4d4ab30baSDaniel Verkamp  *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
5d4ab30baSDaniel Verkamp  *   All rights reserved.
6d4ab30baSDaniel Verkamp  *
7d4ab30baSDaniel Verkamp  *   Redistribution and use in source and binary forms, with or without
8d4ab30baSDaniel Verkamp  *   modification, are permitted provided that the following conditions
9d4ab30baSDaniel Verkamp  *   are met:
10d4ab30baSDaniel Verkamp  *
11d4ab30baSDaniel Verkamp  *     * Redistributions of source code must retain the above copyright
12d4ab30baSDaniel Verkamp  *       notice, this list of conditions and the following disclaimer.
13d4ab30baSDaniel Verkamp  *     * Redistributions in binary form must reproduce the above copyright
14d4ab30baSDaniel Verkamp  *       notice, this list of conditions and the following disclaimer in
15d4ab30baSDaniel Verkamp  *       the documentation and/or other materials provided with the
16d4ab30baSDaniel Verkamp  *       distribution.
17d4ab30baSDaniel Verkamp  *     * Neither the name of Intel Corporation nor the names of its
18d4ab30baSDaniel Verkamp  *       contributors may be used to endorse or promote products derived
19d4ab30baSDaniel Verkamp  *       from this software without specific prior written permission.
20d4ab30baSDaniel Verkamp  *
21d4ab30baSDaniel Verkamp  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22d4ab30baSDaniel Verkamp  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23d4ab30baSDaniel Verkamp  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24d4ab30baSDaniel Verkamp  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25d4ab30baSDaniel Verkamp  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26d4ab30baSDaniel Verkamp  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27d4ab30baSDaniel Verkamp  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28d4ab30baSDaniel Verkamp  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29d4ab30baSDaniel Verkamp  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30d4ab30baSDaniel Verkamp  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31d4ab30baSDaniel Verkamp  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32d4ab30baSDaniel Verkamp  */
33d4ab30baSDaniel Verkamp 
34d4ab30baSDaniel Verkamp #include <stdio.h>
35d4ab30baSDaniel Verkamp #include <unistd.h>
36d4ab30baSDaniel Verkamp #include <stdlib.h>
37d4ab30baSDaniel Verkamp #include <stdbool.h>
38d4ab30baSDaniel Verkamp #include <string.h>
39d4ab30baSDaniel Verkamp #include <rte_config.h>
40d4ab30baSDaniel Verkamp #include <rte_malloc.h>
41d4ab30baSDaniel Verkamp #include <rte_eal.h>
42d4ab30baSDaniel Verkamp #include <rte_lcore.h>
43d4ab30baSDaniel Verkamp #include <rte_cycles.h>
44d4ab30baSDaniel Verkamp #include <rte_mempool.h>
45d4ab30baSDaniel Verkamp #include <pciaccess.h>
46d4ab30baSDaniel Verkamp #include "spdk/ioat.h"
47d4ab30baSDaniel Verkamp #include "spdk/pci.h"
48d4ab30baSDaniel Verkamp #include "spdk/string.h"
49d4ab30baSDaniel Verkamp 
50d4ab30baSDaniel Verkamp struct user_config {
51d4ab30baSDaniel Verkamp 	int xfer_size_bytes;
52d4ab30baSDaniel Verkamp 	int queue_depth;
53d4ab30baSDaniel Verkamp 	int time_in_sec;
54d4ab30baSDaniel Verkamp 	bool verify;
55d4ab30baSDaniel Verkamp 	char *core_mask;
56d4ab30baSDaniel Verkamp };
57d4ab30baSDaniel Verkamp 
58d4ab30baSDaniel Verkamp struct ioat_device {
59d4ab30baSDaniel Verkamp 	struct ioat_channel *ioat;
60d4ab30baSDaniel Verkamp 	TAILQ_ENTRY(ioat_device) tailq;
61d4ab30baSDaniel Verkamp };
62d4ab30baSDaniel Verkamp 
63d4ab30baSDaniel Verkamp static TAILQ_HEAD(, ioat_device) g_devices;
64d4ab30baSDaniel Verkamp 
65d4ab30baSDaniel Verkamp static struct user_config g_user_config;
66d4ab30baSDaniel Verkamp 
67d4ab30baSDaniel Verkamp struct thread_entry {
68d4ab30baSDaniel Verkamp 	uint64_t xfer_completed;
69d4ab30baSDaniel Verkamp 	uint64_t xfer_failed;
70d4ab30baSDaniel Verkamp 	uint64_t current_queue_depth;
71d4ab30baSDaniel Verkamp 	unsigned lcore_id;
72d4ab30baSDaniel Verkamp 	bool is_draining;
73d4ab30baSDaniel Verkamp 	struct rte_mempool *data_pool;
74d4ab30baSDaniel Verkamp 	struct rte_mempool *task_pool;
75d4ab30baSDaniel Verkamp };
76d4ab30baSDaniel Verkamp 
77d4ab30baSDaniel Verkamp struct ioat_task {
78d4ab30baSDaniel Verkamp 	struct thread_entry *thread_entry;
79d4ab30baSDaniel Verkamp 	void *src;
80d4ab30baSDaniel Verkamp 	void *dst;
81d4ab30baSDaniel Verkamp };
82d4ab30baSDaniel Verkamp 
83d4ab30baSDaniel Verkamp static void submit_single_xfer(struct thread_entry *thread_entry, struct ioat_task *ioat_task,
84d4ab30baSDaniel Verkamp 			       void *dst, void *src);
85d4ab30baSDaniel Verkamp 
86d4ab30baSDaniel Verkamp static void
87d4ab30baSDaniel Verkamp construct_user_config(struct user_config *self)
88d4ab30baSDaniel Verkamp {
89d4ab30baSDaniel Verkamp 	self->xfer_size_bytes = 4096;
90d4ab30baSDaniel Verkamp 	self->queue_depth = 256;
91d4ab30baSDaniel Verkamp 	self->time_in_sec = 10;
92d4ab30baSDaniel Verkamp 	self->verify = false;
93d4ab30baSDaniel Verkamp 	self->core_mask = "0x1";
94d4ab30baSDaniel Verkamp }
95d4ab30baSDaniel Verkamp 
96d4ab30baSDaniel Verkamp static void
97d4ab30baSDaniel Verkamp dump_user_config(struct user_config *self)
98d4ab30baSDaniel Verkamp {
99d4ab30baSDaniel Verkamp 	printf("User configuration:\n");
100d4ab30baSDaniel Verkamp 	printf("Transfer size:  %u bytes\n", self->xfer_size_bytes);
101d4ab30baSDaniel Verkamp 	printf("Queue depth:    %u\n", self->queue_depth);
102d4ab30baSDaniel Verkamp 	printf("Run time:       %u seconds\n", self->time_in_sec);
103d4ab30baSDaniel Verkamp 	printf("Core mask:      %s\n", self->core_mask);
104d4ab30baSDaniel Verkamp 	printf("Verify:         %s\n\n", self->verify ? "Yes" : "No");
105d4ab30baSDaniel Verkamp }
106d4ab30baSDaniel Verkamp 
107d4ab30baSDaniel Verkamp static void
108d4ab30baSDaniel Verkamp ioat_exit(void)
109d4ab30baSDaniel Verkamp {
110d4ab30baSDaniel Verkamp 	struct ioat_device *dev;
111d4ab30baSDaniel Verkamp 
112d4ab30baSDaniel Verkamp 	while (!TAILQ_EMPTY(&g_devices)) {
113d4ab30baSDaniel Verkamp 		dev = TAILQ_FIRST(&g_devices);
114d4ab30baSDaniel Verkamp 		TAILQ_REMOVE(&g_devices, dev, tailq);
115*25cad6ffSDaniel Verkamp 		if (dev->ioat) {
116d4ab30baSDaniel Verkamp 			ioat_detach(dev->ioat);
117*25cad6ffSDaniel Verkamp 		}
118d4ab30baSDaniel Verkamp 		rte_free(dev);
119d4ab30baSDaniel Verkamp 	}
120d4ab30baSDaniel Verkamp }
121d4ab30baSDaniel Verkamp 
122d4ab30baSDaniel Verkamp static void
123d4ab30baSDaniel Verkamp ioat_done(void *cb_arg)
124d4ab30baSDaniel Verkamp {
125d4ab30baSDaniel Verkamp 	struct ioat_task *ioat_task = (struct ioat_task *)cb_arg;
126d4ab30baSDaniel Verkamp 	struct thread_entry *thread_entry = ioat_task->thread_entry;
127d4ab30baSDaniel Verkamp 
128d4ab30baSDaniel Verkamp 	if (g_user_config.verify && memcmp(ioat_task->src, ioat_task->dst, g_user_config.xfer_size_bytes)) {
129d4ab30baSDaniel Verkamp 		thread_entry->xfer_failed++;
130d4ab30baSDaniel Verkamp 	} else {
131d4ab30baSDaniel Verkamp 		thread_entry->xfer_completed++;
132d4ab30baSDaniel Verkamp 	}
133d4ab30baSDaniel Verkamp 
134d4ab30baSDaniel Verkamp 	thread_entry->current_queue_depth--;
135d4ab30baSDaniel Verkamp 
136d4ab30baSDaniel Verkamp 	if (thread_entry->is_draining) {
137d4ab30baSDaniel Verkamp 		rte_mempool_put(thread_entry->data_pool, ioat_task->src);
138d4ab30baSDaniel Verkamp 		rte_mempool_put(thread_entry->data_pool, ioat_task->dst);
139d4ab30baSDaniel Verkamp 		rte_mempool_put(thread_entry->task_pool, ioat_task);
140d4ab30baSDaniel Verkamp 	} else {
141d4ab30baSDaniel Verkamp 		submit_single_xfer(thread_entry, ioat_task, ioat_task->dst, ioat_task->src);
142d4ab30baSDaniel Verkamp 	}
143d4ab30baSDaniel Verkamp }
144d4ab30baSDaniel Verkamp 
145d4ab30baSDaniel Verkamp static int
146d4ab30baSDaniel Verkamp ioat_init(void)
147d4ab30baSDaniel Verkamp {
148d4ab30baSDaniel Verkamp 	struct pci_device_iterator *iter;
149d4ab30baSDaniel Verkamp 	struct pci_device *pci_dev;
150d4ab30baSDaniel Verkamp 	int err = 0;
151d4ab30baSDaniel Verkamp 	struct pci_id_match match;
152d4ab30baSDaniel Verkamp 	struct ioat_device *dev;
153d4ab30baSDaniel Verkamp 
154d4ab30baSDaniel Verkamp 	pci_system_init();
155d4ab30baSDaniel Verkamp 	TAILQ_INIT(&g_devices);
156d4ab30baSDaniel Verkamp 
157d4ab30baSDaniel Verkamp 	match.vendor_id		= PCI_MATCH_ANY;
158d4ab30baSDaniel Verkamp 	match.subvendor_id	= PCI_MATCH_ANY;
159d4ab30baSDaniel Verkamp 	match.subdevice_id	= PCI_MATCH_ANY;
160d4ab30baSDaniel Verkamp 	match.device_id		= PCI_MATCH_ANY;
161d4ab30baSDaniel Verkamp 	match.device_class	= 0x088000;
162d4ab30baSDaniel Verkamp 	match.device_class_mask	= 0xFFFFFF;
163d4ab30baSDaniel Verkamp 
164d4ab30baSDaniel Verkamp 	iter = pci_id_match_iterator_create(&match);
165d4ab30baSDaniel Verkamp 
166d4ab30baSDaniel Verkamp 	while ((pci_dev = pci_device_next(iter)) != NULL) {
167d4ab30baSDaniel Verkamp 		/* Check if the PCI devices is a supported IOAT channel. */
168d4ab30baSDaniel Verkamp 		if (!(ioat_pci_device_match_id(pci_dev->vendor_id,
169d4ab30baSDaniel Verkamp 					       pci_dev->device_id))) {
170d4ab30baSDaniel Verkamp 			continue;
171d4ab30baSDaniel Verkamp 		}
172d4ab30baSDaniel Verkamp 
173d4ab30baSDaniel Verkamp 		printf(" Found matching device at %d:%d:%d "
174d4ab30baSDaniel Verkamp 		       "vendor:0x%04x device:0x%04x\n   name:%s\n",
175d4ab30baSDaniel Verkamp 		       pci_dev->bus, pci_dev->dev, pci_dev->func,
176d4ab30baSDaniel Verkamp 		       pci_dev->vendor_id, pci_dev->device_id,
177d4ab30baSDaniel Verkamp 		       pci_device_get_device_name(pci_dev));
178d4ab30baSDaniel Verkamp 
179d4ab30baSDaniel Verkamp 		if (pci_device_has_non_null_driver(pci_dev)) {
180d4ab30baSDaniel Verkamp 			printf("Device has kernel driver, skipping...\n");
181d4ab30baSDaniel Verkamp 			continue;
182d4ab30baSDaniel Verkamp 		}
183d4ab30baSDaniel Verkamp 
184d4ab30baSDaniel Verkamp 		pci_device_probe(pci_dev);
185d4ab30baSDaniel Verkamp 
186d4ab30baSDaniel Verkamp 		dev = rte_malloc(NULL, sizeof(*dev), 0);
187d4ab30baSDaniel Verkamp 		if (dev == NULL) {
188d4ab30baSDaniel Verkamp 			printf("Failed to allocate device struct\n");
189d4ab30baSDaniel Verkamp 			err = -1;
190d4ab30baSDaniel Verkamp 			goto cleanup;
191d4ab30baSDaniel Verkamp 		}
192d4ab30baSDaniel Verkamp 
193d4ab30baSDaniel Verkamp 		dev->ioat = ioat_attach(pci_dev);
194d4ab30baSDaniel Verkamp 		if (dev->ioat == NULL) {
195d4ab30baSDaniel Verkamp 			rte_free(dev);
196d4ab30baSDaniel Verkamp 			/* Likely no device found. */
197d4ab30baSDaniel Verkamp 			err = -1;
198d4ab30baSDaniel Verkamp 			goto cleanup;
199d4ab30baSDaniel Verkamp 		}
200d4ab30baSDaniel Verkamp 		TAILQ_INSERT_TAIL(&g_devices, dev, tailq);
201d4ab30baSDaniel Verkamp 	}
202d4ab30baSDaniel Verkamp 
203d4ab30baSDaniel Verkamp cleanup:
204d4ab30baSDaniel Verkamp 	pci_iterator_destroy(iter);
205d4ab30baSDaniel Verkamp 	if (err != 0) {
206d4ab30baSDaniel Verkamp 		ioat_exit();
207d4ab30baSDaniel Verkamp 	}
208d4ab30baSDaniel Verkamp 	return 0;
209d4ab30baSDaniel Verkamp }
210d4ab30baSDaniel Verkamp 
211d4ab30baSDaniel Verkamp static void
212d4ab30baSDaniel Verkamp usage(char *program_name)
213d4ab30baSDaniel Verkamp {
214d4ab30baSDaniel Verkamp 	printf("%s options\n", program_name);
215d4ab30baSDaniel Verkamp 	printf("\t[-h help message]\n");
216d4ab30baSDaniel Verkamp 	printf("\t[-c core mask for distributing I/O submission/completion work]\n");
217d4ab30baSDaniel Verkamp 	printf("\t[-q queue depth]\n");
218d4ab30baSDaniel Verkamp 	printf("\t[-s transfer size in bytes]\n");
219d4ab30baSDaniel Verkamp 	printf("\t[-t time in seconds]\n");
220d4ab30baSDaniel Verkamp 	printf("\t[-v verify copy result if this switch is on]\n");
221d4ab30baSDaniel Verkamp }
222d4ab30baSDaniel Verkamp 
223d4ab30baSDaniel Verkamp static int
224d4ab30baSDaniel Verkamp parse_args(int argc, char **argv)
225d4ab30baSDaniel Verkamp {
226d4ab30baSDaniel Verkamp 	int op;
227d4ab30baSDaniel Verkamp 
228d4ab30baSDaniel Verkamp 	construct_user_config(&g_user_config);
229d4ab30baSDaniel Verkamp 	while ((op = getopt(argc, argv, "c:hq:s:t:v")) != -1) {
230d4ab30baSDaniel Verkamp 		switch (op) {
231d4ab30baSDaniel Verkamp 		case 's':
232d4ab30baSDaniel Verkamp 			g_user_config.xfer_size_bytes = atoi(optarg);
233d4ab30baSDaniel Verkamp 			break;
234d4ab30baSDaniel Verkamp 		case 'q':
235d4ab30baSDaniel Verkamp 			g_user_config.queue_depth = atoi(optarg);
236d4ab30baSDaniel Verkamp 			break;
237d4ab30baSDaniel Verkamp 		case 't':
238d4ab30baSDaniel Verkamp 			g_user_config.time_in_sec = atoi(optarg);
239d4ab30baSDaniel Verkamp 			break;
240d4ab30baSDaniel Verkamp 		case 'c':
241d4ab30baSDaniel Verkamp 			g_user_config.core_mask = optarg;
242d4ab30baSDaniel Verkamp 			break;
243d4ab30baSDaniel Verkamp 		case 'v':
244d4ab30baSDaniel Verkamp 			g_user_config.verify = true;
245d4ab30baSDaniel Verkamp 			break;
246d4ab30baSDaniel Verkamp 		case 'h':
247d4ab30baSDaniel Verkamp 			usage(argv[0]);
248d4ab30baSDaniel Verkamp 			exit(0);
249d4ab30baSDaniel Verkamp 		default:
250d4ab30baSDaniel Verkamp 			usage(argv[0]);
251d4ab30baSDaniel Verkamp 			return 1;
252d4ab30baSDaniel Verkamp 		}
253d4ab30baSDaniel Verkamp 	}
254d4ab30baSDaniel Verkamp 	if (!g_user_config.xfer_size_bytes || !g_user_config.queue_depth ||
255d4ab30baSDaniel Verkamp 	    !g_user_config.time_in_sec || !g_user_config.core_mask) {
256d4ab30baSDaniel Verkamp 		usage(argv[0]);
257d4ab30baSDaniel Verkamp 		return 1;
258d4ab30baSDaniel Verkamp 	}
259d4ab30baSDaniel Verkamp 	optind = 1;
260d4ab30baSDaniel Verkamp 	return 0;
261d4ab30baSDaniel Verkamp }
262d4ab30baSDaniel Verkamp 
263d4ab30baSDaniel Verkamp static void
264d4ab30baSDaniel Verkamp drain_io(struct thread_entry *thread_entry)
265d4ab30baSDaniel Verkamp {
266d4ab30baSDaniel Verkamp 	while (thread_entry->current_queue_depth > 0) {
267d4ab30baSDaniel Verkamp 		ioat_process_events();
268d4ab30baSDaniel Verkamp 	}
269d4ab30baSDaniel Verkamp }
270d4ab30baSDaniel Verkamp 
271d4ab30baSDaniel Verkamp static void
272d4ab30baSDaniel Verkamp submit_single_xfer(struct thread_entry *thread_entry, struct ioat_task *ioat_task, void *dst,
273d4ab30baSDaniel Verkamp 		   void *src)
274d4ab30baSDaniel Verkamp {
275d4ab30baSDaniel Verkamp 	ioat_task->thread_entry = thread_entry;
276d4ab30baSDaniel Verkamp 	ioat_task->src = src;
277d4ab30baSDaniel Verkamp 	ioat_task->dst = dst;
278d4ab30baSDaniel Verkamp 
279d4ab30baSDaniel Verkamp 	ioat_submit_copy(ioat_task, ioat_done, dst, src, g_user_config.xfer_size_bytes);
280d4ab30baSDaniel Verkamp 
281d4ab30baSDaniel Verkamp 	thread_entry->current_queue_depth++;
282d4ab30baSDaniel Verkamp }
283d4ab30baSDaniel Verkamp 
284d4ab30baSDaniel Verkamp static void
285d4ab30baSDaniel Verkamp submit_xfers(struct thread_entry *thread_entry, uint64_t queue_depth)
286d4ab30baSDaniel Verkamp {
287d4ab30baSDaniel Verkamp 	while (queue_depth-- > 0) {
288d4ab30baSDaniel Verkamp 		void *src = NULL, *dst = NULL;
289d4ab30baSDaniel Verkamp 		struct ioat_task *ioat_task = NULL;
290d4ab30baSDaniel Verkamp 
291d4ab30baSDaniel Verkamp 		rte_mempool_get(thread_entry->data_pool, &src);
292d4ab30baSDaniel Verkamp 		rte_mempool_get(thread_entry->data_pool, &dst);
293d4ab30baSDaniel Verkamp 		rte_mempool_get(thread_entry->task_pool, (void **)&ioat_task);
294d4ab30baSDaniel Verkamp 
295d4ab30baSDaniel Verkamp 		submit_single_xfer(thread_entry, ioat_task, dst, src);
296d4ab30baSDaniel Verkamp 	}
297d4ab30baSDaniel Verkamp }
298d4ab30baSDaniel Verkamp 
299d4ab30baSDaniel Verkamp static int
300d4ab30baSDaniel Verkamp work_fn(void *arg)
301d4ab30baSDaniel Verkamp {
302d4ab30baSDaniel Verkamp 	char buf_pool_name[20], task_pool_name[20];
303d4ab30baSDaniel Verkamp 	uint64_t tsc_end;
304d4ab30baSDaniel Verkamp 	struct thread_entry *t = (struct thread_entry *)arg;
305d4ab30baSDaniel Verkamp 
306d4ab30baSDaniel Verkamp 	t->lcore_id = rte_lcore_id();
307d4ab30baSDaniel Verkamp 
308d4ab30baSDaniel Verkamp 	snprintf(buf_pool_name, sizeof(buf_pool_name), "buf_pool_%d", rte_lcore_id());
309d4ab30baSDaniel Verkamp 	snprintf(task_pool_name, sizeof(task_pool_name), "task_pool_%d", rte_lcore_id());
310d4ab30baSDaniel Verkamp 	t->data_pool = rte_mempool_create(buf_pool_name, 512, g_user_config.xfer_size_bytes, 0, 0, NULL,
311d4ab30baSDaniel Verkamp 					  NULL,
312d4ab30baSDaniel Verkamp 					  NULL, NULL, SOCKET_ID_ANY, 0);
313d4ab30baSDaniel Verkamp 	t->task_pool = rte_mempool_create(task_pool_name, 512, sizeof(struct ioat_task), 0, 0, NULL, NULL,
314d4ab30baSDaniel Verkamp 					  NULL, NULL, SOCKET_ID_ANY, 0);
315d4ab30baSDaniel Verkamp 	if (!t->data_pool || !t->task_pool) {
316d4ab30baSDaniel Verkamp 		fprintf(stderr, "Could not allocate buffer pool.\n");
317d4ab30baSDaniel Verkamp 		return 1;
318d4ab30baSDaniel Verkamp 	}
319d4ab30baSDaniel Verkamp 
320d4ab30baSDaniel Verkamp 	if (ioat_register_thread() != 0) {
321d4ab30baSDaniel Verkamp 		fprintf(stderr, "lcore %u: No ioat channels found. Check that ioatdma driver is unloaded.\n",
322d4ab30baSDaniel Verkamp 			rte_lcore_id());
323d4ab30baSDaniel Verkamp 		return 0;
324d4ab30baSDaniel Verkamp 	}
325d4ab30baSDaniel Verkamp 
326d4ab30baSDaniel Verkamp 	tsc_end = rte_get_timer_cycles() + g_user_config.time_in_sec * rte_get_timer_hz();
327d4ab30baSDaniel Verkamp 
328d4ab30baSDaniel Verkamp 	// begin to submit transfers
329d4ab30baSDaniel Verkamp 	submit_xfers(t, g_user_config.queue_depth);
330d4ab30baSDaniel Verkamp 	while (rte_get_timer_cycles() < tsc_end) {
331d4ab30baSDaniel Verkamp 		ioat_process_events();
332d4ab30baSDaniel Verkamp 	}
333d4ab30baSDaniel Verkamp 
334d4ab30baSDaniel Verkamp 	// begin to drain io
335d4ab30baSDaniel Verkamp 	t->is_draining = true;
336d4ab30baSDaniel Verkamp 	drain_io(t);
337d4ab30baSDaniel Verkamp 	ioat_unregister_thread();
338d4ab30baSDaniel Verkamp 
339d4ab30baSDaniel Verkamp 	return 0;
340d4ab30baSDaniel Verkamp }
341d4ab30baSDaniel Verkamp 
342d4ab30baSDaniel Verkamp static int
343d4ab30baSDaniel Verkamp init(void)
344d4ab30baSDaniel Verkamp {
345d4ab30baSDaniel Verkamp 	char *core_mask_conf;
346d4ab30baSDaniel Verkamp 
347d4ab30baSDaniel Verkamp 	core_mask_conf = sprintf_alloc("-c %s", g_user_config.core_mask);
348d4ab30baSDaniel Verkamp 	if (!core_mask_conf) {
349d4ab30baSDaniel Verkamp 		return 1;
350d4ab30baSDaniel Verkamp 	}
351d4ab30baSDaniel Verkamp 
352d4ab30baSDaniel Verkamp 	char *ealargs[] = {"perf", core_mask_conf, "-n 4", "--no-pci"};
353d4ab30baSDaniel Verkamp 
354d4ab30baSDaniel Verkamp 	if (rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs) < 0) {
355d4ab30baSDaniel Verkamp 		free(core_mask_conf);
356d4ab30baSDaniel Verkamp 		fprintf(stderr, "Could not init eal\n");
357d4ab30baSDaniel Verkamp 		return 1;
358d4ab30baSDaniel Verkamp 	}
359d4ab30baSDaniel Verkamp 
360d4ab30baSDaniel Verkamp 	free(core_mask_conf);
361d4ab30baSDaniel Verkamp 
362d4ab30baSDaniel Verkamp 	if (ioat_init() != 0) {
363d4ab30baSDaniel Verkamp 		fprintf(stderr, "Could not init ioat\n");
364d4ab30baSDaniel Verkamp 		return 1;
365d4ab30baSDaniel Verkamp 	}
366d4ab30baSDaniel Verkamp 
367d4ab30baSDaniel Verkamp 	return 0;
368d4ab30baSDaniel Verkamp }
369d4ab30baSDaniel Verkamp 
370d4ab30baSDaniel Verkamp static int
371d4ab30baSDaniel Verkamp dump_result(struct thread_entry *threads, int len)
372d4ab30baSDaniel Verkamp {
373d4ab30baSDaniel Verkamp 	int i;
374d4ab30baSDaniel Verkamp 	uint64_t total_completed = 0;
375d4ab30baSDaniel Verkamp 	uint64_t total_failed = 0;
376d4ab30baSDaniel Verkamp 	uint64_t total_xfer_per_sec, total_bw_in_MBps;
377d4ab30baSDaniel Verkamp 
378d4ab30baSDaniel Verkamp 	printf("lcore     Transfers        Bandwidth  Failed\n");
379d4ab30baSDaniel Verkamp 	printf("--------------------------------------------\n");
380d4ab30baSDaniel Verkamp 	for (i = 0; i < len; i++) {
381d4ab30baSDaniel Verkamp 		struct thread_entry *t = &threads[i];
382d4ab30baSDaniel Verkamp 
383d4ab30baSDaniel Verkamp 		uint64_t xfer_per_sec = t->xfer_completed / g_user_config.time_in_sec;
384d4ab30baSDaniel Verkamp 		uint64_t bw_in_MBps = (t->xfer_completed * g_user_config.xfer_size_bytes) /
385d4ab30baSDaniel Verkamp 				      (g_user_config.time_in_sec * 1024 * 1024);
386d4ab30baSDaniel Verkamp 
387d4ab30baSDaniel Verkamp 		total_completed += t->xfer_completed;
388d4ab30baSDaniel Verkamp 		total_failed += t->xfer_failed;
389d4ab30baSDaniel Verkamp 
390d4ab30baSDaniel Verkamp 		if (xfer_per_sec) {
391d4ab30baSDaniel Verkamp 			printf("%5d  %10" PRIu64 "/s  %10" PRIu64 " MB/s  %6" PRIu64 "\n",
392d4ab30baSDaniel Verkamp 			       t->lcore_id, xfer_per_sec, bw_in_MBps, t->xfer_failed);
393d4ab30baSDaniel Verkamp 		}
394d4ab30baSDaniel Verkamp 	}
395d4ab30baSDaniel Verkamp 
396d4ab30baSDaniel Verkamp 	total_xfer_per_sec = total_completed / g_user_config.time_in_sec;
397d4ab30baSDaniel Verkamp 	total_bw_in_MBps = (total_completed * g_user_config.xfer_size_bytes) /
398d4ab30baSDaniel Verkamp 			   (g_user_config.time_in_sec * 1024 * 1024);
399d4ab30baSDaniel Verkamp 
400d4ab30baSDaniel Verkamp 	printf("============================================\n");
401d4ab30baSDaniel Verkamp 	printf("Total: %10" PRIu64 "/s  %10" PRIu64 " MB/s  %6" PRIu64 "\n",
402d4ab30baSDaniel Verkamp 	       total_xfer_per_sec, total_bw_in_MBps, total_failed);
403d4ab30baSDaniel Verkamp 	return total_failed ? 1 : 0;
404d4ab30baSDaniel Verkamp }
405d4ab30baSDaniel Verkamp 
406d4ab30baSDaniel Verkamp int
407d4ab30baSDaniel Verkamp main(int argc, char **argv)
408d4ab30baSDaniel Verkamp {
409d4ab30baSDaniel Verkamp 	unsigned lcore_id;
410d4ab30baSDaniel Verkamp 	struct thread_entry threads[RTE_MAX_LCORE] = {};
411*25cad6ffSDaniel Verkamp 	int rc;
412d4ab30baSDaniel Verkamp 
413d4ab30baSDaniel Verkamp 	if (parse_args(argc, argv) != 0) {
414d4ab30baSDaniel Verkamp 		return 1;
415d4ab30baSDaniel Verkamp 	}
416d4ab30baSDaniel Verkamp 
417d4ab30baSDaniel Verkamp 	if (init() != 0) {
418d4ab30baSDaniel Verkamp 		return 1;
419d4ab30baSDaniel Verkamp 	}
420d4ab30baSDaniel Verkamp 
421d4ab30baSDaniel Verkamp 	dump_user_config(&g_user_config);
422d4ab30baSDaniel Verkamp 
423d4ab30baSDaniel Verkamp 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
424d4ab30baSDaniel Verkamp 		rte_eal_remote_launch(work_fn, &threads[lcore_id], lcore_id);
425d4ab30baSDaniel Verkamp 	}
426d4ab30baSDaniel Verkamp 
427d4ab30baSDaniel Verkamp 	if (work_fn(&threads[rte_get_master_lcore()]) != 0) {
428*25cad6ffSDaniel Verkamp 		rc = 1;
429*25cad6ffSDaniel Verkamp 		goto cleanup;
430d4ab30baSDaniel Verkamp 	}
431d4ab30baSDaniel Verkamp 
432d4ab30baSDaniel Verkamp 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
433d4ab30baSDaniel Verkamp 		if (rte_eal_wait_lcore(lcore_id) != 0) {
434*25cad6ffSDaniel Verkamp 			rc = 1;
435*25cad6ffSDaniel Verkamp 			goto cleanup;
436d4ab30baSDaniel Verkamp 		}
437d4ab30baSDaniel Verkamp 	}
438d4ab30baSDaniel Verkamp 
439*25cad6ffSDaniel Verkamp 	rc = dump_result(threads, RTE_MAX_LCORE);
440*25cad6ffSDaniel Verkamp 
441*25cad6ffSDaniel Verkamp cleanup:
442*25cad6ffSDaniel Verkamp 	ioat_exit();
443*25cad6ffSDaniel Verkamp 
444*25cad6ffSDaniel Verkamp 	return rc;
445d4ab30baSDaniel Verkamp }
446