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