blob: 8d2678b22c360fcedb29c1fe083706e0de4072cc [file] [log] [blame]
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -08001/*
2 * Loopback test application
3 *
4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
6 *
7 * Provided under the three clause BSD license found in the LICENSE file.
8 */
9#include <errno.h>
10#include <fcntl.h>
11#include <stdio.h>
12#include <string.h>
13#include <stdlib.h>
Axel Haslam9250c0e2016-02-26 11:39:49 +010014#include <stdint.h>
15#include <poll.h>
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080016#include <sys/types.h>
17#include <time.h>
18#include <unistd.h>
19#include <dirent.h>
Axel Haslam3b900402016-03-11 13:19:30 +010020#include <signal.h>
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080021
Axel Haslam3f830562016-01-29 11:34:19 +010022#define MAX_NUM_DEVICES 10
Johan Hovold0e68b682020-03-12 12:01:51 +010023#define MAX_SYSFS_PREFIX 0x80
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080024#define MAX_SYSFS_PATH 0x200
25#define CSV_MAX_LINE 0x1000
26#define SYSFS_MAX_INT 0x20
27#define MAX_STR_LEN 255
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080028#define DEFAULT_ASYNC_TIMEOUT 200000
29
30struct dict {
31 char *name;
32 int type;
33};
34
35static struct dict dict[] = {
36 {"ping", 2},
37 {"transfer", 3},
Greg Kroah-Hartmand5bc9602015-12-15 13:57:22 -080038 {"sink", 4},
39 {NULL,} /* list termination */
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080040};
41
42struct loopback_results {
43 float latency_avg;
44 uint32_t latency_max;
45 uint32_t latency_min;
46 uint32_t latency_jitter;
47
48 float request_avg;
49 uint32_t request_max;
50 uint32_t request_min;
51 uint32_t request_jitter;
52
53 float throughput_avg;
54 uint32_t throughput_max;
55 uint32_t throughput_min;
56 uint32_t throughput_jitter;
57
58 float apbridge_unipro_latency_avg;
59 uint32_t apbridge_unipro_latency_max;
60 uint32_t apbridge_unipro_latency_min;
61 uint32_t apbridge_unipro_latency_jitter;
62
Axel Haslamb797c432016-05-24 16:21:29 +020063 float gbphy_firmware_latency_avg;
64 uint32_t gbphy_firmware_latency_max;
65 uint32_t gbphy_firmware_latency_min;
66 uint32_t gbphy_firmware_latency_jitter;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080067
68 uint32_t error;
69};
70
71struct loopback_device {
Johan Hovold0e68b682020-03-12 12:01:51 +010072 char name[MAX_STR_LEN];
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080073 char sysfs_entry[MAX_SYSFS_PATH];
74 char debugfs_entry[MAX_SYSFS_PATH];
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080075 struct loopback_results results;
76};
77
78struct loopback_test {
79 int verbose;
80 int debug;
81 int raw_data_dump;
82 int porcelain;
83 int mask;
84 int size;
85 int iteration_max;
86 int aggregate_output;
87 int test_id;
88 int device_count;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080089 int list_devices;
90 int use_async;
91 int async_timeout;
92 int async_outstanding_operations;
93 int us_wait;
Axel Haslam5bee7602016-01-26 21:26:02 +010094 int file_output;
Ryan Lim346bae62016-07-20 08:14:04 -070095 int stop_all;
Axel Haslam9250c0e2016-02-26 11:39:49 +010096 int poll_count;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -080097 char test_name[MAX_STR_LEN];
Johan Hovold0e68b682020-03-12 12:01:51 +010098 char sysfs_prefix[MAX_SYSFS_PREFIX];
99 char debugfs_prefix[MAX_SYSFS_PREFIX];
Axel Haslam3b900402016-03-11 13:19:30 +0100100 struct timespec poll_timeout;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800101 struct loopback_device devices[MAX_NUM_DEVICES];
102 struct loopback_results aggregate_results;
Axel Haslam9250c0e2016-02-26 11:39:49 +0100103 struct pollfd fds[MAX_NUM_DEVICES];
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800104};
Axel Haslam9250c0e2016-02-26 11:39:49 +0100105
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800106struct loopback_test t;
107
108/* Helper macros to calculate the aggregate results for all devices */
109static inline int device_enabled(struct loopback_test *t, int dev_idx);
110
111#define GET_MAX(field) \
112static int get_##field##_aggregate(struct loopback_test *t) \
113{ \
114 uint32_t max = 0; \
115 int i; \
116 for (i = 0; i < t->device_count; i++) { \
117 if (!device_enabled(t, i)) \
118 continue; \
119 if (t->devices[i].results.field > max) \
120 max = t->devices[i].results.field; \
121 } \
122 return max; \
123} \
124
125#define GET_MIN(field) \
126static int get_##field##_aggregate(struct loopback_test *t) \
127{ \
128 uint32_t min = ~0; \
129 int i; \
130 for (i = 0; i < t->device_count; i++) { \
131 if (!device_enabled(t, i)) \
132 continue; \
133 if (t->devices[i].results.field < min) \
134 min = t->devices[i].results.field; \
135 } \
136 return min; \
137} \
138
139#define GET_AVG(field) \
140static int get_##field##_aggregate(struct loopback_test *t) \
141{ \
142 uint32_t val = 0; \
143 uint32_t count = 0; \
144 int i; \
145 for (i = 0; i < t->device_count; i++) { \
146 if (!device_enabled(t, i)) \
147 continue; \
148 count++; \
149 val += t->devices[i].results.field; \
150 } \
151 if (count) \
152 val /= count; \
153 return val; \
154} \
155
156GET_MAX(throughput_max);
157GET_MAX(request_max);
158GET_MAX(latency_max);
159GET_MAX(apbridge_unipro_latency_max);
Axel Haslamb797c432016-05-24 16:21:29 +0200160GET_MAX(gbphy_firmware_latency_max);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800161GET_MIN(throughput_min);
162GET_MIN(request_min);
163GET_MIN(latency_min);
164GET_MIN(apbridge_unipro_latency_min);
Axel Haslamb797c432016-05-24 16:21:29 +0200165GET_MIN(gbphy_firmware_latency_min);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800166GET_AVG(throughput_avg);
167GET_AVG(request_avg);
168GET_AVG(latency_avg);
169GET_AVG(apbridge_unipro_latency_avg);
Axel Haslamb797c432016-05-24 16:21:29 +0200170GET_AVG(gbphy_firmware_latency_avg);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800171
172void abort()
173{
174 _exit(1);
175}
176
177void usage(void)
178{
179 fprintf(stderr, "Usage: loopback_test TEST [SIZE] ITERATIONS [SYSPATH] [DBGPATH]\n\n"
180 " Run TEST for a number of ITERATIONS with operation data SIZE bytes\n"
181 " TEST may be \'ping\' \'transfer\' or \'sink\'\n"
182 " SIZE indicates the size of transfer <= greybus max payload bytes\n"
183 " ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n"
184 " Note if ITERATIONS is set to zero then this utility will\n"
185 " initiate an infinite (non terminating) test and exit\n"
186 " without logging any metrics data\n"
187 " SYSPATH indicates the sysfs path for the loopback greybus entries e.g.\n"
188 " /sys/bus/greybus/devices\n"
189 " DBGPATH indicates the debugfs path for the loopback greybus entries e.g.\n"
190 " /sys/kernel/debug/gb_loopback/\n"
191 " Mandatory arguments\n"
192 " -t must be one of the test names - sink, transfer or ping\n"
193 " -i iteration count - the number of iterations to run the test over\n"
194 " Optional arguments\n"
195 " -S sysfs location - location for greybus 'endo' entires default /sys/bus/greybus/devices/\n"
196 " -D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/\n"
197 " -s size of data packet to send during test - defaults to zero\n"
198 " -m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc\n"
199 " default is zero which means broadcast to all connections\n"
200 " -v verbose output\n"
201 " -d debug output\n"
202 " -r raw data output - when specified the full list of latency values are included in the output CSV\n"
203 " -p porcelain - when specified printout is in a user-friendly non-CSV format. This option suppresses writing to CSV file\n"
204 " -a aggregate - show aggregation of all enabled devices\n"
205 " -l list found loopback devices and exit\n"
206 " -x Async - Enable async transfers\n"
207 " -o Async Timeout - Timeout in uSec for async operations\n"
Axel Haslam9250c0e2016-02-26 11:39:49 +0100208 " -O Poll loop time out in seconds(max time a test is expected to last, default: 30sec)\n"
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800209 " -c Max number of outstanding operations for async operations\n"
210 " -w Wait in uSec between operations\n"
Axel Haslam5bee7602016-01-26 21:26:02 +0100211 " -z Enable output to a CSV file (incompatible with -p)\n"
Ryan Lim346bae62016-07-20 08:14:04 -0700212 " -f When starting new loopback test, stop currently running tests on all devices\n"
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800213 "Examples:\n"
214 " Send 10000 transfers with a packet size of 128 bytes to all active connections\n"
215 " loopback_test -t transfer -s 128 -i 10000 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"
216 " loopback_test -t transfer -s 128 -i 10000 -m 0\n"
217 " Send 10000 transfers with a packet size of 128 bytes to connection 1 and 4\n"
218 " loopback_test -t transfer -s 128 -i 10000 -m 9\n"
219 " loopback_test -t ping -s 0 128 -i -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"
220 " loopback_test -t sink -s 2030 -i 32768 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n");
221 abort();
222}
223
224static inline int device_enabled(struct loopback_test *t, int dev_idx)
225{
226 if (!t->mask || (t->mask & (1 << dev_idx)))
227 return 1;
228
229 return 0;
230}
231
232static void show_loopback_devices(struct loopback_test *t)
233{
234 int i;
235
236 if (t->device_count == 0) {
237 printf("No loopback devices.\n");
238 return;
239 }
240
241 for (i = 0; i < t->device_count; i++)
242 printf("device[%d] = %s\n", i, t->devices[i].name);
243
244}
245
246int open_sysfs(const char *sys_pfx, const char *node, int flags)
247{
248 int fd;
249 char path[MAX_SYSFS_PATH];
250
251 snprintf(path, sizeof(path), "%s%s", sys_pfx, node);
252 fd = open(path, flags);
253 if (fd < 0) {
254 fprintf(stderr, "unable to open %s\n", path);
255 abort();
256 }
257 return fd;
258}
259
260int read_sysfs_int_fd(int fd, const char *sys_pfx, const char *node)
261{
262 char buf[SYSFS_MAX_INT];
263
264 if (read(fd, buf, sizeof(buf)) < 0) {
265 fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node,
266 strerror(errno));
267 close(fd);
268 abort();
269 }
270 return atoi(buf);
271}
272
273float read_sysfs_float_fd(int fd, const char *sys_pfx, const char *node)
274{
275 char buf[SYSFS_MAX_INT];
276
277 if (read(fd, buf, sizeof(buf)) < 0) {
278
279 fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node,
280 strerror(errno));
281 close(fd);
282 abort();
283 }
284 return atof(buf);
285}
286
287int read_sysfs_int(const char *sys_pfx, const char *node)
288{
289 int fd, val;
290
291 fd = open_sysfs(sys_pfx, node, O_RDONLY);
292 val = read_sysfs_int_fd(fd, sys_pfx, node);
293 close(fd);
294 return val;
295}
296
297float read_sysfs_float(const char *sys_pfx, const char *node)
298{
299 int fd;
300 float val;
301
302 fd = open_sysfs(sys_pfx, node, O_RDONLY);
303 val = read_sysfs_float_fd(fd, sys_pfx, node);
304 close(fd);
305 return val;
306}
307
308void write_sysfs_val(const char *sys_pfx, const char *node, int val)
309{
310 int fd, len;
311 char buf[SYSFS_MAX_INT];
312
313 fd = open_sysfs(sys_pfx, node, O_RDWR);
314 len = snprintf(buf, sizeof(buf), "%d", val);
315 if (write(fd, buf, len) < 0) {
316 fprintf(stderr, "unable to write to %s%s %s\n", sys_pfx, node,
317 strerror(errno));
318 close(fd);
319 abort();
320 }
321 close(fd);
322}
323
324static int get_results(struct loopback_test *t)
325{
326 struct loopback_device *d;
327 struct loopback_results *r;
328 int i;
329
330 for (i = 0; i < t->device_count; i++) {
331 if (!device_enabled(t, i))
332 continue;
333
334 d = &t->devices[i];
335 r = &d->results;
336
337 r->error = read_sysfs_int(d->sysfs_entry, "error");
338 r->request_min = read_sysfs_int(d->sysfs_entry, "requests_per_second_min");
339 r->request_max = read_sysfs_int(d->sysfs_entry, "requests_per_second_max");
340 r->request_avg = read_sysfs_float(d->sysfs_entry, "requests_per_second_avg");
341
342 r->latency_min = read_sysfs_int(d->sysfs_entry, "latency_min");
343 r->latency_max = read_sysfs_int(d->sysfs_entry, "latency_max");
344 r->latency_avg = read_sysfs_float(d->sysfs_entry, "latency_avg");
345
346 r->throughput_min = read_sysfs_int(d->sysfs_entry, "throughput_min");
347 r->throughput_max = read_sysfs_int(d->sysfs_entry, "throughput_max");
348 r->throughput_avg = read_sysfs_float(d->sysfs_entry, "throughput_avg");
349
350 r->apbridge_unipro_latency_min =
351 read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_min");
352 r->apbridge_unipro_latency_max =
353 read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_max");
354 r->apbridge_unipro_latency_avg =
355 read_sysfs_float(d->sysfs_entry, "apbridge_unipro_latency_avg");
356
Axel Haslamb797c432016-05-24 16:21:29 +0200357 r->gbphy_firmware_latency_min =
358 read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_min");
359 r->gbphy_firmware_latency_max =
360 read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_max");
361 r->gbphy_firmware_latency_avg =
362 read_sysfs_float(d->sysfs_entry, "gbphy_firmware_latency_avg");
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800363
364 r->request_jitter = r->request_max - r->request_min;
365 r->latency_jitter = r->latency_max - r->latency_min;
366 r->throughput_jitter = r->throughput_max - r->throughput_min;
367 r->apbridge_unipro_latency_jitter =
368 r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min;
Axel Haslamb797c432016-05-24 16:21:29 +0200369 r->gbphy_firmware_latency_jitter =
370 r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800371
372 }
373
374 /*calculate the aggregate results of all enabled devices */
375 if (t->aggregate_output) {
376 r = &t->aggregate_results;
377
378 r->request_min = get_request_min_aggregate(t);
379 r->request_max = get_request_max_aggregate(t);
380 r->request_avg = get_request_avg_aggregate(t);
381
382 r->latency_min = get_latency_min_aggregate(t);
383 r->latency_max = get_latency_max_aggregate(t);
384 r->latency_avg = get_latency_avg_aggregate(t);
385
386 r->throughput_min = get_throughput_min_aggregate(t);
387 r->throughput_max = get_throughput_max_aggregate(t);
388 r->throughput_avg = get_throughput_avg_aggregate(t);
389
390 r->apbridge_unipro_latency_min =
391 get_apbridge_unipro_latency_min_aggregate(t);
392 r->apbridge_unipro_latency_max =
393 get_apbridge_unipro_latency_max_aggregate(t);
394 r->apbridge_unipro_latency_avg =
395 get_apbridge_unipro_latency_avg_aggregate(t);
396
Axel Haslamb797c432016-05-24 16:21:29 +0200397 r->gbphy_firmware_latency_min =
398 get_gbphy_firmware_latency_min_aggregate(t);
399 r->gbphy_firmware_latency_max =
400 get_gbphy_firmware_latency_max_aggregate(t);
401 r->gbphy_firmware_latency_avg =
402 get_gbphy_firmware_latency_avg_aggregate(t);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800403
404 r->request_jitter = r->request_max - r->request_min;
405 r->latency_jitter = r->latency_max - r->latency_min;
406 r->throughput_jitter = r->throughput_max - r->throughput_min;
407 r->apbridge_unipro_latency_jitter =
408 r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min;
Axel Haslamb797c432016-05-24 16:21:29 +0200409 r->gbphy_firmware_latency_jitter =
410 r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800411
412 }
413
414 return 0;
415}
416
417void log_csv_error(int len, int err)
418{
419 fprintf(stderr, "unable to write %d bytes to csv %s\n", len,
420 strerror(err));
421}
422
423int format_output(struct loopback_test *t,
424 struct loopback_results *r,
425 const char *dev_name,
426 char *buf, int buf_len,
427 struct tm *tm)
428{
429 int len = 0;
430
431 memset(buf, 0x00, buf_len);
432 len = snprintf(buf, buf_len, "%u-%u-%u %u:%u:%u",
433 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
434 tm->tm_hour, tm->tm_min, tm->tm_sec);
435
436 if (t->porcelain) {
437 len += snprintf(&buf[len], buf_len - len,
438 "\n test:\t\t\t%s\n path:\t\t\t%s\n size:\t\t\t%u\n iterations:\t\t%u\n errors:\t\t%u\n async:\t\t\t%s\n",
439 t->test_name,
440 dev_name,
441 t->size,
442 t->iteration_max,
443 r->error,
444 t->use_async ? "Enabled" : "Disabled");
445
446 len += snprintf(&buf[len], buf_len - len,
447 " requests per-sec:\tmin=%u, max=%u, average=%f, jitter=%u\n",
448 r->request_min,
449 r->request_max,
450 r->request_avg,
451 r->request_jitter);
452
453 len += snprintf(&buf[len], buf_len - len,
454 " ap-throughput B/s:\tmin=%u max=%u average=%f jitter=%u\n",
455 r->throughput_min,
456 r->throughput_max,
457 r->throughput_avg,
458 r->throughput_jitter);
459 len += snprintf(&buf[len], buf_len - len,
460 " ap-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
461 r->latency_min,
462 r->latency_max,
463 r->latency_avg,
464 r->latency_jitter);
465 len += snprintf(&buf[len], buf_len - len,
466 " apbridge-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
467 r->apbridge_unipro_latency_min,
468 r->apbridge_unipro_latency_max,
469 r->apbridge_unipro_latency_avg,
470 r->apbridge_unipro_latency_jitter);
471
472 len += snprintf(&buf[len], buf_len - len,
Axel Haslamb797c432016-05-24 16:21:29 +0200473 " gbphy-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
474 r->gbphy_firmware_latency_min,
475 r->gbphy_firmware_latency_max,
476 r->gbphy_firmware_latency_avg,
477 r->gbphy_firmware_latency_jitter);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800478
479 } else {
480 len += snprintf(&buf[len], buf_len- len, ",%s,%s,%u,%u,%u",
481 t->test_name, dev_name, t->size, t->iteration_max,
482 r->error);
483
484 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
485 r->request_min,
486 r->request_max,
487 r->request_avg,
488 r->request_jitter);
489
490 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
491 r->latency_min,
492 r->latency_max,
493 r->latency_avg,
494 r->latency_jitter);
495
496 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
497 r->throughput_min,
498 r->throughput_max,
499 r->throughput_avg,
500 r->throughput_jitter);
501
502 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
503 r->apbridge_unipro_latency_min,
504 r->apbridge_unipro_latency_max,
505 r->apbridge_unipro_latency_avg,
506 r->apbridge_unipro_latency_jitter);
507
508 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
Axel Haslamb797c432016-05-24 16:21:29 +0200509 r->gbphy_firmware_latency_min,
510 r->gbphy_firmware_latency_max,
511 r->gbphy_firmware_latency_avg,
512 r->gbphy_firmware_latency_jitter);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800513 }
514
515 printf("\n%s\n", buf);
516
517 return len;
518}
519
520static int log_results(struct loopback_test *t)
521{
522 int fd, i, len, ret;
523 struct tm tm;
524 time_t local_time;
525 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
526 char file_name[MAX_SYSFS_PATH];
527 char data[CSV_MAX_LINE];
528
529 local_time = time(NULL);
530 tm = *localtime(&local_time);
531
532 /*
533 * file name will test_name_size_iteration_max.csv
534 * every time the same test with the same parameters is run we will then
535 * append to the same CSV with datestamp - representing each test
536 * dataset.
537 */
Axel Haslam5bee7602016-01-26 21:26:02 +0100538 if (t->file_output && !t->porcelain) {
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800539 snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv",
540 t->test_name, t->size, t->iteration_max);
541
542 fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, mode);
543 if (fd < 0) {
544 fprintf(stderr, "unable to open %s for appendation\n", file_name);
545 abort();
546 }
547
548 }
549 for (i = 0; i < t->device_count; i++) {
550 if (!device_enabled(t, i))
551 continue;
552
553 len = format_output(t, &t->devices[i].results,
554 t->devices[i].name,
555 data, sizeof(data), &tm);
Axel Haslam5bee7602016-01-26 21:26:02 +0100556 if (t->file_output && !t->porcelain) {
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800557 ret = write(fd, data, len);
558 if (ret == -1)
559 fprintf(stderr, "unable to write %d bytes to csv.\n", len);
560 }
561
562 }
563
564
565 if (t->aggregate_output) {
566 len = format_output(t, &t->aggregate_results, "aggregate",
567 data, sizeof(data), &tm);
Axel Haslam5bee7602016-01-26 21:26:02 +0100568 if (t->file_output && !t->porcelain) {
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800569 ret = write(fd, data, len);
570 if (ret == -1)
571 fprintf(stderr, "unable to write %d bytes to csv.\n", len);
572 }
573 }
574
Axel Haslam5bee7602016-01-26 21:26:02 +0100575 if (t->file_output && !t->porcelain)
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800576 close(fd);
577
578 return 0;
579}
580
581int is_loopback_device(const char *path, const char *node)
582{
583 char file[MAX_SYSFS_PATH];
584
585 snprintf(file, MAX_SYSFS_PATH, "%s%s/iteration_count", path, node);
586 if (access(file, F_OK) == 0)
587 return 1;
588 return 0;
589}
590
591int find_loopback_devices(struct loopback_test *t)
592{
593 struct dirent **namelist;
594 int i, n, ret;
595 unsigned int dev_id;
596 struct loopback_device *d;
597
598 n = scandir(t->sysfs_prefix, &namelist, NULL, alphasort);
599 if (n < 0) {
600 perror("scandir");
601 ret = -ENODEV;
602 goto baddir;
603 }
604
605 /* Don't include '.' and '..' */
606 if (n <= 2) {
607 ret = -ENOMEM;
608 goto done;
609 }
610
611 for (i = 0; i < n; i++) {
612 ret = sscanf(namelist[i]->d_name, "gb_loopback%u", &dev_id);
613 if (ret != 1)
614 continue;
615
616 if (!is_loopback_device(t->sysfs_prefix, namelist[i]->d_name))
617 continue;
618
619 if (t->device_count == MAX_NUM_DEVICES) {
620 fprintf(stderr, "max number of devices reached!\n");
621 break;
622 }
623
624 d = &t->devices[t->device_count++];
625 snprintf(d->name, MAX_STR_LEN, "gb_loopback%u", dev_id);
626
627 snprintf(d->sysfs_entry, MAX_SYSFS_PATH, "%s%s/",
628 t->sysfs_prefix, d->name);
629
630 snprintf(d->debugfs_entry, MAX_SYSFS_PATH, "%sraw_latency_%s",
631 t->debugfs_prefix, d->name);
632
633 if (t->debug)
634 printf("add %s %s\n", d->sysfs_entry,
635 d->debugfs_entry);
636 }
637
638 ret = 0;
639done:
640 for (i = 0; i < n; i++)
641 free(namelist[n]);
642 free(namelist);
643baddir:
644 return ret;
645}
646
Axel Haslam9250c0e2016-02-26 11:39:49 +0100647static int open_poll_files(struct loopback_test *t)
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800648{
Axel Haslam9250c0e2016-02-26 11:39:49 +0100649 struct loopback_device *dev;
Johan Hovoldd444ed62020-03-12 12:01:50 +0100650 char buf[MAX_SYSFS_PATH + MAX_STR_LEN];
Axel Haslam9250c0e2016-02-26 11:39:49 +0100651 char dummy;
652 int fds_idx = 0;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800653 int i;
654
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800655 for (i = 0; i < t->device_count; i++) {
Axel Haslam9250c0e2016-02-26 11:39:49 +0100656 dev = &t->devices[i];
657
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800658 if (!device_enabled(t, i))
659 continue;
660
Axel Haslam9250c0e2016-02-26 11:39:49 +0100661 snprintf(buf, sizeof(buf), "%s%s", dev->sysfs_entry, "iteration_count");
662 t->fds[fds_idx].fd = open(buf, O_RDONLY);
663 if (t->fds[fds_idx].fd < 0) {
664 fprintf(stderr, "Error opening poll file!\n");
665 goto err;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800666 }
Axel Haslam9250c0e2016-02-26 11:39:49 +0100667 read(t->fds[fds_idx].fd, &dummy, 1);
668 t->fds[fds_idx].events = POLLERR|POLLPRI;
669 t->fds[fds_idx].revents = 0;
670 fds_idx++;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800671 }
672
Axel Haslam9250c0e2016-02-26 11:39:49 +0100673 t->poll_count = fds_idx;
674
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800675 return 0;
Axel Haslam9250c0e2016-02-26 11:39:49 +0100676
677err:
678 for (i = 0; i < fds_idx; i++)
679 close(t->fds[fds_idx].fd);
680
681 return -1;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800682}
683
Axel Haslam9250c0e2016-02-26 11:39:49 +0100684static int close_poll_files(struct loopback_test *t)
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800685{
686 int i;
Axel Haslam9250c0e2016-02-26 11:39:49 +0100687 for (i = 0; i < t->poll_count; i++)
688 close(t->fds[i].fd);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800689
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800690 return 0;
691}
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800692static int is_complete(struct loopback_test *t)
693{
Greg Kroah-Hartman6bfff1d2015-12-15 13:55:05 -0800694 int iteration_count;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800695 int i;
696
697 for (i = 0; i < t->device_count; i++) {
698 if (!device_enabled(t, i))
699 continue;
700
701 iteration_count = read_sysfs_int(t->devices[i].sysfs_entry,
702 "iteration_count");
703
704 /* at least one device did not finish yet */
705 if (iteration_count != t->iteration_max)
706 return 0;
707 }
708
709 return 1;
710}
711
Axel Haslam3b900402016-03-11 13:19:30 +0100712static void stop_tests(struct loopback_test *t)
713{
714 int i;
715
716 for (i = 0; i < t->device_count; i++) {
717 if (!device_enabled(t, i))
718 continue;
719 write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
720 }
721}
722
723static void handler(int sig) { /* do nothing */ }
724
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800725static int wait_for_complete(struct loopback_test *t)
726{
Axel Haslam9250c0e2016-02-26 11:39:49 +0100727 int number_of_events = 0;
728 char dummy;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800729 int ret;
Axel Haslam9250c0e2016-02-26 11:39:49 +0100730 int i;
Axel Haslam3b900402016-03-11 13:19:30 +0100731 struct timespec *ts = NULL;
732 struct sigaction sa;
733 sigset_t mask_old, mask;
734
735 sigemptyset(&mask);
736 sigemptyset(&mask_old);
737 sigaddset(&mask, SIGINT);
738 sigprocmask(SIG_BLOCK, &mask, &mask_old);
739
740 sa.sa_handler = handler;
741 sa.sa_flags = 0;
742 sigemptyset(&sa.sa_mask);
743 if (sigaction(SIGINT, &sa, NULL) == -1) {
744 fprintf(stderr, "sigaction error\n");
745 return -1;
746 }
747
748 if (t->poll_timeout.tv_sec != 0)
749 ts = &t->poll_timeout;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800750
751 while (1) {
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800752
Axel Haslam3b900402016-03-11 13:19:30 +0100753 ret = ppoll(t->fds, t->poll_count, ts, &mask_old);
754 if (ret <= 0) {
755 stop_tests(t);
756 fprintf(stderr, "Poll exit with errno %d\n", errno);
Axel Haslam9250c0e2016-02-26 11:39:49 +0100757 return -1;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800758 }
Axel Haslam9250c0e2016-02-26 11:39:49 +0100759
760 for (i = 0; i < t->poll_count; i++) {
761 if (t->fds[i].revents & POLLPRI) {
762 /* Dummy read to clear the event */
763 read(t->fds[i].fd, &dummy, 1);
764 number_of_events++;
765 }
766 }
767
768 if (number_of_events == t->poll_count)
769 break;
770 }
771
772 if (!is_complete(t)) {
773 fprintf(stderr, "Iteration count did not finish!\n");
774 return -1;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800775 }
776
777 return 0;
778}
779
780static void prepare_devices(struct loopback_test *t)
781{
782 int i;
783
Ryan Lim346bae62016-07-20 08:14:04 -0700784 /* Cancel any running tests on enabled devices. If
785 * stop_all option is given, stop test on all devices.
786 */
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800787 for (i = 0; i < t->device_count; i++)
Ryan Lim346bae62016-07-20 08:14:04 -0700788 if (t->stop_all || device_enabled(t, i))
Ryan Lim2861e202016-07-20 08:14:02 -0700789 write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800790
791
792 for (i = 0; i < t->device_count; i++) {
793 if (!device_enabled(t, i))
794 continue;
795
796 write_sysfs_val(t->devices[i].sysfs_entry, "us_wait",
797 t->us_wait);
798
799 /* Set operation size */
800 write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
801
802 /* Set iterations */
803 write_sysfs_val(t->devices[i].sysfs_entry, "iteration_max",
804 t->iteration_max);
805
806 if (t->use_async) {
807 write_sysfs_val(t->devices[i].sysfs_entry,
808 "async", 1);
809 write_sysfs_val(t->devices[i].sysfs_entry,
810 "timeout", t->async_timeout);
811 write_sysfs_val(t->devices[i].sysfs_entry,
812 "outstanding_operations_max",
813 t->async_outstanding_operations);
814 } else
815 write_sysfs_val(t->devices[i].sysfs_entry,
816 "async", 0);
817 }
818}
819
820static int start(struct loopback_test *t)
821{
822 int i;
823
824 /* the test starts by writing test_id to the type file. */
825 for (i = 0; i < t->device_count; i++) {
826 if (!device_enabled(t, i))
827 continue;
828
829 write_sysfs_val(t->devices[i].sysfs_entry, "type", t->test_id);
830 }
831
832 return 0;
833}
834
835
836void loopback_run(struct loopback_test *t)
837{
838 int i;
839 int ret;
840
Greg Kroah-Hartmand5bc9602015-12-15 13:57:22 -0800841 for (i = 0; dict[i].name != NULL; i++) {
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800842 if (strstr(dict[i].name, t->test_name))
843 t->test_id = dict[i].type;
844 }
845 if (!t->test_id) {
846 fprintf(stderr, "invalid test %s\n", t->test_name);
847 usage();
848 return;
849 }
850
851 prepare_devices(t);
852
Axel Haslam9250c0e2016-02-26 11:39:49 +0100853 ret = open_poll_files(t);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800854 if (ret)
855 goto err;
856
857 start(t);
858
Axel Haslam9250c0e2016-02-26 11:39:49 +0100859 ret = wait_for_complete(t);
860 close_poll_files(t);
861 if (ret)
862 goto err;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800863
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800864
865 get_results(t);
866
867 log_results(t);
868
869 return;
870
871err:
872 printf("Error running test\n");
873 return;
874}
875
876static int sanity_check(struct loopback_test *t)
877{
878 int i;
879
880 if (t->device_count == 0) {
881 fprintf(stderr, "No loopback devices found\n");
882 return -1;
883 }
884
885 for (i = 0; i < MAX_NUM_DEVICES; i++) {
886 if (!device_enabled(t, i))
887 continue;
888
889 if (t->mask && !strcmp(t->devices[i].name, "")) {
890 fprintf(stderr, "Bad device mask %x\n", (1 << i));
891 return -1;
892 }
893
894 }
895
896
897 return 0;
898}
Axel Haslam3b900402016-03-11 13:19:30 +0100899
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800900int main(int argc, char *argv[])
901{
902 int o, ret;
903 char *sysfs_prefix = "/sys/class/gb_loopback/";
904 char *debugfs_prefix = "/sys/kernel/debug/gb_loopback/";
905
906 memset(&t, 0, sizeof(t));
907
908 while ((o = getopt(argc, argv,
Ryan Lim346bae62016-07-20 08:14:04 -0700909 "t:s:i:S:D:m:v::d::r::p::a::l::x::o:O:c:w:z::f::")) != -1) {
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800910 switch (o) {
911 case 't':
912 snprintf(t.test_name, MAX_STR_LEN, "%s", optarg);
913 break;
914 case 's':
915 t.size = atoi(optarg);
916 break;
917 case 'i':
918 t.iteration_max = atoi(optarg);
919 break;
920 case 'S':
Johan Hovold0e68b682020-03-12 12:01:51 +0100921 snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800922 break;
923 case 'D':
Johan Hovold0e68b682020-03-12 12:01:51 +0100924 snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800925 break;
926 case 'm':
927 t.mask = atol(optarg);
928 break;
929 case 'v':
930 t.verbose = 1;
931 break;
932 case 'd':
933 t.debug = 1;
934 break;
935 case 'r':
936 t.raw_data_dump = 1;
937 break;
938 case 'p':
939 t.porcelain = 1;
940 break;
941 case 'a':
942 t.aggregate_output = 1;
943 break;
944 case 'l':
945 t.list_devices = 1;
946 break;
947 case 'x':
948 t.use_async = 1;
949 break;
950 case 'o':
951 t.async_timeout = atoi(optarg);
952 break;
Axel Haslam9250c0e2016-02-26 11:39:49 +0100953 case 'O':
Axel Haslam3b900402016-03-11 13:19:30 +0100954 t.poll_timeout.tv_sec = atoi(optarg);
Axel Haslam9250c0e2016-02-26 11:39:49 +0100955 break;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800956 case 'c':
957 t.async_outstanding_operations = atoi(optarg);
958 break;
959 case 'w':
960 t.us_wait = atoi(optarg);
961 break;
Axel Haslam5bee7602016-01-26 21:26:02 +0100962 case 'z':
963 t.file_output = 1;
Ryan Limbf326542016-07-20 08:14:03 -0700964 break;
Ryan Lim346bae62016-07-20 08:14:04 -0700965 case 'f':
966 t.stop_all = 1;
967 break;
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800968 default:
969 usage();
970 return -EINVAL;
971 }
972 }
973
974 if (!strcmp(t.sysfs_prefix, ""))
Johan Hovold0e68b682020-03-12 12:01:51 +0100975 snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", sysfs_prefix);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800976
977 if (!strcmp(t.debugfs_prefix, ""))
Johan Hovold0e68b682020-03-12 12:01:51 +0100978 snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", debugfs_prefix);
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800979
980 ret = find_loopback_devices(&t);
981 if (ret)
982 return ret;
983 ret = sanity_check(&t);
984 if (ret)
985 return ret;
986
987 if (t.list_devices) {
988 show_loopback_devices(&t);
989 return 0;
990 }
991
992 if (t.test_name[0] == '\0' || t.iteration_max == 0)
993 usage();
994
995 if (t.async_timeout == 0)
996 t.async_timeout = DEFAULT_ASYNC_TIMEOUT;
997
Greg Kroah-Hartman6b0658f2015-12-15 12:46:22 -0800998 loopback_run(&t);
999
1000 return 0;
1001}