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