xref: /spdk/examples/ioat/perf/perf.c (revision 186b109dd3a723612e3df79bb3d97699173d39e3)
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