root/tools/virtio/ringtest/main.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. notify
  2. wait_for_notify
  3. kick
  4. wait_for_kick
  5. call
  6. wait_for_call
  7. set_affinity
  8. poll_used
  9. run_guest
  10. poll_avail
  11. run_host
  12. start_guest
  13. start_host
  14. help
  15. main

   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 
  20 int runcycles = 10000000;
  21 int max_outstanding = INT_MAX;
  22 int batch = 1;
  23 int param = 0;
  24 
  25 bool do_sleep = false;
  26 bool do_relax = false;
  27 bool do_exit = true;
  28 
  29 unsigned ring_size = 256;
  30 
  31 static int kickfd = -1;
  32 static int callfd = -1;
  33 
  34 void 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 
  45 void 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 
  56 void kick(void)
  57 {
  58         notify(kickfd);
  59 }
  60 
  61 void wait_for_kick(void)
  62 {
  63         wait_for_notify(kickfd);
  64 }
  65 
  66 void call(void)
  67 {
  68         notify(callfd);
  69 }
  70 
  71 void wait_for_call(void)
  72 {
  73         wait_for_notify(callfd);
  74 }
  75 
  76 void 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 
 100 void poll_used(void)
 101 {
 102         while (used_empty())
 103                 busy_wait();
 104 }
 105 
 106 static 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 
 159 void poll_avail(void)
 160 {
 161         while (avail_empty())
 162                 busy_wait();
 163 }
 164 
 165 static 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 
 199 void *start_guest(void *arg)
 200 {
 201         set_affinity(arg);
 202         run_guest();
 203         pthread_exit(NULL);
 204 }
 205 
 206 void *start_host(void *arg)
 207 {
 208         set_affinity(arg);
 209         run_host();
 210         pthread_exit(NULL);
 211 }
 212 
 213 static const char optstring[] = "";
 214 static 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 
 274 static 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 
 292 int 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();
 370 done:
 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 }

/* [<][>][^][v][top][bottom][index][help] */