linux/tools/virtio/ringtest/main.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2016 Red Hat, Inc.
   4 * Author: Michael S. Tsirkin <mst@redhat.com>
   5 *
   6 * Command line processing and common functions for ring benchmarking.
   7 */
   8#define _GNU_SOURCE
   9#include <getopt.h>
  10#include <pthread.h>
  11#include <assert.h>
  12#include <sched.h>
  13#include "main.h"
  14#include <sys/eventfd.h>
  15#include <stdlib.h>
  16#include <stdio.h>
  17#include <unistd.h>
  18#include <limits.h>
  19
  20int runcycles = 10000000;
  21int max_outstanding = INT_MAX;
  22int batch = 1;
  23int param = 0;
  24
  25bool do_sleep = false;
  26bool do_relax = false;
  27bool do_exit = true;
  28
  29unsigned ring_size = 256;
  30
  31static int kickfd = -1;
  32static int callfd = -1;
  33
  34void notify(int fd)
  35{
  36        unsigned long long v = 1;
  37        int r;
  38
  39        vmexit();
  40        r = write(fd, &v, sizeof v);
  41        assert(r == sizeof v);
  42        vmentry();
  43}
  44
  45void wait_for_notify(int fd)
  46{
  47        unsigned long long v = 1;
  48        int r;
  49
  50        vmexit();
  51        r = read(fd, &v, sizeof v);
  52        assert(r == sizeof v);
  53        vmentry();
  54}
  55
  56void kick(void)
  57{
  58        notify(kickfd);
  59}
  60
  61void wait_for_kick(void)
  62{
  63        wait_for_notify(kickfd);
  64}
  65
  66void call(void)
  67{
  68        notify(callfd);
  69}
  70
  71void wait_for_call(void)
  72{
  73        wait_for_notify(callfd);
  74}
  75
  76void set_affinity(const char *arg)
  77{
  78        cpu_set_t cpuset;
  79        int ret;
  80        pthread_t self;
  81        long int cpu;
  82        char *endptr;
  83
  84        if (!arg)
  85                return;
  86
  87        cpu = strtol(arg, &endptr, 0);
  88        assert(!*endptr);
  89
  90        assert(cpu >= 0 && cpu < CPU_SETSIZE);
  91
  92        self = pthread_self();
  93        CPU_ZERO(&cpuset);
  94        CPU_SET(cpu, &cpuset);
  95
  96        ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
  97        assert(!ret);
  98}
  99
 100void poll_used(void)
 101{
 102        while (used_empty())
 103                busy_wait();
 104}
 105
 106static void __attribute__((__flatten__)) run_guest(void)
 107{
 108        int completed_before;
 109        int completed = 0;
 110        int started = 0;
 111        int bufs = runcycles;
 112        int spurious = 0;
 113        int r;
 114        unsigned len;
 115        void *buf;
 116        int tokick = batch;
 117
 118        for (;;) {
 119                if (do_sleep)
 120                        disable_call();
 121                completed_before = completed;
 122                do {
 123                        if (started < bufs &&
 124                            started - completed < max_outstanding) {
 125                                r = add_inbuf(0, "Buffer\n", "Hello, world!");
 126                                if (__builtin_expect(r == 0, true)) {
 127                                        ++started;
 128                                        if (!--tokick) {
 129                                                tokick = batch;
 130                                                if (do_sleep)
 131                                                        kick_available();
 132                                        }
 133
 134                                }
 135                        } else
 136                                r = -1;
 137
 138                        /* Flush out completed bufs if any */
 139                        if (get_buf(&len, &buf)) {
 140                                ++completed;
 141                                if (__builtin_expect(completed == bufs, false))
 142                                        return;
 143                                r = 0;
 144                        }
 145                } while (r == 0);
 146                if (completed == completed_before)
 147                        ++spurious;
 148                assert(completed <= bufs);
 149                assert(started <= bufs);
 150                if (do_sleep) {
 151                        if (used_empty() && enable_call())
 152                                wait_for_call();
 153                } else {
 154                        poll_used();
 155                }
 156        }
 157}
 158
 159void poll_avail(void)
 160{
 161        while (avail_empty())
 162                busy_wait();
 163}
 164
 165static void __attribute__((__flatten__)) run_host(void)
 166{
 167        int completed_before;
 168        int completed = 0;
 169        int spurious = 0;
 170        int bufs = runcycles;
 171        unsigned len;
 172        void *buf;
 173
 174        for (;;) {
 175                if (do_sleep) {
 176                        if (avail_empty() && enable_kick())
 177                                wait_for_kick();
 178                } else {
 179                        poll_avail();
 180                }
 181                if (do_sleep)
 182                        disable_kick();
 183                completed_before = completed;
 184                while (__builtin_expect(use_buf(&len, &buf), true)) {
 185                        if (do_sleep)
 186                                call_used();
 187                        ++completed;
 188                        if (__builtin_expect(completed == bufs, false))
 189                                return;
 190                }
 191                if (completed == completed_before)
 192                        ++spurious;
 193                assert(completed <= bufs);
 194                if (completed == bufs)
 195                        break;
 196        }
 197}
 198
 199void *start_guest(void *arg)
 200{
 201        set_affinity(arg);
 202        run_guest();
 203        pthread_exit(NULL);
 204}
 205
 206void *start_host(void *arg)
 207{
 208        set_affinity(arg);
 209        run_host();
 210        pthread_exit(NULL);
 211}
 212
 213static const char optstring[] = "";
 214static const struct option longopts[] = {
 215        {
 216                .name = "help",
 217                .has_arg = no_argument,
 218                .val = 'h',
 219        },
 220        {
 221                .name = "host-affinity",
 222                .has_arg = required_argument,
 223                .val = 'H',
 224        },
 225        {
 226                .name = "guest-affinity",
 227                .has_arg = required_argument,
 228                .val = 'G',
 229        },
 230        {
 231                .name = "ring-size",
 232                .has_arg = required_argument,
 233                .val = 'R',
 234        },
 235        {
 236                .name = "run-cycles",
 237                .has_arg = required_argument,
 238                .val = 'C',
 239        },
 240        {
 241                .name = "outstanding",
 242                .has_arg = required_argument,
 243                .val = 'o',
 244        },
 245        {
 246                .name = "batch",
 247                .has_arg = required_argument,
 248                .val = 'b',
 249        },
 250        {
 251                .name = "param",
 252                .has_arg = required_argument,
 253                .val = 'p',
 254        },
 255        {
 256                .name = "sleep",
 257                .has_arg = no_argument,
 258                .val = 's',
 259        },
 260        {
 261                .name = "relax",
 262                .has_arg = no_argument,
 263                .val = 'x',
 264        },
 265        {
 266                .name = "exit",
 267                .has_arg = no_argument,
 268                .val = 'e',
 269        },
 270        {
 271        }
 272};
 273
 274static void help(void)
 275{
 276        fprintf(stderr, "Usage: <test> [--help]"
 277                " [--host-affinity H]"
 278                " [--guest-affinity G]"
 279                " [--ring-size R (default: %d)]"
 280                " [--run-cycles C (default: %d)]"
 281                " [--batch b]"
 282                " [--outstanding o]"
 283                " [--param p]"
 284                " [--sleep]"
 285                " [--relax]"
 286                " [--exit]"
 287                "\n",
 288                ring_size,
 289                runcycles);
 290}
 291
 292int main(int argc, char **argv)
 293{
 294        int ret;
 295        pthread_t host, guest;
 296        void *tret;
 297        char *host_arg = NULL;
 298        char *guest_arg = NULL;
 299        char *endptr;
 300        long int c;
 301
 302        kickfd = eventfd(0, 0);
 303        assert(kickfd >= 0);
 304        callfd = eventfd(0, 0);
 305        assert(callfd >= 0);
 306
 307        for (;;) {
 308                int o = getopt_long(argc, argv, optstring, longopts, NULL);
 309                switch (o) {
 310                case -1:
 311                        goto done;
 312                case '?':
 313                        help();
 314                        exit(2);
 315                case 'H':
 316                        host_arg = optarg;
 317                        break;
 318                case 'G':
 319                        guest_arg = optarg;
 320                        break;
 321                case 'R':
 322                        ring_size = strtol(optarg, &endptr, 0);
 323                        assert(ring_size && !(ring_size & (ring_size - 1)));
 324                        assert(!*endptr);
 325                        break;
 326                case 'C':
 327                        c = strtol(optarg, &endptr, 0);
 328                        assert(!*endptr);
 329                        assert(c > 0 && c < INT_MAX);
 330                        runcycles = c;
 331                        break;
 332                case 'o':
 333                        c = strtol(optarg, &endptr, 0);
 334                        assert(!*endptr);
 335                        assert(c > 0 && c < INT_MAX);
 336                        max_outstanding = c;
 337                        break;
 338                case 'p':
 339                        c = strtol(optarg, &endptr, 0);
 340                        assert(!*endptr);
 341                        assert(c > 0 && c < INT_MAX);
 342                        param = c;
 343                        break;
 344                case 'b':
 345                        c = strtol(optarg, &endptr, 0);
 346                        assert(!*endptr);
 347                        assert(c > 0 && c < INT_MAX);
 348                        batch = c;
 349                        break;
 350                case 's':
 351                        do_sleep = true;
 352                        break;
 353                case 'x':
 354                        do_relax = true;
 355                        break;
 356                case 'e':
 357                        do_exit = true;
 358                        break;
 359                default:
 360                        help();
 361                        exit(4);
 362                        break;
 363                }
 364        }
 365
 366        /* does nothing here, used to make sure all smp APIs compile */
 367        smp_acquire();
 368        smp_release();
 369        smp_mb();
 370done:
 371
 372        if (batch > max_outstanding)
 373                batch = max_outstanding;
 374
 375        if (optind < argc) {
 376                help();
 377                exit(4);
 378        }
 379        alloc_ring();
 380
 381        ret = pthread_create(&host, NULL, start_host, host_arg);
 382        assert(!ret);
 383        ret = pthread_create(&guest, NULL, start_guest, guest_arg);
 384        assert(!ret);
 385
 386        ret = pthread_join(guest, &tret);
 387        assert(!ret);
 388        ret = pthread_join(host, &tret);
 389        assert(!ret);
 390        return 0;
 391}
 392