ioatcontrol.c revision 300661
1/*-
2 * Copyright (C) 2012 Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/10/tools/tools/ioat/ioatcontrol.c 300661 2016-05-25 07:09:54Z mav $");
29
30#include <sys/ioctl.h>
31#include <sys/queue.h>
32
33#include <fcntl.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <stdint.h>
37#include <stdlib.h>
38#include <sysexits.h>
39#include <unistd.h>
40
41#include <libutil.h>
42
43#include "ioat_test.h"
44
45static int prettyprint(struct ioat_test *);
46
47static void
48usage(void)
49{
50
51	printf("Usage: %s [-E|-f|-m] OPTIONS <channel #> <txns> [<bufsize> "
52	    "[<chain-len> [duration]]]\n", getprogname());
53	printf("       %s -r [-v] OPTIONS <channel #> <addr> [<bufsize>]\n\n",
54	    getprogname());
55	printf("       OPTIONS:\n");
56	printf("           -c <period> - Enable interrupt coalescing (us)\n");
57	printf("           -V          - Enable verification\n");
58	printf("           -z          - Zero device stats before test\n");
59	exit(EX_USAGE);
60}
61
62static void
63main_raw(struct ioat_test *t, int argc, char **argv)
64{
65	int fd;
66
67	/* Raw DMA defaults */
68	t->testkind = IOAT_TEST_RAW_DMA;
69	t->transactions = 1;
70	t->chain_depth = 1;
71	t->buffer_size = 4 * 1024;
72
73	t->raw_target = strtoull(argv[1], NULL, 0);
74	if (t->raw_target == 0) {
75		printf("Target shoudln't be NULL\n");
76		exit(EX_USAGE);
77	}
78
79	if (argc >= 3) {
80		t->buffer_size = atoi(argv[2]);
81		if (t->buffer_size == 0) {
82			printf("Buffer size must be greater than zero\n");
83			exit(EX_USAGE);
84		}
85	}
86
87	fd = open("/dev/ioat_test", O_RDWR);
88	if (fd < 0) {
89		printf("Cannot open /dev/ioat_test\n");
90		exit(EX_UNAVAILABLE);
91	}
92
93	(void)ioctl(fd, IOAT_DMATEST, t);
94	close(fd);
95
96	exit(prettyprint(t));
97}
98
99int
100main(int argc, char **argv)
101{
102	struct ioat_test t;
103	int fd, ch;
104	bool fflag, rflag, Eflag, mflag;
105	unsigned modeflags;
106
107	fflag = rflag = Eflag = mflag = false;
108	modeflags = 0;
109
110	while ((ch = getopt(argc, argv, "c:EfmrvVwz")) != -1) {
111		switch (ch) {
112		case 'c':
113			t.coalesce_period = atoi(optarg);
114			break;
115		case 'E':
116			Eflag = true;
117			modeflags++;
118			break;
119		case 'f':
120			fflag = true;
121			modeflags++;
122			break;
123		case 'm':
124			mflag = true;
125			modeflags++;
126			break;
127		case 'r':
128			rflag = true;
129			modeflags++;
130			break;
131		case 'v':
132			t.raw_is_virtual = true;
133			break;
134		case 'V':
135			t.verify = true;
136			break;
137		case 'w':
138			t.raw_write = true;
139			break;
140		case 'z':
141			t.zero_stats = true;
142			break;
143		default:
144			usage();
145		}
146	}
147	argc -= optind;
148	argv += optind;
149
150	if (argc < 2)
151		usage();
152
153	if (modeflags > 1) {
154		printf("Invalid: Cannot use >1 mode flag (-E, -f, -m, or -r)\n");
155		usage();
156	}
157
158	/* Defaults for optional args */
159	t.buffer_size = 256 * 1024;
160	t.chain_depth = 2;
161	t.duration = 0;
162	t.testkind = IOAT_TEST_DMA;
163
164	if (fflag)
165		t.testkind = IOAT_TEST_FILL;
166	else if (Eflag) {
167		t.testkind = IOAT_TEST_DMA_8K;
168		t.buffer_size = 8 * 1024;
169	} else if (mflag)
170		t.testkind = IOAT_TEST_MEMCPY;
171
172	t.channel_index = atoi(argv[0]);
173	if (t.channel_index > 8) {
174		printf("Channel number must be between 0 and 7.\n");
175		return (EX_USAGE);
176	}
177
178	if (rflag) {
179		main_raw(&t, argc, argv);
180		return (EX_OK);
181	}
182
183	t.transactions = atoi(argv[1]);
184
185	if (argc >= 3) {
186		t.buffer_size = atoi(argv[2]);
187		if (t.buffer_size == 0) {
188			printf("Buffer size must be greater than zero\n");
189			return (EX_USAGE);
190		}
191	}
192
193	if (argc >= 4) {
194		t.chain_depth = atoi(argv[3]);
195		if (t.chain_depth < 1) {
196			printf("Chain length must be greater than zero\n");
197			return (EX_USAGE);
198		}
199	}
200
201	if (argc >= 5) {
202		t.duration = atoi(argv[4]);
203		if (t.duration < 1) {
204			printf("Duration must be greater than zero\n");
205			return (EX_USAGE);
206		}
207	}
208
209	fd = open("/dev/ioat_test", O_RDWR);
210	if (fd < 0) {
211		printf("Cannot open /dev/ioat_test\n");
212		return (EX_UNAVAILABLE);
213	}
214
215	(void)ioctl(fd, IOAT_DMATEST, &t);
216	close(fd);
217
218	return (prettyprint(&t));
219}
220
221static int
222prettyprint(struct ioat_test *t)
223{
224	char bps[10], bytesh[10];
225	uintmax_t bytes;
226
227	if (t->status[IOAT_TEST_NO_DMA_ENGINE] != 0 ||
228	    t->status[IOAT_TEST_NO_MEMORY] != 0 ||
229	    t->status[IOAT_TEST_MISCOMPARE] != 0) {
230		printf("Errors:\n");
231		if (t->status[IOAT_TEST_NO_DMA_ENGINE] != 0)
232			printf("\tNo DMA engine present: %u\n",
233			    (unsigned)t->status[IOAT_TEST_NO_DMA_ENGINE]);
234		if (t->status[IOAT_TEST_NO_MEMORY] != 0)
235			printf("\tOut of memory: %u\n",
236			    (unsigned)t->status[IOAT_TEST_NO_MEMORY]);
237		if (t->status[IOAT_TEST_MISCOMPARE] != 0)
238			printf("\tMiscompares: %u\n",
239			    (unsigned)t->status[IOAT_TEST_MISCOMPARE]);
240	}
241
242	printf("Processed %u txns\n", (unsigned)t->status[IOAT_TEST_OK] /
243	    t->chain_depth);
244	bytes = (uintmax_t)t->buffer_size * t->status[IOAT_TEST_OK];
245
246	humanize_number(bytesh, sizeof(bytesh), (int64_t)bytes, "B",
247	    HN_AUTOSCALE, HN_DECIMAL);
248	if (t->duration) {
249		humanize_number(bps, sizeof(bps),
250		    (int64_t)1000 * bytes / t->duration, "B/s", HN_AUTOSCALE,
251		    HN_DECIMAL);
252		printf("%ju (%s) copied in %u ms (%s)\n", bytes, bytesh,
253		    (unsigned)t->duration, bps);
254	} else
255		printf("%ju (%s) copied\n", bytes, bytesh);
256
257	return (EX_OK);
258}
259