]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/examples/ioat/kperf/ioat_kperf.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / spdk / examples / ioat / kperf / ioat_kperf.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
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
16 * distribution.
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.
20 *
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.
32 */
33
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <dirent.h>
39 #include <inttypes.h>
40 #include <assert.h>
41
42 #define ioat_max(a,b) (((a)>(b))?(a):(b))
43
44 static int
45 check_modules(char *driver_name)
46 {
47 FILE *fd;
48 const char *proc_modules = "/proc/modules";
49 char buffer[256];
50
51 fd = fopen(proc_modules, "r");
52 if (!fd)
53 return -1;
54
55 while (fgets(buffer, sizeof(buffer), fd)) {
56 if (strstr(buffer, driver_name) == NULL)
57 continue;
58 else {
59 fclose(fd);
60 return 0;
61 }
62 }
63 fclose(fd);
64
65 return -1;
66 }
67
68 static int
69 get_u32_from_file(const char *sysfs_file, uint32_t *value)
70 {
71 FILE *f;
72 char buf[BUFSIZ];
73
74 f = fopen(sysfs_file, "r");
75 if (f == NULL) {
76 return -1;
77 }
78
79 if (fgets(buf, sizeof(buf), f) != NULL) {
80 *value = strtoul(buf, NULL, 10);
81 }
82
83 fclose(f);
84
85 return 0;
86 }
87
88 static int
89 get_str_from_file(const char *sysfs_file, char *buf, int len)
90 {
91 FILE *f;
92
93 f = fopen(sysfs_file, "r");
94 if (f == NULL) {
95 return -1;
96 }
97
98 if (fgets(buf, len, f) != NULL) {
99 fclose(f);
100 return 0;
101 }
102
103 fclose(f);
104 return -1;
105 }
106
107 static int
108 put_u32_to_file(const char *sysfs_file, uint32_t value)
109 {
110 FILE *f;
111 int n;
112 char buf[BUFSIZ];
113
114 f = fopen(sysfs_file, "w");
115 if (f == NULL) {
116 return -1;
117 }
118
119 n = snprintf(buf, sizeof(buf), "%ul", value);
120 if ((n < 0) || (n >= (int)sizeof(buf))) {
121 fclose(f);
122 return -1;
123 }
124
125 if (fwrite(buf, n, 1, f) == 0) {
126 fclose(f);
127 return -1;
128 }
129
130 fclose(f);
131 return 0;
132 }
133
134 static int
135 get_u64_from_file(const char *sysfs_file, uint64_t *value)
136 {
137 FILE *f;
138 char buf[BUFSIZ];
139
140 f = fopen(sysfs_file, "r");
141 if (f == NULL) {
142 return -1;
143 }
144
145 if (fgets(buf, sizeof(buf), f) != NULL) {
146 *value = strtoull(buf, NULL, 10);
147 }
148
149 fclose(f);
150
151 return 0;
152 }
153
154 static int
155 get_dma_channel_count(void)
156 {
157 int count = 0;
158 struct dirent *e;
159 DIR *dir;
160 char *str;
161
162 dir = opendir("/sys/bus/pci/drivers/ioatdma");
163 if (dir == NULL) {
164 return 0;
165 }
166
167 while ((e = readdir(dir)) != NULL) {
168 str = strstr(e->d_name, ":");
169 if (str != NULL)
170 count++;
171 }
172 closedir(dir);
173
174 return count;
175 }
176
177 static void
178 usage(char *program_name)
179 {
180 printf("%s options\n", program_name);
181 printf("\t[-h usage]\n");
182 printf("\t[-n number of DMA channels]\n");
183 printf("\t[-q queue depth, per DMA channel]\n");
184 printf("\t[-s [n^2] transfer size, per descriptor]\n");
185 printf("\t[-t total [n^2] data to tranfer, per DMA channel]\n");
186 }
187
188 int main(int argc, char *argv[])
189 {
190 int op;
191 int rc;
192 char buf[BUFSIZ];
193 uint32_t count = 0;
194 uint32_t i, threads = 0;
195 uint32_t ring_size, queue_depth = 0;
196 uint32_t transfer_size, order = 0;
197 uint64_t total_size, copied = 0;
198 uint64_t elapsed_time = 0;
199 uint64_t total_time = 0;
200 uint64_t perf, total_copied = 0;
201 char channel[1024];
202
203 if (check_modules("ioatdma")) {
204 fprintf(stderr, "Ioat driver not loaded,"
205 " run `modprobe -v ioatdma` first\n");
206 return -1;
207 }
208 if (check_modules("dmaperf")) {
209 fprintf(stderr, "Kernel Ioat test driver not loaded,"
210 " run `insmod dmaperf.ko` in the kmod directory\n");
211 return -1;
212 }
213 count = get_dma_channel_count();
214 if (!count) {
215 fprintf(stderr, "No DMA channel found\n");
216 return -1;
217 }
218
219 ring_size = 1UL << 16;
220
221 while ((op = getopt(argc, argv, "hn:q:s:t:")) != -1) {
222 switch (op) {
223 case 'n':
224 threads = atoi(optarg);
225 if (threads > count) {
226 fprintf(stderr, "Error: Total channel count %u\n", count);
227 return -1;
228 }
229 rc = put_u32_to_file("/sys/kernel/debug/dmaperf/dmaperf/threads", threads);
230 if (rc < 0) {
231 fprintf(stderr, "Cannot set dma channels\n");
232 return -1;
233 }
234 break;
235 case 'q':
236 queue_depth = atoi(optarg);
237 if (queue_depth > ring_size) {
238 fprintf(stderr, "Max Ioat DMA ring size %d\n", ring_size);
239 return -1;
240 }
241 rc = put_u32_to_file("/sys/kernel/debug/dmaperf/dmaperf/queue_depth", queue_depth);
242 if (rc < 0) {
243 fprintf(stderr, "Cannot set queue depth\n");
244 return -1;
245 }
246 break;
247 case 's':
248 order = atoi(optarg);
249 rc = put_u32_to_file("/sys/kernel/debug/dmaperf/dmaperf/transfer_size_order", order);
250 if (rc < 0) {
251 fprintf(stderr, "Cannot set descriptor transfer size order\n");
252 return -1;
253 }
254 break;
255 case 't':
256 order = atoi(optarg);
257 rc = put_u32_to_file("/sys/kernel/debug/dmaperf/dmaperf/total_size_order", order);
258 if (rc < 0) {
259 fprintf(stderr, "Cannot set channel total transfer size order\n");
260 return -1;
261 }
262 break;
263 case 'h' :
264 usage(argv[0]);
265 exit(0);
266 default:
267 usage(argv[0]);
268 exit(1);
269 }
270 }
271
272 /* get driver configuration */
273 rc = get_u32_from_file("/sys/kernel/debug/dmaperf/dmaperf/transfer_size_order",
274 &order);
275 if (rc < 0) {
276 fprintf(stderr, "Cannot get channel descriptor transfer size\n");
277 return -1;
278 }
279 transfer_size = 1UL << order;
280
281 rc = get_u32_from_file("/sys/kernel/debug/dmaperf/dmaperf/total_size_order",
282 &order);
283 if (rc < 0) {
284 fprintf(stderr, "Cannot get channel total transfer size\n");
285 return -1;
286 }
287 total_size = 1ULL << order;
288
289 rc = get_u32_from_file("/sys/kernel/debug/dmaperf/dmaperf/threads",
290 &threads);
291 if (rc < 0) {
292 fprintf(stderr, "Cannot get dma channel threads\n");
293 return -1;
294 }
295
296 rc = get_u32_from_file("/sys/kernel/debug/dmaperf/dmaperf/queue_depth",
297 &queue_depth);
298 if (rc < 0) {
299 fprintf(stderr, "Cannot get queue depth\n");
300 return -1;
301 }
302
303 fprintf(stdout,
304 "Total %d Channels, Queue_Depth %d, Transfer Size %d Bytes, Total Transfer Size %"PRIu64" GB\n",
305 threads, queue_depth, transfer_size, total_size >> 30ULL);
306
307 /* run the channels */
308 rc = put_u32_to_file("/sys/kernel/debug/dmaperf/dmaperf/run", 1);
309 if (rc < 0) {
310 fprintf(stderr, "Cannot run the channels\n");
311 return -1;
312 }
313
314 fprintf(stdout, "Running I/O ");
315 fflush(stdout);
316 memset(buf, 0, BUFSIZ);
317 /* wait all the channels to be idle */
318 do {
319 fprintf(stdout, ". ");
320 fflush(stdout);
321 sleep(1);
322
323 if (strstr(buf, "idle") != NULL) {
324 fprintf(stdout, "\n");
325 fflush(stdout);
326 sleep(1);
327 break;
328 }
329 } while (!get_str_from_file("/sys/kernel/debug/dmaperf/dmaperf/status", buf, BUFSIZ));
330
331 /* collect each channel performance data */
332
333 for (i = 0; i < threads; i++) {
334 /* total data transfer length for the DMA channel in Bytes */
335 snprintf(channel, sizeof(channel), "/sys/kernel/debug/dmaperf/dmaperf/thread_%u/copied", i);
336 rc = get_u64_from_file(channel, &copied);
337 if (rc < 0) {
338 fprintf(stderr, "Cannot get channel copied data\n");
339 return -1;
340 }
341 /* time in microseconds for total data transfer length */
342 snprintf(channel, sizeof(channel), "/sys/kernel/debug/dmaperf/dmaperf/thread_%u/elapsed_time", i);
343 /* elapsed_time is in microsecond */
344 rc = get_u64_from_file(channel, &elapsed_time);
345 if (rc < 0) {
346 fprintf(stderr, "Cannot get channel elapsed time\n");
347 return -1;
348 }
349 assert(elapsed_time != 0);
350 perf = (copied * 1000 * 1000) / (elapsed_time * 1024 * 1024);
351 total_copied += copied;
352 total_time = ioat_max(elapsed_time, total_time);
353 fprintf(stdout, "Channel %d Bandwidth %"PRIu64" MiB/s\n",
354 i, perf);
355 }
356
357 if (total_time && threads) {
358 fprintf(stdout, "Total Channel Bandwidth: %"PRIu64" MiB/s\n",
359 total_copied / total_time);
360 fprintf(stdout, "Average Bandwidth Per Channel: %"PRIu64" MiB/s\n",
361 (total_copied * 1000 * 1000) / (total_time * threads * 1024 * 1024));
362 }
363
364 return 0;
365 }