Merge tag 'powerpc-5.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux/fpc-iii.git] / tools / virtio / ringtest / main.c
blob5a18b2301a63cb71bad5221a1abb39cac9bc9599
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2016 Red Hat, Inc.
4 * Author: Michael S. Tsirkin <mst@redhat.com>
6 * Command line processing and common functions for ring benchmarking.
7 */
8 #define _GNU_SOURCE
9 #include <getopt.h>
10 #include <pthread.h>
11 #include <assert.h>
12 #include <sched.h>
13 #include "main.h"
14 #include <sys/eventfd.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <limits.h>
20 int runcycles = 10000000;
21 int max_outstanding = INT_MAX;
22 int batch = 1;
23 int param = 0;
25 bool do_sleep = false;
26 bool do_relax = false;
27 bool do_exit = true;
29 unsigned ring_size = 256;
31 static int kickfd = -1;
32 static int callfd = -1;
34 void notify(int fd)
36 unsigned long long v = 1;
37 int r;
39 vmexit();
40 r = write(fd, &v, sizeof v);
41 assert(r == sizeof v);
42 vmentry();
45 void wait_for_notify(int fd)
47 unsigned long long v = 1;
48 int r;
50 vmexit();
51 r = read(fd, &v, sizeof v);
52 assert(r == sizeof v);
53 vmentry();
56 void kick(void)
58 notify(kickfd);
61 void wait_for_kick(void)
63 wait_for_notify(kickfd);
66 void call(void)
68 notify(callfd);
71 void wait_for_call(void)
73 wait_for_notify(callfd);
76 void set_affinity(const char *arg)
78 cpu_set_t cpuset;
79 int ret;
80 pthread_t self;
81 long int cpu;
82 char *endptr;
84 if (!arg)
85 return;
87 cpu = strtol(arg, &endptr, 0);
88 assert(!*endptr);
90 assert(cpu >= 0 && cpu < CPU_SETSIZE);
92 self = pthread_self();
93 CPU_ZERO(&cpuset);
94 CPU_SET(cpu, &cpuset);
96 ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
97 assert(!ret);
100 void poll_used(void)
102 while (used_empty())
103 busy_wait();
106 static void __attribute__((__flatten__)) run_guest(void)
108 int completed_before;
109 int completed = 0;
110 int started = 0;
111 int bufs = runcycles;
112 int spurious = 0;
113 int r;
114 unsigned len;
115 void *buf;
116 int tokick = batch;
118 for (;;) {
119 if (do_sleep)
120 disable_call();
121 completed_before = completed;
122 do {
123 if (started < bufs &&
124 started - completed < max_outstanding) {
125 r = add_inbuf(0, "Buffer\n", "Hello, world!");
126 if (__builtin_expect(r == 0, true)) {
127 ++started;
128 if (!--tokick) {
129 tokick = batch;
130 if (do_sleep)
131 kick_available();
135 } else
136 r = -1;
138 /* Flush out completed bufs if any */
139 if (get_buf(&len, &buf)) {
140 ++completed;
141 if (__builtin_expect(completed == bufs, false))
142 return;
143 r = 0;
145 } while (r == 0);
146 if (completed == completed_before)
147 ++spurious;
148 assert(completed <= bufs);
149 assert(started <= bufs);
150 if (do_sleep) {
151 if (used_empty() && enable_call())
152 wait_for_call();
153 } else {
154 poll_used();
159 void poll_avail(void)
161 while (avail_empty())
162 busy_wait();
165 static void __attribute__((__flatten__)) run_host(void)
167 int completed_before;
168 int completed = 0;
169 int spurious = 0;
170 int bufs = runcycles;
171 unsigned len;
172 void *buf;
174 for (;;) {
175 if (do_sleep) {
176 if (avail_empty() && enable_kick())
177 wait_for_kick();
178 } else {
179 poll_avail();
181 if (do_sleep)
182 disable_kick();
183 completed_before = completed;
184 while (__builtin_expect(use_buf(&len, &buf), true)) {
185 if (do_sleep)
186 call_used();
187 ++completed;
188 if (__builtin_expect(completed == bufs, false))
189 return;
191 if (completed == completed_before)
192 ++spurious;
193 assert(completed <= bufs);
194 if (completed == bufs)
195 break;
199 void *start_guest(void *arg)
201 set_affinity(arg);
202 run_guest();
203 pthread_exit(NULL);
206 void *start_host(void *arg)
208 set_affinity(arg);
209 run_host();
210 pthread_exit(NULL);
213 static const char optstring[] = "";
214 static const struct option longopts[] = {
216 .name = "help",
217 .has_arg = no_argument,
218 .val = 'h',
221 .name = "host-affinity",
222 .has_arg = required_argument,
223 .val = 'H',
226 .name = "guest-affinity",
227 .has_arg = required_argument,
228 .val = 'G',
231 .name = "ring-size",
232 .has_arg = required_argument,
233 .val = 'R',
236 .name = "run-cycles",
237 .has_arg = required_argument,
238 .val = 'C',
241 .name = "outstanding",
242 .has_arg = required_argument,
243 .val = 'o',
246 .name = "batch",
247 .has_arg = required_argument,
248 .val = 'b',
251 .name = "param",
252 .has_arg = required_argument,
253 .val = 'p',
256 .name = "sleep",
257 .has_arg = no_argument,
258 .val = 's',
261 .name = "relax",
262 .has_arg = no_argument,
263 .val = 'x',
266 .name = "exit",
267 .has_arg = no_argument,
268 .val = 'e',
274 static void help(void)
276 fprintf(stderr, "Usage: <test> [--help]"
277 " [--host-affinity H]"
278 " [--guest-affinity G]"
279 " [--ring-size R (default: %d)]"
280 " [--run-cycles C (default: %d)]"
281 " [--batch b]"
282 " [--outstanding o]"
283 " [--param p]"
284 " [--sleep]"
285 " [--relax]"
286 " [--exit]"
287 "\n",
288 ring_size,
289 runcycles);
292 int main(int argc, char **argv)
294 int ret;
295 pthread_t host, guest;
296 void *tret;
297 char *host_arg = NULL;
298 char *guest_arg = NULL;
299 char *endptr;
300 long int c;
302 kickfd = eventfd(0, 0);
303 assert(kickfd >= 0);
304 callfd = eventfd(0, 0);
305 assert(callfd >= 0);
307 for (;;) {
308 int o = getopt_long(argc, argv, optstring, longopts, NULL);
309 switch (o) {
310 case -1:
311 goto done;
312 case '?':
313 help();
314 exit(2);
315 case 'H':
316 host_arg = optarg;
317 break;
318 case 'G':
319 guest_arg = optarg;
320 break;
321 case 'R':
322 ring_size = strtol(optarg, &endptr, 0);
323 assert(ring_size && !(ring_size & (ring_size - 1)));
324 assert(!*endptr);
325 break;
326 case 'C':
327 c = strtol(optarg, &endptr, 0);
328 assert(!*endptr);
329 assert(c > 0 && c < INT_MAX);
330 runcycles = c;
331 break;
332 case 'o':
333 c = strtol(optarg, &endptr, 0);
334 assert(!*endptr);
335 assert(c > 0 && c < INT_MAX);
336 max_outstanding = c;
337 break;
338 case 'p':
339 c = strtol(optarg, &endptr, 0);
340 assert(!*endptr);
341 assert(c > 0 && c < INT_MAX);
342 param = c;
343 break;
344 case 'b':
345 c = strtol(optarg, &endptr, 0);
346 assert(!*endptr);
347 assert(c > 0 && c < INT_MAX);
348 batch = c;
349 break;
350 case 's':
351 do_sleep = true;
352 break;
353 case 'x':
354 do_relax = true;
355 break;
356 case 'e':
357 do_exit = true;
358 break;
359 default:
360 help();
361 exit(4);
362 break;
366 /* does nothing here, used to make sure all smp APIs compile */
367 smp_acquire();
368 smp_release();
369 smp_mb();
370 done:
372 if (batch > max_outstanding)
373 batch = max_outstanding;
375 if (optind < argc) {
376 help();
377 exit(4);
379 alloc_ring();
381 ret = pthread_create(&host, NULL, start_host, host_arg);
382 assert(!ret);
383 ret = pthread_create(&guest, NULL, start_guest, guest_arg);
384 assert(!ret);
386 ret = pthread_join(guest, &tret);
387 assert(!ret);
388 ret = pthread_join(host, &tret);
389 assert(!ret);
390 return 0;