linux/drivers/staging/greybus/tools/loopback_test.c
<<
>>
Prefs
   1/*
   2 * Loopback test application
   3 *
   4 * Copyright 2015 Google Inc.
   5 * Copyright 2015 Linaro Ltd.
   6 *
   7 * Provided under the three clause BSD license found in the LICENSE file.
   8 */
   9#include <errno.h>
  10#include <fcntl.h>
  11#include <stdio.h>
  12#include <string.h>
  13#include <stdlib.h>
  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,}         /* list termination */
  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/* Helper macros to calculate the aggregate results for all devices */
 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        /*calculate the aggregate results of all enabled devices */
 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        * file name will test_name_size_iteration_max.csv
 533        * every time the same test with the same parameters is run we will then
 534        * append to the same CSV with datestamp - representing each test
 535        * dataset.
 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        /* Don't include '.' and '..' */
 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                /* at least one device did not finish yet */
 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) { /* do nothing */  }
 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                                /* Dummy read to clear the event */
 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        /* Cancel any running tests on enabled devices. If
 784         * stop_all option is given, stop test on all devices.
 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                /* Set operation size */
 799                write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
 800
 801                /* Set iterations */
 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        /* the test starts by writing test_id to the type file. */
 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