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
  99static void run_guest(void)
 100{
 101        int completed_before;
 102        int completed = 0;
 103        int started = 0;
 104        int bufs = runcycles;
 105        int spurious = 0;
 106        int r;
 107        unsigned len;
 108        void *buf;
 109        int tokick = batch;
 110
 111        for (;;) {
 112                if (do_sleep)
 113                        disable_call();
 114                completed_before = completed;
 115                do {
 116                        if (started < bufs &&
 117                            started - completed < max_outstanding) {
 118                                r = add_inbuf(0, NULL, "Hello, world!");
 119                                if (__builtin_expect(r == 0, true)) {
 120                                        ++started;
 121                                        if (!--tokick) {
 122                                                tokick = batch;
 123                                                if (do_sleep)
 124                                                        kick_available();
 125                                        }
 126
 127                                }
 128                        } else
 129                                r = -1;
 130
 131                        /* Flush out completed bufs if any */
 132                        if (get_buf(&len, &buf)) {
 133                                ++completed;
 134                                if (__builtin_expect(completed == bufs, false))
 135                                        return;
 136                                r = 0;
 137                        }
 138                } while (r == 0);
 139                if (completed == completed_before)
 140                        ++spurious;
 141                assert(completed <= bufs);
 142                assert(started <= bufs);
 143                if (do_sleep) {
 144                        if (enable_call())
 145                                wait_for_call();
 146                } else {
 147                        poll_used();
 148                }
 149        }
 150}
 151
 152static void run_host(void)
 153{
 154        int completed_before;
 155        int completed = 0;
 156        int spurious = 0;
 157        int bufs = runcycles;
 158        unsigned len;
 159        void *buf;
 160
 161        for (;;) {
 162                if (do_sleep) {
 163                        if (enable_kick())
 164                                wait_for_kick();
 165                } else {
 166                        poll_avail();
 167                }
 168                if (do_sleep)
 169                        disable_kick();
 170                completed_before = completed;
 171                while (__builtin_expect(use_buf(&len, &buf), true)) {
 172                        if (do_sleep)
 173                                call_used();
 174                        ++completed;
 175                        if (__builtin_expect(completed == bufs, false))
 176                                return;
 177                }
 178                if (completed == completed_before)
 179                        ++spurious;
 180                assert(completed <= bufs);
 181                if (completed == bufs)
 182                        break;
 183        }
 184}
 185
 186void *start_guest(void *arg)
 187{
 188        set_affinity(arg);
 189        run_guest();
 190        pthread_exit(NULL);
 191}
 192
 193void *start_host(void *arg)
 194{
 195        set_affinity(arg);
 196        run_host();
 197        pthread_exit(NULL);
 198}
 199
 200static const char optstring[] = "";
 201static const struct option longopts[] = {
 202        {
 203                .name = "help",
 204                .has_arg = no_argument,
 205                .val = 'h',
 206        },
 207        {
 208                .name = "host-affinity",
 209                .has_arg = required_argument,
 210                .val = 'H',
 211        },
 212        {
 213                .name = "guest-affinity",
 214                .has_arg = required_argument,
 215                .val = 'G',
 216        },
 217        {
 218                .name = "ring-size",
 219                .has_arg = required_argument,
 220                .val = 'R',
 221        },
 222        {
 223                .name = "run-cycles",
 224                .has_arg = required_argument,
 225                .val = 'C',
 226        },
 227        {
 228                .name = "outstanding",
 229                .has_arg = required_argument,
 230                .val = 'o',
 231        },
 232        {
 233                .name = "batch",
 234                .has_arg = required_argument,
 235                .val = 'b',
 236        },
 237        {
 238                .name = "sleep",
 239                .has_arg = no_argument,
 240                .val = 's',
 241        },
 242        {
 243                .name = "relax",
 244                .has_arg = no_argument,
 245                .val = 'x',
 246        },
 247        {
 248                .name = "exit",
 249                .has_arg = no_argument,
 250                .val = 'e',
 251        },
 252        {
 253        }
 254};
 255
 256static void help(void)
 257{
 258        fprintf(stderr, "Usage: <test> [--help]"
 259                " [--host-affinity H]"
 260                " [--guest-affinity G]"
 261                " [--ring-size R (default: %d)]"
 262                " [--run-cycles C (default: %d)]"
 263                " [--batch b]"
 264                " [--outstanding o]"
 265                " [--sleep]"
 266                " [--relax]"
 267                " [--exit]"
 268                "\n",
 269                ring_size,
 270                runcycles);
 271}
 272
 273int main(int argc, char **argv)
 274{
 275        int ret;
 276        pthread_t host, guest;
 277        void *tret;
 278        char *host_arg = NULL;
 279        char *guest_arg = NULL;
 280        char *endptr;
 281        long int c;
 282
 283        kickfd = eventfd(0, 0);
 284        assert(kickfd >= 0);
 285        callfd = eventfd(0, 0);
 286        assert(callfd >= 0);
 287
 288        for (;;) {
 289                int o = getopt_long(argc, argv, optstring, longopts, NULL);
 290                switch (o) {
 291                case -1:
 292                        goto done;
 293                case '?':
 294                        help();
 295                        exit(2);
 296                case 'H':
 297                        host_arg = optarg;
 298                        break;
 299                case 'G':
 300                        guest_arg = optarg;
 301                        break;
 302                case 'R':
 303                        ring_size = strtol(optarg, &endptr, 0);
 304                        assert(ring_size && !(ring_size & (ring_size - 1)));
 305                        assert(!*endptr);
 306                        break;
 307                case 'C':
 308                        c = strtol(optarg, &endptr, 0);
 309                        assert(!*endptr);
 310                        assert(c > 0 && c < INT_MAX);
 311                        runcycles = c;
 312                        break;
 313                case 'o':
 314                        c = strtol(optarg, &endptr, 0);
 315                        assert(!*endptr);
 316                        assert(c > 0 && c < INT_MAX);
 317                        max_outstanding = c;
 318                        break;
 319                case 'b':
 320                        c = strtol(optarg, &endptr, 0);
 321                        assert(!*endptr);
 322                        assert(c > 0 && c < INT_MAX);
 323                        batch = c;
 324                        break;
 325                case 's':
 326                        do_sleep = true;
 327                        break;
 328                case 'x':
 329                        do_relax = true;
 330                        break;
 331                case 'e':
 332                        do_exit = true;
 333                        break;
 334                default:
 335                        help();
 336                        exit(4);
 337                        break;
 338                }
 339        }
 340
 341        /* does nothing here, used to make sure all smp APIs compile */
 342        smp_acquire();
 343        smp_release();
 344        smp_mb();
 345done:
 346
 347        if (batch > max_outstanding)
 348                batch = max_outstanding;
 349
 350        if (optind < argc) {
 351                help();
 352                exit(4);
 353        }
 354        alloc_ring();
 355
 356        ret = pthread_create(&host, NULL, start_host, host_arg);
 357        assert(!ret);
 358        ret = pthread_create(&guest, NULL, start_guest, guest_arg);
 359        assert(!ret);
 360
 361        ret = pthread_join(guest, &tret);
 362        assert(!ret);
 363        ret = pthread_join(host, &tret);
 364        assert(!ret);
 365        return 0;
 366}
 367