]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/greybus/tools/loopback_test.c
Merge branch 'for-linus-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad...
[linux.git] / drivers / staging / greybus / tools / loopback_test.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Loopback test application
4  *
5  * Copyright 2015 Google Inc.
6  * Copyright 2015 Linaro Ltd.
7  *
8  * Provided under the three clause BSD license found in the LICENSE file.
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
30 struct dict {
31         char *name;
32         int type;
33 };
34
35 static struct dict dict[] = {
36         {"ping", 2},
37         {"transfer", 3},
38         {"sink", 4},
39         {NULL,}         /* list termination */
40 };
41
42 struct 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
71 struct 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
78 struct 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
106 struct loopback_test t;
107
108 /* Helper macros to calculate the aggregate results for all devices */
109 static inline int device_enabled(struct loopback_test *t, int dev_idx);
110
111 #define GET_MAX(field)                                                  \
112 static 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)                                                  \
126 static 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)                                                  \
140 static 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
156 GET_MAX(throughput_max);
157 GET_MAX(request_max);
158 GET_MAX(latency_max);
159 GET_MAX(apbridge_unipro_latency_max);
160 GET_MAX(gbphy_firmware_latency_max);
161 GET_MIN(throughput_min);
162 GET_MIN(request_min);
163 GET_MIN(latency_min);
164 GET_MIN(apbridge_unipro_latency_min);
165 GET_MIN(gbphy_firmware_latency_min);
166 GET_AVG(throughput_avg);
167 GET_AVG(request_avg);
168 GET_AVG(latency_avg);
169 GET_AVG(apbridge_unipro_latency_avg);
170 GET_AVG(gbphy_firmware_latency_avg);
171
172 void abort(void)
173 {
174         _exit(1);
175 }
176
177 void 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
224 static 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
232 static 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
246 int 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
260 int 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
273 float 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
287 int 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
297 float 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
308 void 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
324 static 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         /*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
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
417 int 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
514 static 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          * file name will test_name_size_iteration_max.csv
527          * every time the same test with the same parameters is run we will then
528          * append to the same CSV with datestamp - representing each test
529          * dataset.
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
574 int 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
584 int 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         /* Don't include '.' and '..' */
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;
631 done:
632         for (i = 0; i < n; i++)
633                 free(namelist[i]);
634         free(namelist);
635 baddir:
636         return ret;
637 }
638
639 static 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
669 err:
670         for (i = 0; i < fds_idx; i++)
671                 close(t->fds[i].fd);
672
673         return -1;
674 }
675
676 static 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 }
684 static 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                 /* at least one device did not finish yet */
697                 if (iteration_count != t->iteration_max)
698                         return 0;
699         }
700
701         return 1;
702 }
703
704 static 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
715 static void handler(int sig) { /* do nothing */  }
716
717 static 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                                 /* Dummy read to clear the event */
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
772 static void prepare_devices(struct loopback_test *t)
773 {
774         int i;
775
776         /*
777          * Cancel any running tests on enabled devices. If
778          * stop_all option is given, stop test on all devices.
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                 /* Set operation size */
793                 write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
794
795                 /* Set iterations */
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
811 static int start(struct loopback_test *t)
812 {
813         int i;
814
815         /* the test starts by writing test_id to the type file. */
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
827 void 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
862 err:
863         printf("Error running test\n");
864         return;
865 }
866
867 static 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
891 int 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 }