1
2
3
4
5
6
7
8
9
10#include <errno.h>
11#include <fcntl.h>
12#include <stdio.h>
13#include <string.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <poll.h>
17#include <sys/types.h>
18#include <time.h>
19#include <unistd.h>
20#include <dirent.h>
21#include <signal.h>
22
23#define MAX_NUM_DEVICES 10
24#define MAX_SYSFS_PATH 0x200
25#define CSV_MAX_LINE 0x1000
26#define SYSFS_MAX_INT 0x20
27#define MAX_STR_LEN 255
28#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},
38 {"sink", 4},
39 {NULL,}
40};
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
63 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;
67
68 uint32_t error;
69};
70
71struct loopback_device {
72 char name[MAX_SYSFS_PATH];
73 char sysfs_entry[MAX_SYSFS_PATH];
74 char debugfs_entry[MAX_SYSFS_PATH];
75 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;
89 int list_devices;
90 int use_async;
91 int async_timeout;
92 int async_outstanding_operations;
93 int us_wait;
94 int file_output;
95 int stop_all;
96 int poll_count;
97 char test_name[MAX_STR_LEN];
98 char sysfs_prefix[MAX_SYSFS_PATH];
99 char debugfs_prefix[MAX_SYSFS_PATH];
100 struct timespec poll_timeout;
101 struct loopback_device devices[MAX_NUM_DEVICES];
102 struct loopback_results aggregate_results;
103 struct pollfd fds[MAX_NUM_DEVICES];
104};
105
106struct loopback_test t;
107
108
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);
160GET_MAX(gbphy_firmware_latency_max);
161GET_MIN(throughput_min);
162GET_MIN(request_min);
163GET_MIN(latency_min);
164GET_MIN(apbridge_unipro_latency_min);
165GET_MIN(gbphy_firmware_latency_min);
166GET_AVG(throughput_avg);
167GET_AVG(request_avg);
168GET_AVG(latency_avg);
169GET_AVG(apbridge_unipro_latency_avg);
170GET_AVG(gbphy_firmware_latency_avg);
171
172void abort(void)
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' entries 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"
208 " -O Poll loop time out in seconds(max time a test is expected to last, default: 30sec)\n"
209 " -c Max number of outstanding operations for async operations\n"
210 " -w Wait in uSec between operations\n"
211 " -z Enable output to a CSV file (incompatible with -p)\n"
212 " -f When starting new loopback test, stop currently running tests on all devices\n"
213 "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
357 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");
363
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;
369 r->gbphy_firmware_latency_jitter =
370 r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
371
372 }
373
374
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
397 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);
403
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;
409 r->gbphy_firmware_latency_jitter =
410 r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
411
412 }
413
414 return 0;
415}
416
417int format_output(struct loopback_test *t,
418 struct loopback_results *r,
419 const char *dev_name,
420 char *buf, int buf_len,
421 struct tm *tm)
422{
423 int len = 0;
424
425 memset(buf, 0x00, buf_len);
426 len = snprintf(buf, buf_len, "%u-%u-%u %u:%u:%u",
427 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
428 tm->tm_hour, tm->tm_min, tm->tm_sec);
429
430 if (t->porcelain) {
431 len += snprintf(&buf[len], buf_len - len,
432 "\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",
433 t->test_name,
434 dev_name,
435 t->size,
436 t->iteration_max,
437 r->error,
438 t->use_async ? "Enabled" : "Disabled");
439
440 len += snprintf(&buf[len], buf_len - len,
441 " requests per-sec:\tmin=%u, max=%u, average=%f, jitter=%u\n",
442 r->request_min,
443 r->request_max,
444 r->request_avg,
445 r->request_jitter);
446
447 len += snprintf(&buf[len], buf_len - len,
448 " ap-throughput B/s:\tmin=%u max=%u average=%f jitter=%u\n",
449 r->throughput_min,
450 r->throughput_max,
451 r->throughput_avg,
452 r->throughput_jitter);
453 len += snprintf(&buf[len], buf_len - len,
454 " ap-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
455 r->latency_min,
456 r->latency_max,
457 r->latency_avg,
458 r->latency_jitter);
459 len += snprintf(&buf[len], buf_len - len,
460 " apbridge-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
461 r->apbridge_unipro_latency_min,
462 r->apbridge_unipro_latency_max,
463 r->apbridge_unipro_latency_avg,
464 r->apbridge_unipro_latency_jitter);
465
466 len += snprintf(&buf[len], buf_len - len,
467 " gbphy-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
468 r->gbphy_firmware_latency_min,
469 r->gbphy_firmware_latency_max,
470 r->gbphy_firmware_latency_avg,
471 r->gbphy_firmware_latency_jitter);
472
473 } else {
474 len += snprintf(&buf[len], buf_len - len, ",%s,%s,%u,%u,%u",
475 t->test_name, dev_name, t->size, t->iteration_max,
476 r->error);
477
478 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
479 r->request_min,
480 r->request_max,
481 r->request_avg,
482 r->request_jitter);
483
484 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
485 r->latency_min,
486 r->latency_max,
487 r->latency_avg,
488 r->latency_jitter);
489
490 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
491 r->throughput_min,
492 r->throughput_max,
493 r->throughput_avg,
494 r->throughput_jitter);
495
496 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
497 r->apbridge_unipro_latency_min,
498 r->apbridge_unipro_latency_max,
499 r->apbridge_unipro_latency_avg,
500 r->apbridge_unipro_latency_jitter);
501
502 len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
503 r->gbphy_firmware_latency_min,
504 r->gbphy_firmware_latency_max,
505 r->gbphy_firmware_latency_avg,
506 r->gbphy_firmware_latency_jitter);
507 }
508
509 printf("\n%s\n", buf);
510
511 return len;
512}
513
514static int log_results(struct loopback_test *t)
515{
516 int fd, i, len, ret;
517 struct tm tm;
518 time_t local_time;
519 char file_name[MAX_SYSFS_PATH];
520 char data[CSV_MAX_LINE];
521
522 local_time = time(NULL);
523 tm = *localtime(&local_time);
524
525
526
527
528
529
530
531 if (t->file_output && !t->porcelain) {
532 snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv",
533 t->test_name, t->size, t->iteration_max);
534
535 fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, 0644);
536 if (fd < 0) {
537 fprintf(stderr, "unable to open %s for appendation\n", file_name);
538 abort();
539 }
540
541 }
542 for (i = 0; i < t->device_count; i++) {
543 if (!device_enabled(t, i))
544 continue;
545
546 len = format_output(t, &t->devices[i].results,
547 t->devices[i].name,
548 data, sizeof(data), &tm);
549 if (t->file_output && !t->porcelain) {
550 ret = write(fd, data, len);
551 if (ret == -1)
552 fprintf(stderr, "unable to write %d bytes to csv.\n", len);
553 }
554
555 }
556
557
558 if (t->aggregate_output) {
559 len = format_output(t, &t->aggregate_results, "aggregate",
560 data, sizeof(data), &tm);
561 if (t->file_output && !t->porcelain) {
562 ret = write(fd, data, len);
563 if (ret == -1)
564 fprintf(stderr, "unable to write %d bytes to csv.\n", len);
565 }
566 }
567
568 if (t->file_output && !t->porcelain)
569 close(fd);
570
571 return 0;
572}
573
574int is_loopback_device(const char *path, const char *node)
575{
576 char file[MAX_SYSFS_PATH];
577
578 snprintf(file, MAX_SYSFS_PATH, "%s%s/iteration_count", path, node);
579 if (access(file, F_OK) == 0)
580 return 1;
581 return 0;
582}
583
584int find_loopback_devices(struct loopback_test *t)
585{
586 struct dirent **namelist;
587 int i, n, ret;
588 unsigned int dev_id;
589 struct loopback_device *d;
590
591 n = scandir(t->sysfs_prefix, &namelist, NULL, alphasort);
592 if (n < 0) {
593 perror("scandir");
594 ret = -ENODEV;
595 goto baddir;
596 }
597
598
599 if (n <= 2) {
600 ret = -ENOMEM;
601 goto done;
602 }
603
604 for (i = 0; i < n; i++) {
605 ret = sscanf(namelist[i]->d_name, "gb_loopback%u", &dev_id);
606 if (ret != 1)
607 continue;
608
609 if (!is_loopback_device(t->sysfs_prefix, namelist[i]->d_name))
610 continue;
611
612 if (t->device_count == MAX_NUM_DEVICES) {
613 fprintf(stderr, "max number of devices reached!\n");
614 break;
615 }
616
617 d = &t->devices[t->device_count++];
618 snprintf(d->name, MAX_STR_LEN, "gb_loopback%u", dev_id);
619
620 snprintf(d->sysfs_entry, MAX_SYSFS_PATH, "%s%s/",
621 t->sysfs_prefix, d->name);
622
623 snprintf(d->debugfs_entry, MAX_SYSFS_PATH, "%sraw_latency_%s",
624 t->debugfs_prefix, d->name);
625
626 if (t->debug)
627 printf("add %s %s\n", d->sysfs_entry, d->debugfs_entry);
628 }
629
630 ret = 0;
631done:
632 for (i = 0; i < n; i++)
633 free(namelist[i]);
634 free(namelist);
635baddir:
636 return ret;
637}
638
639static int open_poll_files(struct loopback_test *t)
640{
641 struct loopback_device *dev;
642 char buf[MAX_STR_LEN];
643 char dummy;
644 int fds_idx = 0;
645 int i;
646
647 for (i = 0; i < t->device_count; i++) {
648 dev = &t->devices[i];
649
650 if (!device_enabled(t, i))
651 continue;
652
653 snprintf(buf, sizeof(buf), "%s%s", dev->sysfs_entry, "iteration_count");
654 t->fds[fds_idx].fd = open(buf, O_RDONLY);
655 if (t->fds[fds_idx].fd < 0) {
656 fprintf(stderr, "Error opening poll file!\n");
657 goto err;
658 }
659 read(t->fds[fds_idx].fd, &dummy, 1);
660 t->fds[fds_idx].events = EPOLLERR|EPOLLPRI;
661 t->fds[fds_idx].revents = 0;
662 fds_idx++;
663 }
664
665 t->poll_count = fds_idx;
666
667 return 0;
668
669err:
670 for (i = 0; i < fds_idx; i++)
671 close(t->fds[i].fd);
672
673 return -1;
674}
675
676static int close_poll_files(struct loopback_test *t)
677{
678 int i;
679 for (i = 0; i < t->poll_count; i++)
680 close(t->fds[i].fd);
681
682 return 0;
683}
684static int is_complete(struct loopback_test *t)
685{
686 int iteration_count;
687 int i;
688
689 for (i = 0; i < t->device_count; i++) {
690 if (!device_enabled(t, i))
691 continue;
692
693 iteration_count = read_sysfs_int(t->devices[i].sysfs_entry,
694 "iteration_count");
695
696
697 if (iteration_count != t->iteration_max)
698 return 0;
699 }
700
701 return 1;
702}
703
704static void stop_tests(struct loopback_test *t)
705{
706 int i;
707
708 for (i = 0; i < t->device_count; i++) {
709 if (!device_enabled(t, i))
710 continue;
711 write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
712 }
713}
714
715static void handler(int sig) { }
716
717static int wait_for_complete(struct loopback_test *t)
718{
719 int number_of_events = 0;
720 char dummy;
721 int ret;
722 int i;
723 struct timespec *ts = NULL;
724 struct sigaction sa;
725 sigset_t mask_old, mask;
726
727 sigemptyset(&mask);
728 sigemptyset(&mask_old);
729 sigaddset(&mask, SIGINT);
730 sigprocmask(SIG_BLOCK, &mask, &mask_old);
731
732 sa.sa_handler = handler;
733 sa.sa_flags = 0;
734 sigemptyset(&sa.sa_mask);
735 if (sigaction(SIGINT, &sa, NULL) == -1) {
736 fprintf(stderr, "sigaction error\n");
737 return -1;
738 }
739
740 if (t->poll_timeout.tv_sec != 0)
741 ts = &t->poll_timeout;
742
743 while (1) {
744
745 ret = ppoll(t->fds, t->poll_count, ts, &mask_old);
746 if (ret <= 0) {
747 stop_tests(t);
748 fprintf(stderr, "Poll exit with errno %d\n", errno);
749 return -1;
750 }
751
752 for (i = 0; i < t->poll_count; i++) {
753 if (t->fds[i].revents & EPOLLPRI) {
754
755 read(t->fds[i].fd, &dummy, 1);
756 number_of_events++;
757 }
758 }
759
760 if (number_of_events == t->poll_count)
761 break;
762 }
763
764 if (!is_complete(t)) {
765 fprintf(stderr, "Iteration count did not finish!\n");
766 return -1;
767 }
768
769 return 0;
770}
771
772static void prepare_devices(struct loopback_test *t)
773{
774 int i;
775
776
777
778
779
780 for (i = 0; i < t->device_count; i++)
781 if (t->stop_all || device_enabled(t, i))
782 write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
783
784
785 for (i = 0; i < t->device_count; i++) {
786 if (!device_enabled(t, i))
787 continue;
788
789 write_sysfs_val(t->devices[i].sysfs_entry, "us_wait",
790 t->us_wait);
791
792
793 write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
794
795
796 write_sysfs_val(t->devices[i].sysfs_entry, "iteration_max",
797 t->iteration_max);
798
799 if (t->use_async) {
800 write_sysfs_val(t->devices[i].sysfs_entry, "async", 1);
801 write_sysfs_val(t->devices[i].sysfs_entry,
802 "timeout", t->async_timeout);
803 write_sysfs_val(t->devices[i].sysfs_entry,
804 "outstanding_operations_max",
805 t->async_outstanding_operations);
806 } else
807 write_sysfs_val(t->devices[i].sysfs_entry, "async", 0);
808 }
809}
810
811static int start(struct loopback_test *t)
812{
813 int i;
814
815
816 for (i = 0; i < t->device_count; i++) {
817 if (!device_enabled(t, i))
818 continue;
819
820 write_sysfs_val(t->devices[i].sysfs_entry, "type", t->test_id);
821 }
822
823 return 0;
824}
825
826
827void loopback_run(struct loopback_test *t)
828{
829 int i;
830 int ret;
831
832 for (i = 0; dict[i].name != NULL; i++) {
833 if (strstr(dict[i].name, t->test_name))
834 t->test_id = dict[i].type;
835 }
836 if (!t->test_id) {
837 fprintf(stderr, "invalid test %s\n", t->test_name);
838 usage();
839 return;
840 }
841
842 prepare_devices(t);
843
844 ret = open_poll_files(t);
845 if (ret)
846 goto err;
847
848 start(t);
849
850 ret = wait_for_complete(t);
851 close_poll_files(t);
852 if (ret)
853 goto err;
854
855
856 get_results(t);
857
858 log_results(t);
859
860 return;
861
862err:
863 printf("Error running test\n");
864 return;
865}
866
867static int sanity_check(struct loopback_test *t)
868{
869 int i;
870
871 if (t->device_count == 0) {
872 fprintf(stderr, "No loopback devices found\n");
873 return -1;
874 }
875
876 for (i = 0; i < MAX_NUM_DEVICES; i++) {
877 if (!device_enabled(t, i))
878 continue;
879
880 if (t->mask && !strcmp(t->devices[i].name, "")) {
881 fprintf(stderr, "Bad device mask %x\n", (1 << i));
882 return -1;
883 }
884
885 }
886
887
888 return 0;
889}
890
891int main(int argc, char *argv[])
892{
893 int o, ret;
894 char *sysfs_prefix = "/sys/class/gb_loopback/";
895 char *debugfs_prefix = "/sys/kernel/debug/gb_loopback/";
896
897 memset(&t, 0, sizeof(t));
898
899 while ((o = getopt(argc, argv,
900 "t:s:i:S:D:m:v::d::r::p::a::l::x::o:O:c:w:z::f::")) != -1) {
901 switch (o) {
902 case 't':
903 snprintf(t.test_name, MAX_STR_LEN, "%s", optarg);
904 break;
905 case 's':
906 t.size = atoi(optarg);
907 break;
908 case 'i':
909 t.iteration_max = atoi(optarg);
910 break;
911 case 'S':
912 snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", optarg);
913 break;
914 case 'D':
915 snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", optarg);
916 break;
917 case 'm':
918 t.mask = atol(optarg);
919 break;
920 case 'v':
921 t.verbose = 1;
922 break;
923 case 'd':
924 t.debug = 1;
925 break;
926 case 'r':
927 t.raw_data_dump = 1;
928 break;
929 case 'p':
930 t.porcelain = 1;
931 break;
932 case 'a':
933 t.aggregate_output = 1;
934 break;
935 case 'l':
936 t.list_devices = 1;
937 break;
938 case 'x':
939 t.use_async = 1;
940 break;
941 case 'o':
942 t.async_timeout = atoi(optarg);
943 break;
944 case 'O':
945 t.poll_timeout.tv_sec = atoi(optarg);
946 break;
947 case 'c':
948 t.async_outstanding_operations = atoi(optarg);
949 break;
950 case 'w':
951 t.us_wait = atoi(optarg);
952 break;
953 case 'z':
954 t.file_output = 1;
955 break;
956 case 'f':
957 t.stop_all = 1;
958 break;
959 default:
960 usage();
961 return -EINVAL;
962 }
963 }
964
965 if (!strcmp(t.sysfs_prefix, ""))
966 snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", sysfs_prefix);
967
968 if (!strcmp(t.debugfs_prefix, ""))
969 snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", debugfs_prefix);
970
971 ret = find_loopback_devices(&t);
972 if (ret)
973 return ret;
974 ret = sanity_check(&t);
975 if (ret)
976 return ret;
977
978 if (t.list_devices) {
979 show_loopback_devices(&t);
980 return 0;
981 }
982
983 if (t.test_name[0] == '\0' || t.iteration_max == 0)
984 usage();
985
986 if (t.async_timeout == 0)
987 t.async_timeout = DEFAULT_ASYNC_TIMEOUT;
988
989 loopback_run(&t);
990
991 return 0;
992}
993