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