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