18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Red Hat, Inc. 48c2ecf20Sopenharmony_ci * Author: Michael S. Tsirkin <mst@redhat.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Command line processing and common functions for ring benchmarking. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#define _GNU_SOURCE 98c2ecf20Sopenharmony_ci#include <getopt.h> 108c2ecf20Sopenharmony_ci#include <pthread.h> 118c2ecf20Sopenharmony_ci#include <assert.h> 128c2ecf20Sopenharmony_ci#include <sched.h> 138c2ecf20Sopenharmony_ci#include "main.h" 148c2ecf20Sopenharmony_ci#include <sys/eventfd.h> 158c2ecf20Sopenharmony_ci#include <stdlib.h> 168c2ecf20Sopenharmony_ci#include <stdio.h> 178c2ecf20Sopenharmony_ci#include <unistd.h> 188c2ecf20Sopenharmony_ci#include <limits.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciint runcycles = 10000000; 218c2ecf20Sopenharmony_ciint max_outstanding = INT_MAX; 228c2ecf20Sopenharmony_ciint batch = 1; 238c2ecf20Sopenharmony_ciint param = 0; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cibool do_sleep = false; 268c2ecf20Sopenharmony_cibool do_relax = false; 278c2ecf20Sopenharmony_cibool do_exit = true; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciunsigned ring_size = 256; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int kickfd = -1; 328c2ecf20Sopenharmony_cistatic int callfd = -1; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_civoid notify(int fd) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci unsigned long long v = 1; 378c2ecf20Sopenharmony_ci int r; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci vmexit(); 408c2ecf20Sopenharmony_ci r = write(fd, &v, sizeof v); 418c2ecf20Sopenharmony_ci assert(r == sizeof v); 428c2ecf20Sopenharmony_ci vmentry(); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_civoid wait_for_notify(int fd) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci unsigned long long v = 1; 488c2ecf20Sopenharmony_ci int r; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci vmexit(); 518c2ecf20Sopenharmony_ci r = read(fd, &v, sizeof v); 528c2ecf20Sopenharmony_ci assert(r == sizeof v); 538c2ecf20Sopenharmony_ci vmentry(); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_civoid kick(void) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci notify(kickfd); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_civoid wait_for_kick(void) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci wait_for_notify(kickfd); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid call(void) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci notify(callfd); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid wait_for_call(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci wait_for_notify(callfd); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid set_affinity(const char *arg) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci cpu_set_t cpuset; 798c2ecf20Sopenharmony_ci int ret; 808c2ecf20Sopenharmony_ci pthread_t self; 818c2ecf20Sopenharmony_ci long int cpu; 828c2ecf20Sopenharmony_ci char *endptr; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (!arg) 858c2ecf20Sopenharmony_ci return; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci cpu = strtol(arg, &endptr, 0); 888c2ecf20Sopenharmony_ci assert(!*endptr); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci assert(cpu >= 0 && cpu < CPU_SETSIZE); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci self = pthread_self(); 938c2ecf20Sopenharmony_ci CPU_ZERO(&cpuset); 948c2ecf20Sopenharmony_ci CPU_SET(cpu, &cpuset); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); 978c2ecf20Sopenharmony_ci assert(!ret); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_civoid poll_used(void) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci while (used_empty()) 1038c2ecf20Sopenharmony_ci busy_wait(); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void __attribute__((__flatten__)) run_guest(void) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int completed_before; 1098c2ecf20Sopenharmony_ci int completed = 0; 1108c2ecf20Sopenharmony_ci int started = 0; 1118c2ecf20Sopenharmony_ci int bufs = runcycles; 1128c2ecf20Sopenharmony_ci int spurious = 0; 1138c2ecf20Sopenharmony_ci int r; 1148c2ecf20Sopenharmony_ci unsigned len; 1158c2ecf20Sopenharmony_ci void *buf; 1168c2ecf20Sopenharmony_ci int tokick = batch; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci for (;;) { 1198c2ecf20Sopenharmony_ci if (do_sleep) 1208c2ecf20Sopenharmony_ci disable_call(); 1218c2ecf20Sopenharmony_ci completed_before = completed; 1228c2ecf20Sopenharmony_ci do { 1238c2ecf20Sopenharmony_ci if (started < bufs && 1248c2ecf20Sopenharmony_ci started - completed < max_outstanding) { 1258c2ecf20Sopenharmony_ci r = add_inbuf(0, "Buffer\n", "Hello, world!"); 1268c2ecf20Sopenharmony_ci if (__builtin_expect(r == 0, true)) { 1278c2ecf20Sopenharmony_ci ++started; 1288c2ecf20Sopenharmony_ci if (!--tokick) { 1298c2ecf20Sopenharmony_ci tokick = batch; 1308c2ecf20Sopenharmony_ci if (do_sleep) 1318c2ecf20Sopenharmony_ci kick_available(); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } else 1368c2ecf20Sopenharmony_ci r = -1; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Flush out completed bufs if any */ 1398c2ecf20Sopenharmony_ci if (get_buf(&len, &buf)) { 1408c2ecf20Sopenharmony_ci ++completed; 1418c2ecf20Sopenharmony_ci if (__builtin_expect(completed == bufs, false)) 1428c2ecf20Sopenharmony_ci return; 1438c2ecf20Sopenharmony_ci r = 0; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } while (r == 0); 1468c2ecf20Sopenharmony_ci if (completed == completed_before) 1478c2ecf20Sopenharmony_ci ++spurious; 1488c2ecf20Sopenharmony_ci assert(completed <= bufs); 1498c2ecf20Sopenharmony_ci assert(started <= bufs); 1508c2ecf20Sopenharmony_ci if (do_sleep) { 1518c2ecf20Sopenharmony_ci if (used_empty() && enable_call()) 1528c2ecf20Sopenharmony_ci wait_for_call(); 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci poll_used(); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_civoid poll_avail(void) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci while (avail_empty()) 1628c2ecf20Sopenharmony_ci busy_wait(); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void __attribute__((__flatten__)) run_host(void) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int completed_before; 1688c2ecf20Sopenharmony_ci int completed = 0; 1698c2ecf20Sopenharmony_ci int spurious = 0; 1708c2ecf20Sopenharmony_ci int bufs = runcycles; 1718c2ecf20Sopenharmony_ci unsigned len; 1728c2ecf20Sopenharmony_ci void *buf; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci for (;;) { 1758c2ecf20Sopenharmony_ci if (do_sleep) { 1768c2ecf20Sopenharmony_ci if (avail_empty() && enable_kick()) 1778c2ecf20Sopenharmony_ci wait_for_kick(); 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci poll_avail(); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci if (do_sleep) 1828c2ecf20Sopenharmony_ci disable_kick(); 1838c2ecf20Sopenharmony_ci completed_before = completed; 1848c2ecf20Sopenharmony_ci while (__builtin_expect(use_buf(&len, &buf), true)) { 1858c2ecf20Sopenharmony_ci if (do_sleep) 1868c2ecf20Sopenharmony_ci call_used(); 1878c2ecf20Sopenharmony_ci ++completed; 1888c2ecf20Sopenharmony_ci if (__builtin_expect(completed == bufs, false)) 1898c2ecf20Sopenharmony_ci return; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci if (completed == completed_before) 1928c2ecf20Sopenharmony_ci ++spurious; 1938c2ecf20Sopenharmony_ci assert(completed <= bufs); 1948c2ecf20Sopenharmony_ci if (completed == bufs) 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_civoid *start_guest(void *arg) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci set_affinity(arg); 2028c2ecf20Sopenharmony_ci run_guest(); 2038c2ecf20Sopenharmony_ci pthread_exit(NULL); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_civoid *start_host(void *arg) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci set_affinity(arg); 2098c2ecf20Sopenharmony_ci run_host(); 2108c2ecf20Sopenharmony_ci pthread_exit(NULL); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic const char optstring[] = ""; 2148c2ecf20Sopenharmony_cistatic const struct option longopts[] = { 2158c2ecf20Sopenharmony_ci { 2168c2ecf20Sopenharmony_ci .name = "help", 2178c2ecf20Sopenharmony_ci .has_arg = no_argument, 2188c2ecf20Sopenharmony_ci .val = 'h', 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci { 2218c2ecf20Sopenharmony_ci .name = "host-affinity", 2228c2ecf20Sopenharmony_ci .has_arg = required_argument, 2238c2ecf20Sopenharmony_ci .val = 'H', 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci { 2268c2ecf20Sopenharmony_ci .name = "guest-affinity", 2278c2ecf20Sopenharmony_ci .has_arg = required_argument, 2288c2ecf20Sopenharmony_ci .val = 'G', 2298c2ecf20Sopenharmony_ci }, 2308c2ecf20Sopenharmony_ci { 2318c2ecf20Sopenharmony_ci .name = "ring-size", 2328c2ecf20Sopenharmony_ci .has_arg = required_argument, 2338c2ecf20Sopenharmony_ci .val = 'R', 2348c2ecf20Sopenharmony_ci }, 2358c2ecf20Sopenharmony_ci { 2368c2ecf20Sopenharmony_ci .name = "run-cycles", 2378c2ecf20Sopenharmony_ci .has_arg = required_argument, 2388c2ecf20Sopenharmony_ci .val = 'C', 2398c2ecf20Sopenharmony_ci }, 2408c2ecf20Sopenharmony_ci { 2418c2ecf20Sopenharmony_ci .name = "outstanding", 2428c2ecf20Sopenharmony_ci .has_arg = required_argument, 2438c2ecf20Sopenharmony_ci .val = 'o', 2448c2ecf20Sopenharmony_ci }, 2458c2ecf20Sopenharmony_ci { 2468c2ecf20Sopenharmony_ci .name = "batch", 2478c2ecf20Sopenharmony_ci .has_arg = required_argument, 2488c2ecf20Sopenharmony_ci .val = 'b', 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci { 2518c2ecf20Sopenharmony_ci .name = "param", 2528c2ecf20Sopenharmony_ci .has_arg = required_argument, 2538c2ecf20Sopenharmony_ci .val = 'p', 2548c2ecf20Sopenharmony_ci }, 2558c2ecf20Sopenharmony_ci { 2568c2ecf20Sopenharmony_ci .name = "sleep", 2578c2ecf20Sopenharmony_ci .has_arg = no_argument, 2588c2ecf20Sopenharmony_ci .val = 's', 2598c2ecf20Sopenharmony_ci }, 2608c2ecf20Sopenharmony_ci { 2618c2ecf20Sopenharmony_ci .name = "relax", 2628c2ecf20Sopenharmony_ci .has_arg = no_argument, 2638c2ecf20Sopenharmony_ci .val = 'x', 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci { 2668c2ecf20Sopenharmony_ci .name = "exit", 2678c2ecf20Sopenharmony_ci .has_arg = no_argument, 2688c2ecf20Sopenharmony_ci .val = 'e', 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci { 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic void help(void) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: <test> [--help]" 2778c2ecf20Sopenharmony_ci " [--host-affinity H]" 2788c2ecf20Sopenharmony_ci " [--guest-affinity G]" 2798c2ecf20Sopenharmony_ci " [--ring-size R (default: %d)]" 2808c2ecf20Sopenharmony_ci " [--run-cycles C (default: %d)]" 2818c2ecf20Sopenharmony_ci " [--batch b]" 2828c2ecf20Sopenharmony_ci " [--outstanding o]" 2838c2ecf20Sopenharmony_ci " [--param p]" 2848c2ecf20Sopenharmony_ci " [--sleep]" 2858c2ecf20Sopenharmony_ci " [--relax]" 2868c2ecf20Sopenharmony_ci " [--exit]" 2878c2ecf20Sopenharmony_ci "\n", 2888c2ecf20Sopenharmony_ci ring_size, 2898c2ecf20Sopenharmony_ci runcycles); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciint main(int argc, char **argv) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci int ret; 2958c2ecf20Sopenharmony_ci pthread_t host, guest; 2968c2ecf20Sopenharmony_ci void *tret; 2978c2ecf20Sopenharmony_ci char *host_arg = NULL; 2988c2ecf20Sopenharmony_ci char *guest_arg = NULL; 2998c2ecf20Sopenharmony_ci char *endptr; 3008c2ecf20Sopenharmony_ci long int c; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci kickfd = eventfd(0, 0); 3038c2ecf20Sopenharmony_ci assert(kickfd >= 0); 3048c2ecf20Sopenharmony_ci callfd = eventfd(0, 0); 3058c2ecf20Sopenharmony_ci assert(callfd >= 0); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci for (;;) { 3088c2ecf20Sopenharmony_ci int o = getopt_long(argc, argv, optstring, longopts, NULL); 3098c2ecf20Sopenharmony_ci switch (o) { 3108c2ecf20Sopenharmony_ci case -1: 3118c2ecf20Sopenharmony_ci goto done; 3128c2ecf20Sopenharmony_ci case '?': 3138c2ecf20Sopenharmony_ci help(); 3148c2ecf20Sopenharmony_ci exit(2); 3158c2ecf20Sopenharmony_ci case 'H': 3168c2ecf20Sopenharmony_ci host_arg = optarg; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case 'G': 3198c2ecf20Sopenharmony_ci guest_arg = optarg; 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci case 'R': 3228c2ecf20Sopenharmony_ci ring_size = strtol(optarg, &endptr, 0); 3238c2ecf20Sopenharmony_ci assert(ring_size && !(ring_size & (ring_size - 1))); 3248c2ecf20Sopenharmony_ci assert(!*endptr); 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case 'C': 3278c2ecf20Sopenharmony_ci c = strtol(optarg, &endptr, 0); 3288c2ecf20Sopenharmony_ci assert(!*endptr); 3298c2ecf20Sopenharmony_ci assert(c > 0 && c < INT_MAX); 3308c2ecf20Sopenharmony_ci runcycles = c; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case 'o': 3338c2ecf20Sopenharmony_ci c = strtol(optarg, &endptr, 0); 3348c2ecf20Sopenharmony_ci assert(!*endptr); 3358c2ecf20Sopenharmony_ci assert(c > 0 && c < INT_MAX); 3368c2ecf20Sopenharmony_ci max_outstanding = c; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci case 'p': 3398c2ecf20Sopenharmony_ci c = strtol(optarg, &endptr, 0); 3408c2ecf20Sopenharmony_ci assert(!*endptr); 3418c2ecf20Sopenharmony_ci assert(c > 0 && c < INT_MAX); 3428c2ecf20Sopenharmony_ci param = c; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci case 'b': 3458c2ecf20Sopenharmony_ci c = strtol(optarg, &endptr, 0); 3468c2ecf20Sopenharmony_ci assert(!*endptr); 3478c2ecf20Sopenharmony_ci assert(c > 0 && c < INT_MAX); 3488c2ecf20Sopenharmony_ci batch = c; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case 's': 3518c2ecf20Sopenharmony_ci do_sleep = true; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci case 'x': 3548c2ecf20Sopenharmony_ci do_relax = true; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci case 'e': 3578c2ecf20Sopenharmony_ci do_exit = true; 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci default: 3608c2ecf20Sopenharmony_ci help(); 3618c2ecf20Sopenharmony_ci exit(4); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* does nothing here, used to make sure all smp APIs compile */ 3678c2ecf20Sopenharmony_ci smp_acquire(); 3688c2ecf20Sopenharmony_ci smp_release(); 3698c2ecf20Sopenharmony_ci smp_mb(); 3708c2ecf20Sopenharmony_cidone: 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (batch > max_outstanding) 3738c2ecf20Sopenharmony_ci batch = max_outstanding; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (optind < argc) { 3768c2ecf20Sopenharmony_ci help(); 3778c2ecf20Sopenharmony_ci exit(4); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci alloc_ring(); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ret = pthread_create(&host, NULL, start_host, host_arg); 3828c2ecf20Sopenharmony_ci assert(!ret); 3838c2ecf20Sopenharmony_ci ret = pthread_create(&guest, NULL, start_guest, guest_arg); 3848c2ecf20Sopenharmony_ci assert(!ret); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = pthread_join(guest, &tret); 3878c2ecf20Sopenharmony_ci assert(!ret); 3888c2ecf20Sopenharmony_ci ret = pthread_join(host, &tret); 3898c2ecf20Sopenharmony_ci assert(!ret); 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 392