1*7a338472SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2481eaec3SMichael S. Tsirkin /*
3481eaec3SMichael S. Tsirkin * Copyright (C) 2016 Red Hat, Inc.
4481eaec3SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com>
5481eaec3SMichael S. Tsirkin *
6481eaec3SMichael S. Tsirkin * Command line processing and common functions for ring benchmarking.
7481eaec3SMichael S. Tsirkin */
8481eaec3SMichael S. Tsirkin #define _GNU_SOURCE
9481eaec3SMichael S. Tsirkin #include <getopt.h>
10481eaec3SMichael S. Tsirkin #include <pthread.h>
11481eaec3SMichael S. Tsirkin #include <assert.h>
12481eaec3SMichael S. Tsirkin #include <sched.h>
13481eaec3SMichael S. Tsirkin #include "main.h"
14481eaec3SMichael S. Tsirkin #include <sys/eventfd.h>
15481eaec3SMichael S. Tsirkin #include <stdlib.h>
16481eaec3SMichael S. Tsirkin #include <stdio.h>
17481eaec3SMichael S. Tsirkin #include <unistd.h>
18481eaec3SMichael S. Tsirkin #include <limits.h>
19481eaec3SMichael S. Tsirkin
20481eaec3SMichael S. Tsirkin int runcycles = 10000000;
21481eaec3SMichael S. Tsirkin int max_outstanding = INT_MAX;
22481eaec3SMichael S. Tsirkin int batch = 1;
23a4979505SMichael S. Tsirkin int param = 0;
24481eaec3SMichael S. Tsirkin
25481eaec3SMichael S. Tsirkin bool do_sleep = false;
26481eaec3SMichael S. Tsirkin bool do_relax = false;
27481eaec3SMichael S. Tsirkin bool do_exit = true;
28481eaec3SMichael S. Tsirkin
29481eaec3SMichael S. Tsirkin unsigned ring_size = 256;
30481eaec3SMichael S. Tsirkin
31481eaec3SMichael S. Tsirkin static int kickfd = -1;
32481eaec3SMichael S. Tsirkin static int callfd = -1;
33481eaec3SMichael S. Tsirkin
notify(int fd)34481eaec3SMichael S. Tsirkin void notify(int fd)
35481eaec3SMichael S. Tsirkin {
36481eaec3SMichael S. Tsirkin unsigned long long v = 1;
37481eaec3SMichael S. Tsirkin int r;
38481eaec3SMichael S. Tsirkin
39481eaec3SMichael S. Tsirkin vmexit();
40481eaec3SMichael S. Tsirkin r = write(fd, &v, sizeof v);
41481eaec3SMichael S. Tsirkin assert(r == sizeof v);
42481eaec3SMichael S. Tsirkin vmentry();
43481eaec3SMichael S. Tsirkin }
44481eaec3SMichael S. Tsirkin
wait_for_notify(int fd)45481eaec3SMichael S. Tsirkin void wait_for_notify(int fd)
46481eaec3SMichael S. Tsirkin {
47481eaec3SMichael S. Tsirkin unsigned long long v = 1;
48481eaec3SMichael S. Tsirkin int r;
49481eaec3SMichael S. Tsirkin
50481eaec3SMichael S. Tsirkin vmexit();
51481eaec3SMichael S. Tsirkin r = read(fd, &v, sizeof v);
52481eaec3SMichael S. Tsirkin assert(r == sizeof v);
53481eaec3SMichael S. Tsirkin vmentry();
54481eaec3SMichael S. Tsirkin }
55481eaec3SMichael S. Tsirkin
kick(void)56481eaec3SMichael S. Tsirkin void kick(void)
57481eaec3SMichael S. Tsirkin {
58481eaec3SMichael S. Tsirkin notify(kickfd);
59481eaec3SMichael S. Tsirkin }
60481eaec3SMichael S. Tsirkin
wait_for_kick(void)61481eaec3SMichael S. Tsirkin void wait_for_kick(void)
62481eaec3SMichael S. Tsirkin {
63481eaec3SMichael S. Tsirkin wait_for_notify(kickfd);
64481eaec3SMichael S. Tsirkin }
65481eaec3SMichael S. Tsirkin
call(void)66481eaec3SMichael S. Tsirkin void call(void)
67481eaec3SMichael S. Tsirkin {
68481eaec3SMichael S. Tsirkin notify(callfd);
69481eaec3SMichael S. Tsirkin }
70481eaec3SMichael S. Tsirkin
wait_for_call(void)71481eaec3SMichael S. Tsirkin void wait_for_call(void)
72481eaec3SMichael S. Tsirkin {
73481eaec3SMichael S. Tsirkin wait_for_notify(callfd);
74481eaec3SMichael S. Tsirkin }
75481eaec3SMichael S. Tsirkin
set_affinity(const char * arg)76481eaec3SMichael S. Tsirkin void set_affinity(const char *arg)
77481eaec3SMichael S. Tsirkin {
78481eaec3SMichael S. Tsirkin cpu_set_t cpuset;
79481eaec3SMichael S. Tsirkin int ret;
80481eaec3SMichael S. Tsirkin pthread_t self;
81481eaec3SMichael S. Tsirkin long int cpu;
82481eaec3SMichael S. Tsirkin char *endptr;
83481eaec3SMichael S. Tsirkin
84481eaec3SMichael S. Tsirkin if (!arg)
85481eaec3SMichael S. Tsirkin return;
86481eaec3SMichael S. Tsirkin
87481eaec3SMichael S. Tsirkin cpu = strtol(arg, &endptr, 0);
88481eaec3SMichael S. Tsirkin assert(!*endptr);
89481eaec3SMichael S. Tsirkin
904f6d9bfcSDan Carpenter assert(cpu >= 0 && cpu < CPU_SETSIZE);
91481eaec3SMichael S. Tsirkin
92481eaec3SMichael S. Tsirkin self = pthread_self();
93481eaec3SMichael S. Tsirkin CPU_ZERO(&cpuset);
94481eaec3SMichael S. Tsirkin CPU_SET(cpu, &cpuset);
95481eaec3SMichael S. Tsirkin
96481eaec3SMichael S. Tsirkin ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
97481eaec3SMichael S. Tsirkin assert(!ret);
98481eaec3SMichael S. Tsirkin }
99481eaec3SMichael S. Tsirkin
poll_used(void)100d3c3589bSPaolo Bonzini void poll_used(void)
101d3c3589bSPaolo Bonzini {
102d3c3589bSPaolo Bonzini while (used_empty())
103d3c3589bSPaolo Bonzini busy_wait();
104d3c3589bSPaolo Bonzini }
105d3c3589bSPaolo Bonzini
run_guest(void)10644d65ea1SPaolo Bonzini static void __attribute__((__flatten__)) run_guest(void)
107481eaec3SMichael S. Tsirkin {
108481eaec3SMichael S. Tsirkin int completed_before;
109481eaec3SMichael S. Tsirkin int completed = 0;
110481eaec3SMichael S. Tsirkin int started = 0;
111481eaec3SMichael S. Tsirkin int bufs = runcycles;
112481eaec3SMichael S. Tsirkin int spurious = 0;
113481eaec3SMichael S. Tsirkin int r;
114481eaec3SMichael S. Tsirkin unsigned len;
115481eaec3SMichael S. Tsirkin void *buf;
116481eaec3SMichael S. Tsirkin int tokick = batch;
117481eaec3SMichael S. Tsirkin
118481eaec3SMichael S. Tsirkin for (;;) {
119481eaec3SMichael S. Tsirkin if (do_sleep)
120481eaec3SMichael S. Tsirkin disable_call();
121481eaec3SMichael S. Tsirkin completed_before = completed;
122481eaec3SMichael S. Tsirkin do {
123481eaec3SMichael S. Tsirkin if (started < bufs &&
124481eaec3SMichael S. Tsirkin started - completed < max_outstanding) {
125bb991288SMichael S. Tsirkin r = add_inbuf(0, "Buffer\n", "Hello, world!");
126481eaec3SMichael S. Tsirkin if (__builtin_expect(r == 0, true)) {
127481eaec3SMichael S. Tsirkin ++started;
128481eaec3SMichael S. Tsirkin if (!--tokick) {
129481eaec3SMichael S. Tsirkin tokick = batch;
130481eaec3SMichael S. Tsirkin if (do_sleep)
131481eaec3SMichael S. Tsirkin kick_available();
132481eaec3SMichael S. Tsirkin }
133481eaec3SMichael S. Tsirkin
134481eaec3SMichael S. Tsirkin }
135481eaec3SMichael S. Tsirkin } else
136481eaec3SMichael S. Tsirkin r = -1;
137481eaec3SMichael S. Tsirkin
138481eaec3SMichael S. Tsirkin /* Flush out completed bufs if any */
139481eaec3SMichael S. Tsirkin if (get_buf(&len, &buf)) {
140481eaec3SMichael S. Tsirkin ++completed;
141481eaec3SMichael S. Tsirkin if (__builtin_expect(completed == bufs, false))
142481eaec3SMichael S. Tsirkin return;
143481eaec3SMichael S. Tsirkin r = 0;
144481eaec3SMichael S. Tsirkin }
145481eaec3SMichael S. Tsirkin } while (r == 0);
146481eaec3SMichael S. Tsirkin if (completed == completed_before)
147481eaec3SMichael S. Tsirkin ++spurious;
148481eaec3SMichael S. Tsirkin assert(completed <= bufs);
149481eaec3SMichael S. Tsirkin assert(started <= bufs);
150481eaec3SMichael S. Tsirkin if (do_sleep) {
151948a8ac2SPaolo Bonzini if (used_empty() && enable_call())
152481eaec3SMichael S. Tsirkin wait_for_call();
153481eaec3SMichael S. Tsirkin } else {
154481eaec3SMichael S. Tsirkin poll_used();
155481eaec3SMichael S. Tsirkin }
156481eaec3SMichael S. Tsirkin }
157481eaec3SMichael S. Tsirkin }
158481eaec3SMichael S. Tsirkin
poll_avail(void)159d3c3589bSPaolo Bonzini void poll_avail(void)
160d3c3589bSPaolo Bonzini {
161d3c3589bSPaolo Bonzini while (avail_empty())
162d3c3589bSPaolo Bonzini busy_wait();
163d3c3589bSPaolo Bonzini }
164d3c3589bSPaolo Bonzini
run_host(void)16544d65ea1SPaolo Bonzini static void __attribute__((__flatten__)) run_host(void)
166481eaec3SMichael S. Tsirkin {
167481eaec3SMichael S. Tsirkin int completed_before;
168481eaec3SMichael S. Tsirkin int completed = 0;
169481eaec3SMichael S. Tsirkin int spurious = 0;
170481eaec3SMichael S. Tsirkin int bufs = runcycles;
171481eaec3SMichael S. Tsirkin unsigned len;
172481eaec3SMichael S. Tsirkin void *buf;
173481eaec3SMichael S. Tsirkin
174481eaec3SMichael S. Tsirkin for (;;) {
175481eaec3SMichael S. Tsirkin if (do_sleep) {
176948a8ac2SPaolo Bonzini if (avail_empty() && enable_kick())
177481eaec3SMichael S. Tsirkin wait_for_kick();
178481eaec3SMichael S. Tsirkin } else {
179481eaec3SMichael S. Tsirkin poll_avail();
180481eaec3SMichael S. Tsirkin }
181481eaec3SMichael S. Tsirkin if (do_sleep)
182481eaec3SMichael S. Tsirkin disable_kick();
183481eaec3SMichael S. Tsirkin completed_before = completed;
184481eaec3SMichael S. Tsirkin while (__builtin_expect(use_buf(&len, &buf), true)) {
185481eaec3SMichael S. Tsirkin if (do_sleep)
186481eaec3SMichael S. Tsirkin call_used();
187481eaec3SMichael S. Tsirkin ++completed;
188481eaec3SMichael S. Tsirkin if (__builtin_expect(completed == bufs, false))
189481eaec3SMichael S. Tsirkin return;
190481eaec3SMichael S. Tsirkin }
191481eaec3SMichael S. Tsirkin if (completed == completed_before)
192481eaec3SMichael S. Tsirkin ++spurious;
193481eaec3SMichael S. Tsirkin assert(completed <= bufs);
194481eaec3SMichael S. Tsirkin if (completed == bufs)
195481eaec3SMichael S. Tsirkin break;
196481eaec3SMichael S. Tsirkin }
197481eaec3SMichael S. Tsirkin }
198481eaec3SMichael S. Tsirkin
start_guest(void * arg)199481eaec3SMichael S. Tsirkin void *start_guest(void *arg)
200481eaec3SMichael S. Tsirkin {
201481eaec3SMichael S. Tsirkin set_affinity(arg);
202481eaec3SMichael S. Tsirkin run_guest();
203481eaec3SMichael S. Tsirkin pthread_exit(NULL);
204481eaec3SMichael S. Tsirkin }
205481eaec3SMichael S. Tsirkin
start_host(void * arg)206481eaec3SMichael S. Tsirkin void *start_host(void *arg)
207481eaec3SMichael S. Tsirkin {
208481eaec3SMichael S. Tsirkin set_affinity(arg);
209481eaec3SMichael S. Tsirkin run_host();
210481eaec3SMichael S. Tsirkin pthread_exit(NULL);
211481eaec3SMichael S. Tsirkin }
212481eaec3SMichael S. Tsirkin
213481eaec3SMichael S. Tsirkin static const char optstring[] = "";
214481eaec3SMichael S. Tsirkin static const struct option longopts[] = {
215481eaec3SMichael S. Tsirkin {
216481eaec3SMichael S. Tsirkin .name = "help",
217481eaec3SMichael S. Tsirkin .has_arg = no_argument,
218481eaec3SMichael S. Tsirkin .val = 'h',
219481eaec3SMichael S. Tsirkin },
220481eaec3SMichael S. Tsirkin {
221481eaec3SMichael S. Tsirkin .name = "host-affinity",
222481eaec3SMichael S. Tsirkin .has_arg = required_argument,
223481eaec3SMichael S. Tsirkin .val = 'H',
224481eaec3SMichael S. Tsirkin },
225481eaec3SMichael S. Tsirkin {
226481eaec3SMichael S. Tsirkin .name = "guest-affinity",
227481eaec3SMichael S. Tsirkin .has_arg = required_argument,
228481eaec3SMichael S. Tsirkin .val = 'G',
229481eaec3SMichael S. Tsirkin },
230481eaec3SMichael S. Tsirkin {
231481eaec3SMichael S. Tsirkin .name = "ring-size",
232481eaec3SMichael S. Tsirkin .has_arg = required_argument,
233481eaec3SMichael S. Tsirkin .val = 'R',
234481eaec3SMichael S. Tsirkin },
235481eaec3SMichael S. Tsirkin {
236481eaec3SMichael S. Tsirkin .name = "run-cycles",
237481eaec3SMichael S. Tsirkin .has_arg = required_argument,
238481eaec3SMichael S. Tsirkin .val = 'C',
239481eaec3SMichael S. Tsirkin },
240481eaec3SMichael S. Tsirkin {
241481eaec3SMichael S. Tsirkin .name = "outstanding",
242481eaec3SMichael S. Tsirkin .has_arg = required_argument,
243481eaec3SMichael S. Tsirkin .val = 'o',
244481eaec3SMichael S. Tsirkin },
245481eaec3SMichael S. Tsirkin {
246481eaec3SMichael S. Tsirkin .name = "batch",
247481eaec3SMichael S. Tsirkin .has_arg = required_argument,
248481eaec3SMichael S. Tsirkin .val = 'b',
249481eaec3SMichael S. Tsirkin },
250481eaec3SMichael S. Tsirkin {
251a4979505SMichael S. Tsirkin .name = "param",
252a4979505SMichael S. Tsirkin .has_arg = required_argument,
253a4979505SMichael S. Tsirkin .val = 'p',
254a4979505SMichael S. Tsirkin },
255a4979505SMichael S. Tsirkin {
256481eaec3SMichael S. Tsirkin .name = "sleep",
257481eaec3SMichael S. Tsirkin .has_arg = no_argument,
258481eaec3SMichael S. Tsirkin .val = 's',
259481eaec3SMichael S. Tsirkin },
260481eaec3SMichael S. Tsirkin {
261481eaec3SMichael S. Tsirkin .name = "relax",
262481eaec3SMichael S. Tsirkin .has_arg = no_argument,
263481eaec3SMichael S. Tsirkin .val = 'x',
264481eaec3SMichael S. Tsirkin },
265481eaec3SMichael S. Tsirkin {
266481eaec3SMichael S. Tsirkin .name = "exit",
267481eaec3SMichael S. Tsirkin .has_arg = no_argument,
268481eaec3SMichael S. Tsirkin .val = 'e',
269481eaec3SMichael S. Tsirkin },
270481eaec3SMichael S. Tsirkin {
271481eaec3SMichael S. Tsirkin }
272481eaec3SMichael S. Tsirkin };
273481eaec3SMichael S. Tsirkin
help(void)274481eaec3SMichael S. Tsirkin static void help(void)
275481eaec3SMichael S. Tsirkin {
276481eaec3SMichael S. Tsirkin fprintf(stderr, "Usage: <test> [--help]"
277481eaec3SMichael S. Tsirkin " [--host-affinity H]"
278481eaec3SMichael S. Tsirkin " [--guest-affinity G]"
279481eaec3SMichael S. Tsirkin " [--ring-size R (default: %d)]"
280481eaec3SMichael S. Tsirkin " [--run-cycles C (default: %d)]"
281481eaec3SMichael S. Tsirkin " [--batch b]"
282481eaec3SMichael S. Tsirkin " [--outstanding o]"
283a4979505SMichael S. Tsirkin " [--param p]"
284481eaec3SMichael S. Tsirkin " [--sleep]"
285481eaec3SMichael S. Tsirkin " [--relax]"
286481eaec3SMichael S. Tsirkin " [--exit]"
287481eaec3SMichael S. Tsirkin "\n",
288481eaec3SMichael S. Tsirkin ring_size,
289481eaec3SMichael S. Tsirkin runcycles);
290481eaec3SMichael S. Tsirkin }
291481eaec3SMichael S. Tsirkin
main(int argc,char ** argv)292481eaec3SMichael S. Tsirkin int main(int argc, char **argv)
293481eaec3SMichael S. Tsirkin {
294481eaec3SMichael S. Tsirkin int ret;
295481eaec3SMichael S. Tsirkin pthread_t host, guest;
296481eaec3SMichael S. Tsirkin void *tret;
297481eaec3SMichael S. Tsirkin char *host_arg = NULL;
298481eaec3SMichael S. Tsirkin char *guest_arg = NULL;
299481eaec3SMichael S. Tsirkin char *endptr;
300481eaec3SMichael S. Tsirkin long int c;
301481eaec3SMichael S. Tsirkin
302481eaec3SMichael S. Tsirkin kickfd = eventfd(0, 0);
303481eaec3SMichael S. Tsirkin assert(kickfd >= 0);
304481eaec3SMichael S. Tsirkin callfd = eventfd(0, 0);
305481eaec3SMichael S. Tsirkin assert(callfd >= 0);
306481eaec3SMichael S. Tsirkin
307481eaec3SMichael S. Tsirkin for (;;) {
308481eaec3SMichael S. Tsirkin int o = getopt_long(argc, argv, optstring, longopts, NULL);
309481eaec3SMichael S. Tsirkin switch (o) {
310481eaec3SMichael S. Tsirkin case -1:
311481eaec3SMichael S. Tsirkin goto done;
312481eaec3SMichael S. Tsirkin case '?':
313481eaec3SMichael S. Tsirkin help();
314481eaec3SMichael S. Tsirkin exit(2);
315481eaec3SMichael S. Tsirkin case 'H':
316481eaec3SMichael S. Tsirkin host_arg = optarg;
317481eaec3SMichael S. Tsirkin break;
318481eaec3SMichael S. Tsirkin case 'G':
319481eaec3SMichael S. Tsirkin guest_arg = optarg;
320481eaec3SMichael S. Tsirkin break;
321481eaec3SMichael S. Tsirkin case 'R':
322481eaec3SMichael S. Tsirkin ring_size = strtol(optarg, &endptr, 0);
323481eaec3SMichael S. Tsirkin assert(ring_size && !(ring_size & (ring_size - 1)));
324481eaec3SMichael S. Tsirkin assert(!*endptr);
325481eaec3SMichael S. Tsirkin break;
326481eaec3SMichael S. Tsirkin case 'C':
327481eaec3SMichael S. Tsirkin c = strtol(optarg, &endptr, 0);
328481eaec3SMichael S. Tsirkin assert(!*endptr);
329481eaec3SMichael S. Tsirkin assert(c > 0 && c < INT_MAX);
330481eaec3SMichael S. Tsirkin runcycles = c;
331481eaec3SMichael S. Tsirkin break;
332481eaec3SMichael S. Tsirkin case 'o':
333481eaec3SMichael S. Tsirkin c = strtol(optarg, &endptr, 0);
334481eaec3SMichael S. Tsirkin assert(!*endptr);
335481eaec3SMichael S. Tsirkin assert(c > 0 && c < INT_MAX);
336481eaec3SMichael S. Tsirkin max_outstanding = c;
337481eaec3SMichael S. Tsirkin break;
338a4979505SMichael S. Tsirkin case 'p':
339a4979505SMichael S. Tsirkin c = strtol(optarg, &endptr, 0);
340a4979505SMichael S. Tsirkin assert(!*endptr);
341a4979505SMichael S. Tsirkin assert(c > 0 && c < INT_MAX);
342a4979505SMichael S. Tsirkin param = c;
343a4979505SMichael S. Tsirkin break;
344481eaec3SMichael S. Tsirkin case 'b':
345481eaec3SMichael S. Tsirkin c = strtol(optarg, &endptr, 0);
346481eaec3SMichael S. Tsirkin assert(!*endptr);
347481eaec3SMichael S. Tsirkin assert(c > 0 && c < INT_MAX);
348481eaec3SMichael S. Tsirkin batch = c;
349481eaec3SMichael S. Tsirkin break;
350481eaec3SMichael S. Tsirkin case 's':
351481eaec3SMichael S. Tsirkin do_sleep = true;
352481eaec3SMichael S. Tsirkin break;
353481eaec3SMichael S. Tsirkin case 'x':
354481eaec3SMichael S. Tsirkin do_relax = true;
355481eaec3SMichael S. Tsirkin break;
356481eaec3SMichael S. Tsirkin case 'e':
357481eaec3SMichael S. Tsirkin do_exit = true;
358481eaec3SMichael S. Tsirkin break;
359481eaec3SMichael S. Tsirkin default:
360481eaec3SMichael S. Tsirkin help();
361481eaec3SMichael S. Tsirkin exit(4);
362481eaec3SMichael S. Tsirkin break;
363481eaec3SMichael S. Tsirkin }
364481eaec3SMichael S. Tsirkin }
365481eaec3SMichael S. Tsirkin
366481eaec3SMichael S. Tsirkin /* does nothing here, used to make sure all smp APIs compile */
367481eaec3SMichael S. Tsirkin smp_acquire();
368481eaec3SMichael S. Tsirkin smp_release();
369481eaec3SMichael S. Tsirkin smp_mb();
370481eaec3SMichael S. Tsirkin done:
371481eaec3SMichael S. Tsirkin
372481eaec3SMichael S. Tsirkin if (batch > max_outstanding)
373481eaec3SMichael S. Tsirkin batch = max_outstanding;
374481eaec3SMichael S. Tsirkin
375481eaec3SMichael S. Tsirkin if (optind < argc) {
376481eaec3SMichael S. Tsirkin help();
377481eaec3SMichael S. Tsirkin exit(4);
378481eaec3SMichael S. Tsirkin }
379481eaec3SMichael S. Tsirkin alloc_ring();
380481eaec3SMichael S. Tsirkin
381481eaec3SMichael S. Tsirkin ret = pthread_create(&host, NULL, start_host, host_arg);
382481eaec3SMichael S. Tsirkin assert(!ret);
383481eaec3SMichael S. Tsirkin ret = pthread_create(&guest, NULL, start_guest, guest_arg);
384481eaec3SMichael S. Tsirkin assert(!ret);
385481eaec3SMichael S. Tsirkin
386481eaec3SMichael S. Tsirkin ret = pthread_join(guest, &tret);
387481eaec3SMichael S. Tsirkin assert(!ret);
388481eaec3SMichael S. Tsirkin ret = pthread_join(host, &tret);
389481eaec3SMichael S. Tsirkin assert(!ret);
390481eaec3SMichael S. Tsirkin return 0;
391481eaec3SMichael S. Tsirkin }
392