linux/drivers/staging/greybus/tools/loopback_test.c
<<
>>
Prefs
   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#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,}         /* list termination */
  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/* Helper macros to calculate the aggregate results for all devices */
 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        /*calculate the aggregate results of all enabled devices */
 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         * file name will test_name_size_iteration_max.csv
 525         * every time the same test with the same parameters is run we will then
 526         * append to the same CSV with datestamp - representing each test
 527         * dataset.
 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        /* Don't include '.' and '..' */
 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                /* at least one device did not finish yet */
 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) { /* do nothing */  }
 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                                /* Dummy read to clear the event */
 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         * Cancel any running tests on enabled devices. If
 776         * stop_all option is given, stop test on all devices.
 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                /* Set operation size */
 791                write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
 792
 793                /* Set iterations */
 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        /* the test starts by writing test_id to the type file. */
 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