Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2016 Red Hat, Inc.
0004  * Author: Michael S. Tsirkin <mst@redhat.com>
0005  *
0006  * Command line processing and common functions for ring benchmarking.
0007  */
0008 #define _GNU_SOURCE
0009 #include <getopt.h>
0010 #include <pthread.h>
0011 #include <assert.h>
0012 #include <sched.h>
0013 #include "main.h"
0014 #include <sys/eventfd.h>
0015 #include <stdlib.h>
0016 #include <stdio.h>
0017 #include <unistd.h>
0018 #include <limits.h>
0019 
0020 int runcycles = 10000000;
0021 int max_outstanding = INT_MAX;
0022 int batch = 1;
0023 int param = 0;
0024 
0025 bool do_sleep = false;
0026 bool do_relax = false;
0027 bool do_exit = true;
0028 
0029 unsigned ring_size = 256;
0030 
0031 static int kickfd = -1;
0032 static int callfd = -1;
0033 
0034 void notify(int fd)
0035 {
0036     unsigned long long v = 1;
0037     int r;
0038 
0039     vmexit();
0040     r = write(fd, &v, sizeof v);
0041     assert(r == sizeof v);
0042     vmentry();
0043 }
0044 
0045 void wait_for_notify(int fd)
0046 {
0047     unsigned long long v = 1;
0048     int r;
0049 
0050     vmexit();
0051     r = read(fd, &v, sizeof v);
0052     assert(r == sizeof v);
0053     vmentry();
0054 }
0055 
0056 void kick(void)
0057 {
0058     notify(kickfd);
0059 }
0060 
0061 void wait_for_kick(void)
0062 {
0063     wait_for_notify(kickfd);
0064 }
0065 
0066 void call(void)
0067 {
0068     notify(callfd);
0069 }
0070 
0071 void wait_for_call(void)
0072 {
0073     wait_for_notify(callfd);
0074 }
0075 
0076 void set_affinity(const char *arg)
0077 {
0078     cpu_set_t cpuset;
0079     int ret;
0080     pthread_t self;
0081     long int cpu;
0082     char *endptr;
0083 
0084     if (!arg)
0085         return;
0086 
0087     cpu = strtol(arg, &endptr, 0);
0088     assert(!*endptr);
0089 
0090     assert(cpu >= 0 && cpu < CPU_SETSIZE);
0091 
0092     self = pthread_self();
0093     CPU_ZERO(&cpuset);
0094     CPU_SET(cpu, &cpuset);
0095 
0096     ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
0097     assert(!ret);
0098 }
0099 
0100 void poll_used(void)
0101 {
0102     while (used_empty())
0103         busy_wait();
0104 }
0105 
0106 static void __attribute__((__flatten__)) run_guest(void)
0107 {
0108     int completed_before;
0109     int completed = 0;
0110     int started = 0;
0111     int bufs = runcycles;
0112     int spurious = 0;
0113     int r;
0114     unsigned len;
0115     void *buf;
0116     int tokick = batch;
0117 
0118     for (;;) {
0119         if (do_sleep)
0120             disable_call();
0121         completed_before = completed;
0122         do {
0123             if (started < bufs &&
0124                 started - completed < max_outstanding) {
0125                 r = add_inbuf(0, "Buffer\n", "Hello, world!");
0126                 if (__builtin_expect(r == 0, true)) {
0127                     ++started;
0128                     if (!--tokick) {
0129                         tokick = batch;
0130                         if (do_sleep)
0131                             kick_available();
0132                     }
0133 
0134                 }
0135             } else
0136                 r = -1;
0137 
0138             /* Flush out completed bufs if any */
0139             if (get_buf(&len, &buf)) {
0140                 ++completed;
0141                 if (__builtin_expect(completed == bufs, false))
0142                     return;
0143                 r = 0;
0144             }
0145         } while (r == 0);
0146         if (completed == completed_before)
0147             ++spurious;
0148         assert(completed <= bufs);
0149         assert(started <= bufs);
0150         if (do_sleep) {
0151             if (used_empty() && enable_call())
0152                 wait_for_call();
0153         } else {
0154             poll_used();
0155         }
0156     }
0157 }
0158 
0159 void poll_avail(void)
0160 {
0161     while (avail_empty())
0162         busy_wait();
0163 }
0164 
0165 static void __attribute__((__flatten__)) run_host(void)
0166 {
0167     int completed_before;
0168     int completed = 0;
0169     int spurious = 0;
0170     int bufs = runcycles;
0171     unsigned len;
0172     void *buf;
0173 
0174     for (;;) {
0175         if (do_sleep) {
0176             if (avail_empty() && enable_kick())
0177                 wait_for_kick();
0178         } else {
0179             poll_avail();
0180         }
0181         if (do_sleep)
0182             disable_kick();
0183         completed_before = completed;
0184         while (__builtin_expect(use_buf(&len, &buf), true)) {
0185             if (do_sleep)
0186                 call_used();
0187             ++completed;
0188             if (__builtin_expect(completed == bufs, false))
0189                 return;
0190         }
0191         if (completed == completed_before)
0192             ++spurious;
0193         assert(completed <= bufs);
0194         if (completed == bufs)
0195             break;
0196     }
0197 }
0198 
0199 void *start_guest(void *arg)
0200 {
0201     set_affinity(arg);
0202     run_guest();
0203     pthread_exit(NULL);
0204 }
0205 
0206 void *start_host(void *arg)
0207 {
0208     set_affinity(arg);
0209     run_host();
0210     pthread_exit(NULL);
0211 }
0212 
0213 static const char optstring[] = "";
0214 static const struct option longopts[] = {
0215     {
0216         .name = "help",
0217         .has_arg = no_argument,
0218         .val = 'h',
0219     },
0220     {
0221         .name = "host-affinity",
0222         .has_arg = required_argument,
0223         .val = 'H',
0224     },
0225     {
0226         .name = "guest-affinity",
0227         .has_arg = required_argument,
0228         .val = 'G',
0229     },
0230     {
0231         .name = "ring-size",
0232         .has_arg = required_argument,
0233         .val = 'R',
0234     },
0235     {
0236         .name = "run-cycles",
0237         .has_arg = required_argument,
0238         .val = 'C',
0239     },
0240     {
0241         .name = "outstanding",
0242         .has_arg = required_argument,
0243         .val = 'o',
0244     },
0245     {
0246         .name = "batch",
0247         .has_arg = required_argument,
0248         .val = 'b',
0249     },
0250     {
0251         .name = "param",
0252         .has_arg = required_argument,
0253         .val = 'p',
0254     },
0255     {
0256         .name = "sleep",
0257         .has_arg = no_argument,
0258         .val = 's',
0259     },
0260     {
0261         .name = "relax",
0262         .has_arg = no_argument,
0263         .val = 'x',
0264     },
0265     {
0266         .name = "exit",
0267         .has_arg = no_argument,
0268         .val = 'e',
0269     },
0270     {
0271     }
0272 };
0273 
0274 static void help(void)
0275 {
0276     fprintf(stderr, "Usage: <test> [--help]"
0277         " [--host-affinity H]"
0278         " [--guest-affinity G]"
0279         " [--ring-size R (default: %d)]"
0280         " [--run-cycles C (default: %d)]"
0281         " [--batch b]"
0282         " [--outstanding o]"
0283         " [--param p]"
0284         " [--sleep]"
0285         " [--relax]"
0286         " [--exit]"
0287         "\n",
0288         ring_size,
0289         runcycles);
0290 }
0291 
0292 int main(int argc, char **argv)
0293 {
0294     int ret;
0295     pthread_t host, guest;
0296     void *tret;
0297     char *host_arg = NULL;
0298     char *guest_arg = NULL;
0299     char *endptr;
0300     long int c;
0301 
0302     kickfd = eventfd(0, 0);
0303     assert(kickfd >= 0);
0304     callfd = eventfd(0, 0);
0305     assert(callfd >= 0);
0306 
0307     for (;;) {
0308         int o = getopt_long(argc, argv, optstring, longopts, NULL);
0309         switch (o) {
0310         case -1:
0311             goto done;
0312         case '?':
0313             help();
0314             exit(2);
0315         case 'H':
0316             host_arg = optarg;
0317             break;
0318         case 'G':
0319             guest_arg = optarg;
0320             break;
0321         case 'R':
0322             ring_size = strtol(optarg, &endptr, 0);
0323             assert(ring_size && !(ring_size & (ring_size - 1)));
0324             assert(!*endptr);
0325             break;
0326         case 'C':
0327             c = strtol(optarg, &endptr, 0);
0328             assert(!*endptr);
0329             assert(c > 0 && c < INT_MAX);
0330             runcycles = c;
0331             break;
0332         case 'o':
0333             c = strtol(optarg, &endptr, 0);
0334             assert(!*endptr);
0335             assert(c > 0 && c < INT_MAX);
0336             max_outstanding = c;
0337             break;
0338         case 'p':
0339             c = strtol(optarg, &endptr, 0);
0340             assert(!*endptr);
0341             assert(c > 0 && c < INT_MAX);
0342             param = c;
0343             break;
0344         case 'b':
0345             c = strtol(optarg, &endptr, 0);
0346             assert(!*endptr);
0347             assert(c > 0 && c < INT_MAX);
0348             batch = c;
0349             break;
0350         case 's':
0351             do_sleep = true;
0352             break;
0353         case 'x':
0354             do_relax = true;
0355             break;
0356         case 'e':
0357             do_exit = true;
0358             break;
0359         default:
0360             help();
0361             exit(4);
0362             break;
0363         }
0364     }
0365 
0366     /* does nothing here, used to make sure all smp APIs compile */
0367     smp_acquire();
0368     smp_release();
0369     smp_mb();
0370 done:
0371 
0372     if (batch > max_outstanding)
0373         batch = max_outstanding;
0374 
0375     if (optind < argc) {
0376         help();
0377         exit(4);
0378     }
0379     alloc_ring();
0380 
0381     ret = pthread_create(&host, NULL, start_host, host_arg);
0382     assert(!ret);
0383     ret = pthread_create(&guest, NULL, start_guest, guest_arg);
0384     assert(!ret);
0385 
0386     ret = pthread_join(guest, &tret);
0387     assert(!ret);
0388     ret = pthread_join(host, &tret);
0389     assert(!ret);
0390     return 0;
0391 }