17a338472SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2481eaec3SMichael S. Tsirkin /* 3481eaec3SMichael S. Tsirkin * Copyright (C) 2016 Red Hat, Inc. 4481eaec3SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com> 5481eaec3SMichael S. Tsirkin * 6481eaec3SMichael S. Tsirkin * Command line processing and common functions for ring benchmarking. 7481eaec3SMichael S. Tsirkin */ 8481eaec3SMichael S. Tsirkin #define _GNU_SOURCE 9481eaec3SMichael S. Tsirkin #include <getopt.h> 10481eaec3SMichael S. Tsirkin #include <pthread.h> 11481eaec3SMichael S. Tsirkin #include <assert.h> 12481eaec3SMichael S. Tsirkin #include <sched.h> 13481eaec3SMichael S. Tsirkin #include "main.h" 14481eaec3SMichael S. Tsirkin #include <sys/eventfd.h> 15481eaec3SMichael S. Tsirkin #include <stdlib.h> 16481eaec3SMichael S. Tsirkin #include <stdio.h> 17481eaec3SMichael S. Tsirkin #include <unistd.h> 18481eaec3SMichael S. Tsirkin #include <limits.h> 19481eaec3SMichael S. Tsirkin 20481eaec3SMichael S. Tsirkin int runcycles = 10000000; 21481eaec3SMichael S. Tsirkin int max_outstanding = INT_MAX; 22481eaec3SMichael S. Tsirkin int batch = 1; 23a4979505SMichael S. Tsirkin int param = 0; 24481eaec3SMichael S. Tsirkin 25481eaec3SMichael S. Tsirkin bool do_sleep = false; 26481eaec3SMichael S. Tsirkin bool do_relax = false; 27481eaec3SMichael S. Tsirkin bool do_exit = true; 28481eaec3SMichael S. Tsirkin 29481eaec3SMichael S. Tsirkin unsigned ring_size = 256; 30481eaec3SMichael S. Tsirkin 31481eaec3SMichael S. Tsirkin static int kickfd = -1; 32481eaec3SMichael S. Tsirkin static int callfd = -1; 33481eaec3SMichael S. Tsirkin 34481eaec3SMichael S. Tsirkin void notify(int fd) 35481eaec3SMichael S. Tsirkin { 36481eaec3SMichael S. Tsirkin unsigned long long v = 1; 37481eaec3SMichael S. Tsirkin int r; 38481eaec3SMichael S. Tsirkin 39481eaec3SMichael S. Tsirkin vmexit(); 40481eaec3SMichael S. Tsirkin r = write(fd, &v, sizeof v); 41481eaec3SMichael S. Tsirkin assert(r == sizeof v); 42481eaec3SMichael S. Tsirkin vmentry(); 43481eaec3SMichael S. Tsirkin } 44481eaec3SMichael S. Tsirkin 45481eaec3SMichael S. Tsirkin void wait_for_notify(int fd) 46481eaec3SMichael S. Tsirkin { 47481eaec3SMichael S. Tsirkin unsigned long long v = 1; 48481eaec3SMichael S. Tsirkin int r; 49481eaec3SMichael S. Tsirkin 50481eaec3SMichael S. Tsirkin vmexit(); 51481eaec3SMichael S. Tsirkin r = read(fd, &v, sizeof v); 52481eaec3SMichael S. Tsirkin assert(r == sizeof v); 53481eaec3SMichael S. Tsirkin vmentry(); 54481eaec3SMichael S. Tsirkin } 55481eaec3SMichael S. Tsirkin 56481eaec3SMichael S. Tsirkin void kick(void) 57481eaec3SMichael S. Tsirkin { 58481eaec3SMichael S. Tsirkin notify(kickfd); 59481eaec3SMichael S. Tsirkin } 60481eaec3SMichael S. Tsirkin 61481eaec3SMichael S. Tsirkin void wait_for_kick(void) 62481eaec3SMichael S. Tsirkin { 63481eaec3SMichael S. Tsirkin wait_for_notify(kickfd); 64481eaec3SMichael S. Tsirkin } 65481eaec3SMichael S. Tsirkin 66481eaec3SMichael S. Tsirkin void call(void) 67481eaec3SMichael S. Tsirkin { 68481eaec3SMichael S. Tsirkin notify(callfd); 69481eaec3SMichael S. Tsirkin } 70481eaec3SMichael S. Tsirkin 71481eaec3SMichael S. Tsirkin void wait_for_call(void) 72481eaec3SMichael S. Tsirkin { 73481eaec3SMichael S. Tsirkin wait_for_notify(callfd); 74481eaec3SMichael S. Tsirkin } 75481eaec3SMichael S. Tsirkin 76481eaec3SMichael S. Tsirkin void set_affinity(const char *arg) 77481eaec3SMichael S. Tsirkin { 78481eaec3SMichael S. Tsirkin cpu_set_t cpuset; 79481eaec3SMichael S. Tsirkin int ret; 80481eaec3SMichael S. Tsirkin pthread_t self; 81481eaec3SMichael S. Tsirkin long int cpu; 82481eaec3SMichael S. Tsirkin char *endptr; 83481eaec3SMichael S. Tsirkin 84481eaec3SMichael S. Tsirkin if (!arg) 85481eaec3SMichael S. Tsirkin return; 86481eaec3SMichael S. Tsirkin 87481eaec3SMichael S. Tsirkin cpu = strtol(arg, &endptr, 0); 88481eaec3SMichael S. Tsirkin assert(!*endptr); 89481eaec3SMichael S. Tsirkin 904f6d9bfcSDan Carpenter assert(cpu >= 0 && cpu < CPU_SETSIZE); 91481eaec3SMichael S. Tsirkin 92481eaec3SMichael S. Tsirkin self = pthread_self(); 93481eaec3SMichael S. Tsirkin CPU_ZERO(&cpuset); 94481eaec3SMichael S. Tsirkin CPU_SET(cpu, &cpuset); 95481eaec3SMichael S. Tsirkin 96481eaec3SMichael S. Tsirkin ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); 97481eaec3SMichael S. Tsirkin assert(!ret); 98481eaec3SMichael S. Tsirkin } 99481eaec3SMichael S. Tsirkin 100d3c3589bSPaolo Bonzini void poll_used(void) 101d3c3589bSPaolo Bonzini { 102d3c3589bSPaolo Bonzini while (used_empty()) 103d3c3589bSPaolo Bonzini busy_wait(); 104d3c3589bSPaolo Bonzini } 105d3c3589bSPaolo Bonzini 10644d65ea1SPaolo Bonzini static void __attribute__((__flatten__)) run_guest(void) 107481eaec3SMichael S. Tsirkin { 108481eaec3SMichael S. Tsirkin int completed_before; 109481eaec3SMichael S. Tsirkin int completed = 0; 110481eaec3SMichael S. Tsirkin int started = 0; 111481eaec3SMichael S. Tsirkin int bufs = runcycles; 112481eaec3SMichael S. Tsirkin int spurious = 0; 113481eaec3SMichael S. Tsirkin int r; 114481eaec3SMichael S. Tsirkin unsigned len; 115481eaec3SMichael S. Tsirkin void *buf; 116481eaec3SMichael S. Tsirkin int tokick = batch; 117481eaec3SMichael S. Tsirkin 118481eaec3SMichael S. Tsirkin for (;;) { 119481eaec3SMichael S. Tsirkin if (do_sleep) 120481eaec3SMichael S. Tsirkin disable_call(); 121481eaec3SMichael S. Tsirkin completed_before = completed; 122481eaec3SMichael S. Tsirkin do { 123481eaec3SMichael S. Tsirkin if (started < bufs && 124481eaec3SMichael S. Tsirkin started - completed < max_outstanding) { 125bb991288SMichael S. Tsirkin r = add_inbuf(0, "Buffer\n", "Hello, world!"); 126481eaec3SMichael S. Tsirkin if (__builtin_expect(r == 0, true)) { 127481eaec3SMichael S. Tsirkin ++started; 128481eaec3SMichael S. Tsirkin if (!--tokick) { 129481eaec3SMichael S. Tsirkin tokick = batch; 130481eaec3SMichael S. Tsirkin if (do_sleep) 131481eaec3SMichael S. Tsirkin kick_available(); 132481eaec3SMichael S. Tsirkin } 133481eaec3SMichael S. Tsirkin 134481eaec3SMichael S. Tsirkin } 135481eaec3SMichael S. Tsirkin } else 136481eaec3SMichael S. Tsirkin r = -1; 137481eaec3SMichael S. Tsirkin 138481eaec3SMichael S. Tsirkin /* Flush out completed bufs if any */ 139481eaec3SMichael S. Tsirkin if (get_buf(&len, &buf)) { 140481eaec3SMichael S. Tsirkin ++completed; 141481eaec3SMichael S. Tsirkin if (__builtin_expect(completed == bufs, false)) 142481eaec3SMichael S. Tsirkin return; 143481eaec3SMichael S. Tsirkin r = 0; 144481eaec3SMichael S. Tsirkin } 145481eaec3SMichael S. Tsirkin } while (r == 0); 146481eaec3SMichael S. Tsirkin if (completed == completed_before) 147481eaec3SMichael S. Tsirkin ++spurious; 148481eaec3SMichael S. Tsirkin assert(completed <= bufs); 149481eaec3SMichael S. Tsirkin assert(started <= bufs); 150481eaec3SMichael S. Tsirkin if (do_sleep) { 151948a8ac2SPaolo Bonzini if (used_empty() && enable_call()) 152481eaec3SMichael S. Tsirkin wait_for_call(); 153481eaec3SMichael S. Tsirkin } else { 154481eaec3SMichael S. Tsirkin poll_used(); 155481eaec3SMichael S. Tsirkin } 156481eaec3SMichael S. Tsirkin } 157481eaec3SMichael S. Tsirkin } 158481eaec3SMichael S. Tsirkin 159d3c3589bSPaolo Bonzini void poll_avail(void) 160d3c3589bSPaolo Bonzini { 161d3c3589bSPaolo Bonzini while (avail_empty()) 162d3c3589bSPaolo Bonzini busy_wait(); 163d3c3589bSPaolo Bonzini } 164d3c3589bSPaolo Bonzini 16544d65ea1SPaolo Bonzini static void __attribute__((__flatten__)) run_host(void) 166481eaec3SMichael S. Tsirkin { 167481eaec3SMichael S. Tsirkin int completed_before; 168481eaec3SMichael S. Tsirkin int completed = 0; 169481eaec3SMichael S. Tsirkin int spurious = 0; 170481eaec3SMichael S. Tsirkin int bufs = runcycles; 171481eaec3SMichael S. Tsirkin unsigned len; 172481eaec3SMichael S. Tsirkin void *buf; 173481eaec3SMichael S. Tsirkin 174481eaec3SMichael S. Tsirkin for (;;) { 175481eaec3SMichael S. Tsirkin if (do_sleep) { 176948a8ac2SPaolo Bonzini if (avail_empty() && enable_kick()) 177481eaec3SMichael S. Tsirkin wait_for_kick(); 178481eaec3SMichael S. Tsirkin } else { 179481eaec3SMichael S. Tsirkin poll_avail(); 180481eaec3SMichael S. Tsirkin } 181481eaec3SMichael S. Tsirkin if (do_sleep) 182481eaec3SMichael S. Tsirkin disable_kick(); 183481eaec3SMichael S. Tsirkin completed_before = completed; 184481eaec3SMichael S. Tsirkin while (__builtin_expect(use_buf(&len, &buf), true)) { 185481eaec3SMichael S. Tsirkin if (do_sleep) 186481eaec3SMichael S. Tsirkin call_used(); 187481eaec3SMichael S. Tsirkin ++completed; 188481eaec3SMichael S. Tsirkin if (__builtin_expect(completed == bufs, false)) 189481eaec3SMichael S. Tsirkin return; 190481eaec3SMichael S. Tsirkin } 191481eaec3SMichael S. Tsirkin if (completed == completed_before) 192481eaec3SMichael S. Tsirkin ++spurious; 193481eaec3SMichael S. Tsirkin assert(completed <= bufs); 194481eaec3SMichael S. Tsirkin if (completed == bufs) 195481eaec3SMichael S. Tsirkin break; 196481eaec3SMichael S. Tsirkin } 197481eaec3SMichael S. Tsirkin } 198481eaec3SMichael S. Tsirkin 199481eaec3SMichael S. Tsirkin void *start_guest(void *arg) 200481eaec3SMichael S. Tsirkin { 201481eaec3SMichael S. Tsirkin set_affinity(arg); 202481eaec3SMichael S. Tsirkin run_guest(); 203481eaec3SMichael S. Tsirkin pthread_exit(NULL); 204481eaec3SMichael S. Tsirkin } 205481eaec3SMichael S. Tsirkin 206481eaec3SMichael S. Tsirkin void *start_host(void *arg) 207481eaec3SMichael S. Tsirkin { 208481eaec3SMichael S. Tsirkin set_affinity(arg); 209481eaec3SMichael S. Tsirkin run_host(); 210481eaec3SMichael S. Tsirkin pthread_exit(NULL); 211481eaec3SMichael S. Tsirkin } 212481eaec3SMichael S. Tsirkin 213481eaec3SMichael S. Tsirkin static const char optstring[] = ""; 214481eaec3SMichael S. Tsirkin static const struct option longopts[] = { 215481eaec3SMichael S. Tsirkin { 216481eaec3SMichael S. Tsirkin .name = "help", 217481eaec3SMichael S. Tsirkin .has_arg = no_argument, 218481eaec3SMichael S. Tsirkin .val = 'h', 219481eaec3SMichael S. Tsirkin }, 220481eaec3SMichael S. Tsirkin { 221481eaec3SMichael S. Tsirkin .name = "host-affinity", 222481eaec3SMichael S. Tsirkin .has_arg = required_argument, 223481eaec3SMichael S. Tsirkin .val = 'H', 224481eaec3SMichael S. Tsirkin }, 225481eaec3SMichael S. Tsirkin { 226481eaec3SMichael S. Tsirkin .name = "guest-affinity", 227481eaec3SMichael S. Tsirkin .has_arg = required_argument, 228481eaec3SMichael S. Tsirkin .val = 'G', 229481eaec3SMichael S. Tsirkin }, 230481eaec3SMichael S. Tsirkin { 231481eaec3SMichael S. Tsirkin .name = "ring-size", 232481eaec3SMichael S. Tsirkin .has_arg = required_argument, 233481eaec3SMichael S. Tsirkin .val = 'R', 234481eaec3SMichael S. Tsirkin }, 235481eaec3SMichael S. Tsirkin { 236481eaec3SMichael S. Tsirkin .name = "run-cycles", 237481eaec3SMichael S. Tsirkin .has_arg = required_argument, 238481eaec3SMichael S. Tsirkin .val = 'C', 239481eaec3SMichael S. Tsirkin }, 240481eaec3SMichael S. Tsirkin { 241481eaec3SMichael S. Tsirkin .name = "outstanding", 242481eaec3SMichael S. Tsirkin .has_arg = required_argument, 243481eaec3SMichael S. Tsirkin .val = 'o', 244481eaec3SMichael S. Tsirkin }, 245481eaec3SMichael S. Tsirkin { 246481eaec3SMichael S. Tsirkin .name = "batch", 247481eaec3SMichael S. Tsirkin .has_arg = required_argument, 248481eaec3SMichael S. Tsirkin .val = 'b', 249481eaec3SMichael S. Tsirkin }, 250481eaec3SMichael S. Tsirkin { 251a4979505SMichael S. Tsirkin .name = "param", 252a4979505SMichael S. Tsirkin .has_arg = required_argument, 253a4979505SMichael S. Tsirkin .val = 'p', 254a4979505SMichael S. Tsirkin }, 255a4979505SMichael S. Tsirkin { 256481eaec3SMichael S. Tsirkin .name = "sleep", 257481eaec3SMichael S. Tsirkin .has_arg = no_argument, 258481eaec3SMichael S. Tsirkin .val = 's', 259481eaec3SMichael S. Tsirkin }, 260481eaec3SMichael S. Tsirkin { 261481eaec3SMichael S. Tsirkin .name = "relax", 262481eaec3SMichael S. Tsirkin .has_arg = no_argument, 263481eaec3SMichael S. Tsirkin .val = 'x', 264481eaec3SMichael S. Tsirkin }, 265481eaec3SMichael S. Tsirkin { 266481eaec3SMichael S. Tsirkin .name = "exit", 267481eaec3SMichael S. Tsirkin .has_arg = no_argument, 268481eaec3SMichael S. Tsirkin .val = 'e', 269481eaec3SMichael S. Tsirkin }, 270481eaec3SMichael S. Tsirkin { 271481eaec3SMichael S. Tsirkin } 272481eaec3SMichael S. Tsirkin }; 273481eaec3SMichael S. Tsirkin 274481eaec3SMichael S. Tsirkin static void help(void) 275481eaec3SMichael S. Tsirkin { 276481eaec3SMichael S. Tsirkin fprintf(stderr, "Usage: <test> [--help]" 277481eaec3SMichael S. Tsirkin " [--host-affinity H]" 278481eaec3SMichael S. Tsirkin " [--guest-affinity G]" 279*a8927f69SZhu Jun " [--ring-size R (default: %u)]" 280481eaec3SMichael S. Tsirkin " [--run-cycles C (default: %d)]" 281481eaec3SMichael S. Tsirkin " [--batch b]" 282481eaec3SMichael S. Tsirkin " [--outstanding o]" 283a4979505SMichael S. Tsirkin " [--param p]" 284481eaec3SMichael S. Tsirkin " [--sleep]" 285481eaec3SMichael S. Tsirkin " [--relax]" 286481eaec3SMichael S. Tsirkin " [--exit]" 287481eaec3SMichael S. Tsirkin "\n", 288481eaec3SMichael S. Tsirkin ring_size, 289481eaec3SMichael S. Tsirkin runcycles); 290481eaec3SMichael S. Tsirkin } 291481eaec3SMichael S. Tsirkin 292481eaec3SMichael S. Tsirkin int main(int argc, char **argv) 293481eaec3SMichael S. Tsirkin { 294481eaec3SMichael S. Tsirkin int ret; 295481eaec3SMichael S. Tsirkin pthread_t host, guest; 296481eaec3SMichael S. Tsirkin void *tret; 297481eaec3SMichael S. Tsirkin char *host_arg = NULL; 298481eaec3SMichael S. Tsirkin char *guest_arg = NULL; 299481eaec3SMichael S. Tsirkin char *endptr; 300481eaec3SMichael S. Tsirkin long int c; 301481eaec3SMichael S. Tsirkin 302481eaec3SMichael S. Tsirkin kickfd = eventfd(0, 0); 303481eaec3SMichael S. Tsirkin assert(kickfd >= 0); 304481eaec3SMichael S. Tsirkin callfd = eventfd(0, 0); 305481eaec3SMichael S. Tsirkin assert(callfd >= 0); 306481eaec3SMichael S. Tsirkin 307481eaec3SMichael S. Tsirkin for (;;) { 308481eaec3SMichael S. Tsirkin int o = getopt_long(argc, argv, optstring, longopts, NULL); 309481eaec3SMichael S. Tsirkin switch (o) { 310481eaec3SMichael S. Tsirkin case -1: 311481eaec3SMichael S. Tsirkin goto done; 312481eaec3SMichael S. Tsirkin case '?': 313481eaec3SMichael S. Tsirkin help(); 314481eaec3SMichael S. Tsirkin exit(2); 315481eaec3SMichael S. Tsirkin case 'H': 316481eaec3SMichael S. Tsirkin host_arg = optarg; 317481eaec3SMichael S. Tsirkin break; 318481eaec3SMichael S. Tsirkin case 'G': 319481eaec3SMichael S. Tsirkin guest_arg = optarg; 320481eaec3SMichael S. Tsirkin break; 321481eaec3SMichael S. Tsirkin case 'R': 322481eaec3SMichael S. Tsirkin ring_size = strtol(optarg, &endptr, 0); 323481eaec3SMichael S. Tsirkin assert(ring_size && !(ring_size & (ring_size - 1))); 324481eaec3SMichael S. Tsirkin assert(!*endptr); 325481eaec3SMichael S. Tsirkin break; 326481eaec3SMichael S. Tsirkin case 'C': 327481eaec3SMichael S. Tsirkin c = strtol(optarg, &endptr, 0); 328481eaec3SMichael S. Tsirkin assert(!*endptr); 329481eaec3SMichael S. Tsirkin assert(c > 0 && c < INT_MAX); 330481eaec3SMichael S. Tsirkin runcycles = c; 331481eaec3SMichael S. Tsirkin break; 332481eaec3SMichael S. Tsirkin case 'o': 333481eaec3SMichael S. Tsirkin c = strtol(optarg, &endptr, 0); 334481eaec3SMichael S. Tsirkin assert(!*endptr); 335481eaec3SMichael S. Tsirkin assert(c > 0 && c < INT_MAX); 336481eaec3SMichael S. Tsirkin max_outstanding = c; 337481eaec3SMichael S. Tsirkin break; 338a4979505SMichael S. Tsirkin case 'p': 339a4979505SMichael S. Tsirkin c = strtol(optarg, &endptr, 0); 340a4979505SMichael S. Tsirkin assert(!*endptr); 341a4979505SMichael S. Tsirkin assert(c > 0 && c < INT_MAX); 342a4979505SMichael S. Tsirkin param = c; 343a4979505SMichael S. Tsirkin break; 344481eaec3SMichael S. Tsirkin case 'b': 345481eaec3SMichael S. Tsirkin c = strtol(optarg, &endptr, 0); 346481eaec3SMichael S. Tsirkin assert(!*endptr); 347481eaec3SMichael S. Tsirkin assert(c > 0 && c < INT_MAX); 348481eaec3SMichael S. Tsirkin batch = c; 349481eaec3SMichael S. Tsirkin break; 350481eaec3SMichael S. Tsirkin case 's': 351481eaec3SMichael S. Tsirkin do_sleep = true; 352481eaec3SMichael S. Tsirkin break; 353481eaec3SMichael S. Tsirkin case 'x': 354481eaec3SMichael S. Tsirkin do_relax = true; 355481eaec3SMichael S. Tsirkin break; 356481eaec3SMichael S. Tsirkin case 'e': 357481eaec3SMichael S. Tsirkin do_exit = true; 358481eaec3SMichael S. Tsirkin break; 359481eaec3SMichael S. Tsirkin default: 360481eaec3SMichael S. Tsirkin help(); 361481eaec3SMichael S. Tsirkin exit(4); 362481eaec3SMichael S. Tsirkin break; 363481eaec3SMichael S. Tsirkin } 364481eaec3SMichael S. Tsirkin } 365481eaec3SMichael S. Tsirkin 366481eaec3SMichael S. Tsirkin /* does nothing here, used to make sure all smp APIs compile */ 367481eaec3SMichael S. Tsirkin smp_acquire(); 368481eaec3SMichael S. Tsirkin smp_release(); 369481eaec3SMichael S. Tsirkin smp_mb(); 370481eaec3SMichael S. Tsirkin done: 371481eaec3SMichael S. Tsirkin 372481eaec3SMichael S. Tsirkin if (batch > max_outstanding) 373481eaec3SMichael S. Tsirkin batch = max_outstanding; 374481eaec3SMichael S. Tsirkin 375481eaec3SMichael S. Tsirkin if (optind < argc) { 376481eaec3SMichael S. Tsirkin help(); 377481eaec3SMichael S. Tsirkin exit(4); 378481eaec3SMichael S. Tsirkin } 379481eaec3SMichael S. Tsirkin alloc_ring(); 380481eaec3SMichael S. Tsirkin 381481eaec3SMichael S. Tsirkin ret = pthread_create(&host, NULL, start_host, host_arg); 382481eaec3SMichael S. Tsirkin assert(!ret); 383481eaec3SMichael S. Tsirkin ret = pthread_create(&guest, NULL, start_guest, guest_arg); 384481eaec3SMichael S. Tsirkin assert(!ret); 385481eaec3SMichael S. Tsirkin 386481eaec3SMichael S. Tsirkin ret = pthread_join(guest, &tret); 387481eaec3SMichael S. Tsirkin assert(!ret); 388481eaec3SMichael S. Tsirkin ret = pthread_join(host, &tret); 389481eaec3SMichael S. Tsirkin assert(!ret); 390481eaec3SMichael S. Tsirkin return 0; 391481eaec3SMichael S. Tsirkin } 392