0001
0002
0003
0004
0005
0006
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
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
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 }