123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- /*
- * Copyright (C) 2016 Red Hat, Inc.
- * Author: Michael S. Tsirkin <mst@redhat.com>
- * This work is licensed under the terms of the GNU GPL, version 2.
- *
- * Command line processing and common functions for ring benchmarking.
- */
- #define _GNU_SOURCE
- #include <getopt.h>
- #include <pthread.h>
- #include <assert.h>
- #include <sched.h>
- #include "main.h"
- #include <sys/eventfd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <limits.h>
- int runcycles = 10000000;
- int max_outstanding = INT_MAX;
- int batch = 1;
- int param = 0;
- bool do_sleep = false;
- bool do_relax = false;
- bool do_exit = true;
- unsigned ring_size = 256;
- static int kickfd = -1;
- static int callfd = -1;
- void notify(int fd)
- {
- unsigned long long v = 1;
- int r;
- vmexit();
- r = write(fd, &v, sizeof v);
- assert(r == sizeof v);
- vmentry();
- }
- void wait_for_notify(int fd)
- {
- unsigned long long v = 1;
- int r;
- vmexit();
- r = read(fd, &v, sizeof v);
- assert(r == sizeof v);
- vmentry();
- }
- void kick(void)
- {
- notify(kickfd);
- }
- void wait_for_kick(void)
- {
- wait_for_notify(kickfd);
- }
- void call(void)
- {
- notify(callfd);
- }
- void wait_for_call(void)
- {
- wait_for_notify(callfd);
- }
- void set_affinity(const char *arg)
- {
- cpu_set_t cpuset;
- int ret;
- pthread_t self;
- long int cpu;
- char *endptr;
- if (!arg)
- return;
- cpu = strtol(arg, &endptr, 0);
- assert(!*endptr);
- assert(cpu >= 0 && cpu < CPU_SETSIZE);
- self = pthread_self();
- CPU_ZERO(&cpuset);
- CPU_SET(cpu, &cpuset);
- ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
- assert(!ret);
- }
- void poll_used(void)
- {
- while (used_empty())
- busy_wait();
- }
- static void __attribute__((__flatten__)) run_guest(void)
- {
- int completed_before;
- int completed = 0;
- int started = 0;
- int bufs = runcycles;
- int spurious = 0;
- int r;
- unsigned len;
- void *buf;
- int tokick = batch;
- for (;;) {
- if (do_sleep)
- disable_call();
- completed_before = completed;
- do {
- if (started < bufs &&
- started - completed < max_outstanding) {
- r = add_inbuf(0, "Buffer\n", "Hello, world!");
- if (__builtin_expect(r == 0, true)) {
- ++started;
- if (!--tokick) {
- tokick = batch;
- if (do_sleep)
- kick_available();
- }
- }
- } else
- r = -1;
- /* Flush out completed bufs if any */
- if (get_buf(&len, &buf)) {
- ++completed;
- if (__builtin_expect(completed == bufs, false))
- return;
- r = 0;
- }
- } while (r == 0);
- if (completed == completed_before)
- ++spurious;
- assert(completed <= bufs);
- assert(started <= bufs);
- if (do_sleep) {
- if (used_empty() && enable_call())
- wait_for_call();
- } else {
- poll_used();
- }
- }
- }
- void poll_avail(void)
- {
- while (avail_empty())
- busy_wait();
- }
- static void __attribute__((__flatten__)) run_host(void)
- {
- int completed_before;
- int completed = 0;
- int spurious = 0;
- int bufs = runcycles;
- unsigned len;
- void *buf;
- for (;;) {
- if (do_sleep) {
- if (avail_empty() && enable_kick())
- wait_for_kick();
- } else {
- poll_avail();
- }
- if (do_sleep)
- disable_kick();
- completed_before = completed;
- while (__builtin_expect(use_buf(&len, &buf), true)) {
- if (do_sleep)
- call_used();
- ++completed;
- if (__builtin_expect(completed == bufs, false))
- return;
- }
- if (completed == completed_before)
- ++spurious;
- assert(completed <= bufs);
- if (completed == bufs)
- break;
- }
- }
- void *start_guest(void *arg)
- {
- set_affinity(arg);
- run_guest();
- pthread_exit(NULL);
- }
- void *start_host(void *arg)
- {
- set_affinity(arg);
- run_host();
- pthread_exit(NULL);
- }
- static const char optstring[] = "";
- static const struct option longopts[] = {
- {
- .name = "help",
- .has_arg = no_argument,
- .val = 'h',
- },
- {
- .name = "host-affinity",
- .has_arg = required_argument,
- .val = 'H',
- },
- {
- .name = "guest-affinity",
- .has_arg = required_argument,
- .val = 'G',
- },
- {
- .name = "ring-size",
- .has_arg = required_argument,
- .val = 'R',
- },
- {
- .name = "run-cycles",
- .has_arg = required_argument,
- .val = 'C',
- },
- {
- .name = "outstanding",
- .has_arg = required_argument,
- .val = 'o',
- },
- {
- .name = "batch",
- .has_arg = required_argument,
- .val = 'b',
- },
- {
- .name = "param",
- .has_arg = required_argument,
- .val = 'p',
- },
- {
- .name = "sleep",
- .has_arg = no_argument,
- .val = 's',
- },
- {
- .name = "relax",
- .has_arg = no_argument,
- .val = 'x',
- },
- {
- .name = "exit",
- .has_arg = no_argument,
- .val = 'e',
- },
- {
- }
- };
- static void help(void)
- {
- fprintf(stderr, "Usage: <test> [--help]"
- " [--host-affinity H]"
- " [--guest-affinity G]"
- " [--ring-size R (default: %d)]"
- " [--run-cycles C (default: %d)]"
- " [--batch b]"
- " [--outstanding o]"
- " [--param p]"
- " [--sleep]"
- " [--relax]"
- " [--exit]"
- "\n",
- ring_size,
- runcycles);
- }
- int main(int argc, char **argv)
- {
- int ret;
- pthread_t host, guest;
- void *tret;
- char *host_arg = NULL;
- char *guest_arg = NULL;
- char *endptr;
- long int c;
- kickfd = eventfd(0, 0);
- assert(kickfd >= 0);
- callfd = eventfd(0, 0);
- assert(callfd >= 0);
- for (;;) {
- int o = getopt_long(argc, argv, optstring, longopts, NULL);
- switch (o) {
- case -1:
- goto done;
- case '?':
- help();
- exit(2);
- case 'H':
- host_arg = optarg;
- break;
- case 'G':
- guest_arg = optarg;
- break;
- case 'R':
- ring_size = strtol(optarg, &endptr, 0);
- assert(ring_size && !(ring_size & (ring_size - 1)));
- assert(!*endptr);
- break;
- case 'C':
- c = strtol(optarg, &endptr, 0);
- assert(!*endptr);
- assert(c > 0 && c < INT_MAX);
- runcycles = c;
- break;
- case 'o':
- c = strtol(optarg, &endptr, 0);
- assert(!*endptr);
- assert(c > 0 && c < INT_MAX);
- max_outstanding = c;
- break;
- case 'p':
- c = strtol(optarg, &endptr, 0);
- assert(!*endptr);
- assert(c > 0 && c < INT_MAX);
- param = c;
- break;
- case 'b':
- c = strtol(optarg, &endptr, 0);
- assert(!*endptr);
- assert(c > 0 && c < INT_MAX);
- batch = c;
- break;
- case 's':
- do_sleep = true;
- break;
- case 'x':
- do_relax = true;
- break;
- case 'e':
- do_exit = true;
- break;
- default:
- help();
- exit(4);
- break;
- }
- }
- /* does nothing here, used to make sure all smp APIs compile */
- smp_acquire();
- smp_release();
- smp_mb();
- done:
- if (batch > max_outstanding)
- batch = max_outstanding;
- if (optind < argc) {
- help();
- exit(4);
- }
- alloc_ring();
- ret = pthread_create(&host, NULL, start_host, host_arg);
- assert(!ret);
- ret = pthread_create(&guest, NULL, start_guest, guest_arg);
- assert(!ret);
- ret = pthread_join(guest, &tret);
- assert(!ret);
- ret = pthread_join(host, &tret);
- assert(!ret);
- return 0;
- }
|