Merge tag 'ntb-4.8' of git://github.com/jonmason/ntb
[deliverable/linux.git] / tools / virtio / ringtest / main.c
1 /*
2 * Copyright (C) 2016 Red Hat, Inc.
3 * Author: Michael S. Tsirkin <mst@redhat.com>
4 * This work is licensed under the terms of the GNU GPL, version 2.
5 *
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>
19
20 int runcycles = 10000000;
21 int max_outstanding = INT_MAX;
22 int batch = 1;
23
24 bool do_sleep = false;
25 bool do_relax = false;
26 bool do_exit = true;
27
28 unsigned ring_size = 256;
29
30 static int kickfd = -1;
31 static int callfd = -1;
32
33 void notify(int fd)
34 {
35 unsigned long long v = 1;
36 int r;
37
38 vmexit();
39 r = write(fd, &v, sizeof v);
40 assert(r == sizeof v);
41 vmentry();
42 }
43
44 void wait_for_notify(int fd)
45 {
46 unsigned long long v = 1;
47 int r;
48
49 vmexit();
50 r = read(fd, &v, sizeof v);
51 assert(r == sizeof v);
52 vmentry();
53 }
54
55 void kick(void)
56 {
57 notify(kickfd);
58 }
59
60 void wait_for_kick(void)
61 {
62 wait_for_notify(kickfd);
63 }
64
65 void call(void)
66 {
67 notify(callfd);
68 }
69
70 void wait_for_call(void)
71 {
72 wait_for_notify(callfd);
73 }
74
75 void set_affinity(const char *arg)
76 {
77 cpu_set_t cpuset;
78 int ret;
79 pthread_t self;
80 long int cpu;
81 char *endptr;
82
83 if (!arg)
84 return;
85
86 cpu = strtol(arg, &endptr, 0);
87 assert(!*endptr);
88
89 assert(cpu >= 0 || cpu < CPU_SETSIZE);
90
91 self = pthread_self();
92 CPU_ZERO(&cpuset);
93 CPU_SET(cpu, &cpuset);
94
95 ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
96 assert(!ret);
97 }
98
99 static void run_guest(void)
100 {
101 int completed_before;
102 int completed = 0;
103 int started = 0;
104 int bufs = runcycles;
105 int spurious = 0;
106 int r;
107 unsigned len;
108 void *buf;
109 int tokick = batch;
110
111 for (;;) {
112 if (do_sleep)
113 disable_call();
114 completed_before = completed;
115 do {
116 if (started < bufs &&
117 started - completed < max_outstanding) {
118 r = add_inbuf(0, "Buffer\n", "Hello, world!");
119 if (__builtin_expect(r == 0, true)) {
120 ++started;
121 if (!--tokick) {
122 tokick = batch;
123 if (do_sleep)
124 kick_available();
125 }
126
127 }
128 } else
129 r = -1;
130
131 /* Flush out completed bufs if any */
132 if (get_buf(&len, &buf)) {
133 ++completed;
134 if (__builtin_expect(completed == bufs, false))
135 return;
136 r = 0;
137 }
138 } while (r == 0);
139 if (completed == completed_before)
140 ++spurious;
141 assert(completed <= bufs);
142 assert(started <= bufs);
143 if (do_sleep) {
144 if (enable_call())
145 wait_for_call();
146 } else {
147 poll_used();
148 }
149 }
150 }
151
152 static void run_host(void)
153 {
154 int completed_before;
155 int completed = 0;
156 int spurious = 0;
157 int bufs = runcycles;
158 unsigned len;
159 void *buf;
160
161 for (;;) {
162 if (do_sleep) {
163 if (enable_kick())
164 wait_for_kick();
165 } else {
166 poll_avail();
167 }
168 if (do_sleep)
169 disable_kick();
170 completed_before = completed;
171 while (__builtin_expect(use_buf(&len, &buf), true)) {
172 if (do_sleep)
173 call_used();
174 ++completed;
175 if (__builtin_expect(completed == bufs, false))
176 return;
177 }
178 if (completed == completed_before)
179 ++spurious;
180 assert(completed <= bufs);
181 if (completed == bufs)
182 break;
183 }
184 }
185
186 void *start_guest(void *arg)
187 {
188 set_affinity(arg);
189 run_guest();
190 pthread_exit(NULL);
191 }
192
193 void *start_host(void *arg)
194 {
195 set_affinity(arg);
196 run_host();
197 pthread_exit(NULL);
198 }
199
200 static const char optstring[] = "";
201 static const struct option longopts[] = {
202 {
203 .name = "help",
204 .has_arg = no_argument,
205 .val = 'h',
206 },
207 {
208 .name = "host-affinity",
209 .has_arg = required_argument,
210 .val = 'H',
211 },
212 {
213 .name = "guest-affinity",
214 .has_arg = required_argument,
215 .val = 'G',
216 },
217 {
218 .name = "ring-size",
219 .has_arg = required_argument,
220 .val = 'R',
221 },
222 {
223 .name = "run-cycles",
224 .has_arg = required_argument,
225 .val = 'C',
226 },
227 {
228 .name = "outstanding",
229 .has_arg = required_argument,
230 .val = 'o',
231 },
232 {
233 .name = "batch",
234 .has_arg = required_argument,
235 .val = 'b',
236 },
237 {
238 .name = "sleep",
239 .has_arg = no_argument,
240 .val = 's',
241 },
242 {
243 .name = "relax",
244 .has_arg = no_argument,
245 .val = 'x',
246 },
247 {
248 .name = "exit",
249 .has_arg = no_argument,
250 .val = 'e',
251 },
252 {
253 }
254 };
255
256 static void help(void)
257 {
258 fprintf(stderr, "Usage: <test> [--help]"
259 " [--host-affinity H]"
260 " [--guest-affinity G]"
261 " [--ring-size R (default: %d)]"
262 " [--run-cycles C (default: %d)]"
263 " [--batch b]"
264 " [--outstanding o]"
265 " [--sleep]"
266 " [--relax]"
267 " [--exit]"
268 "\n",
269 ring_size,
270 runcycles);
271 }
272
273 int main(int argc, char **argv)
274 {
275 int ret;
276 pthread_t host, guest;
277 void *tret;
278 char *host_arg = NULL;
279 char *guest_arg = NULL;
280 char *endptr;
281 long int c;
282
283 kickfd = eventfd(0, 0);
284 assert(kickfd >= 0);
285 callfd = eventfd(0, 0);
286 assert(callfd >= 0);
287
288 for (;;) {
289 int o = getopt_long(argc, argv, optstring, longopts, NULL);
290 switch (o) {
291 case -1:
292 goto done;
293 case '?':
294 help();
295 exit(2);
296 case 'H':
297 host_arg = optarg;
298 break;
299 case 'G':
300 guest_arg = optarg;
301 break;
302 case 'R':
303 ring_size = strtol(optarg, &endptr, 0);
304 assert(ring_size && !(ring_size & (ring_size - 1)));
305 assert(!*endptr);
306 break;
307 case 'C':
308 c = strtol(optarg, &endptr, 0);
309 assert(!*endptr);
310 assert(c > 0 && c < INT_MAX);
311 runcycles = c;
312 break;
313 case 'o':
314 c = strtol(optarg, &endptr, 0);
315 assert(!*endptr);
316 assert(c > 0 && c < INT_MAX);
317 max_outstanding = c;
318 break;
319 case 'b':
320 c = strtol(optarg, &endptr, 0);
321 assert(!*endptr);
322 assert(c > 0 && c < INT_MAX);
323 batch = c;
324 break;
325 case 's':
326 do_sleep = true;
327 break;
328 case 'x':
329 do_relax = true;
330 break;
331 case 'e':
332 do_exit = true;
333 break;
334 default:
335 help();
336 exit(4);
337 break;
338 }
339 }
340
341 /* does nothing here, used to make sure all smp APIs compile */
342 smp_acquire();
343 smp_release();
344 smp_mb();
345 done:
346
347 if (batch > max_outstanding)
348 batch = max_outstanding;
349
350 if (optind < argc) {
351 help();
352 exit(4);
353 }
354 alloc_ring();
355
356 ret = pthread_create(&host, NULL, start_host, host_arg);
357 assert(!ret);
358 ret = pthread_create(&guest, NULL, start_guest, guest_arg);
359 assert(!ret);
360
361 ret = pthread_join(guest, &tret);
362 assert(!ret);
363 ret = pthread_join(host, &tret);
364 assert(!ret);
365 return 0;
366 }
This page took 0.049037 seconds and 5 git commands to generate.