Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/virtio/ringtest/main.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2016 Red Hat, Inc.
4
* Author: Michael S. Tsirkin <[email protected]>
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
int param = 0;
24
25
bool do_sleep = false;
26
bool do_relax = false;
27
bool do_exit = true;
28
29
unsigned ring_size = 256;
30
31
static int kickfd = -1;
32
static int callfd = -1;
33
34
void notify(int fd)
35
{
36
unsigned long long v = 1;
37
int r;
38
39
vmexit();
40
r = write(fd, &v, sizeof v);
41
assert(r == sizeof v);
42
vmentry();
43
}
44
45
void wait_for_notify(int fd)
46
{
47
unsigned long long v = 1;
48
int r;
49
50
vmexit();
51
r = read(fd, &v, sizeof v);
52
assert(r == sizeof v);
53
vmentry();
54
}
55
56
void kick(void)
57
{
58
notify(kickfd);
59
}
60
61
void wait_for_kick(void)
62
{
63
wait_for_notify(kickfd);
64
}
65
66
void call(void)
67
{
68
notify(callfd);
69
}
70
71
void wait_for_call(void)
72
{
73
wait_for_notify(callfd);
74
}
75
76
void set_affinity(const char *arg)
77
{
78
cpu_set_t cpuset;
79
int ret;
80
pthread_t self;
81
long int cpu;
82
char *endptr;
83
84
if (!arg)
85
return;
86
87
cpu = strtol(arg, &endptr, 0);
88
assert(!*endptr);
89
90
assert(cpu >= 0 && cpu < CPU_SETSIZE);
91
92
self = pthread_self();
93
CPU_ZERO(&cpuset);
94
CPU_SET(cpu, &cpuset);
95
96
ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
97
assert(!ret);
98
}
99
100
void poll_used(void)
101
{
102
while (used_empty())
103
busy_wait();
104
}
105
106
static void __attribute__((__flatten__)) run_guest(void)
107
{
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;
117
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();
132
}
133
134
}
135
} else
136
r = -1;
137
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;
144
}
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();
155
}
156
}
157
}
158
159
void poll_avail(void)
160
{
161
while (avail_empty())
162
busy_wait();
163
}
164
165
static void __attribute__((__flatten__)) run_host(void)
166
{
167
int completed_before;
168
int completed = 0;
169
int spurious = 0;
170
int bufs = runcycles;
171
unsigned len;
172
void *buf;
173
174
for (;;) {
175
if (do_sleep) {
176
if (avail_empty() && enable_kick())
177
wait_for_kick();
178
} else {
179
poll_avail();
180
}
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;
190
}
191
if (completed == completed_before)
192
++spurious;
193
assert(completed <= bufs);
194
if (completed == bufs)
195
break;
196
}
197
}
198
199
void *start_guest(void *arg)
200
{
201
set_affinity(arg);
202
run_guest();
203
pthread_exit(NULL);
204
}
205
206
void *start_host(void *arg)
207
{
208
set_affinity(arg);
209
run_host();
210
pthread_exit(NULL);
211
}
212
213
static const char optstring[] = "";
214
static const struct option longopts[] = {
215
{
216
.name = "help",
217
.has_arg = no_argument,
218
.val = 'h',
219
},
220
{
221
.name = "host-affinity",
222
.has_arg = required_argument,
223
.val = 'H',
224
},
225
{
226
.name = "guest-affinity",
227
.has_arg = required_argument,
228
.val = 'G',
229
},
230
{
231
.name = "ring-size",
232
.has_arg = required_argument,
233
.val = 'R',
234
},
235
{
236
.name = "run-cycles",
237
.has_arg = required_argument,
238
.val = 'C',
239
},
240
{
241
.name = "outstanding",
242
.has_arg = required_argument,
243
.val = 'o',
244
},
245
{
246
.name = "batch",
247
.has_arg = required_argument,
248
.val = 'b',
249
},
250
{
251
.name = "param",
252
.has_arg = required_argument,
253
.val = 'p',
254
},
255
{
256
.name = "sleep",
257
.has_arg = no_argument,
258
.val = 's',
259
},
260
{
261
.name = "relax",
262
.has_arg = no_argument,
263
.val = 'x',
264
},
265
{
266
.name = "exit",
267
.has_arg = no_argument,
268
.val = 'e',
269
},
270
{
271
}
272
};
273
274
static void help(void)
275
{
276
fprintf(stderr, "Usage: <test> [--help]"
277
" [--host-affinity H]"
278
" [--guest-affinity G]"
279
" [--ring-size R (default: %u)]"
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);
290
}
291
292
int main(int argc, char **argv)
293
{
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;
301
302
kickfd = eventfd(0, 0);
303
assert(kickfd >= 0);
304
callfd = eventfd(0, 0);
305
assert(callfd >= 0);
306
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;
363
}
364
}
365
366
/* does nothing here, used to make sure all smp APIs compile */
367
smp_acquire();
368
smp_release();
369
smp_mb();
370
done:
371
372
if (batch > max_outstanding)
373
batch = max_outstanding;
374
375
if (optind < argc) {
376
help();
377
exit(4);
378
}
379
alloc_ring();
380
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);
385
386
ret = pthread_join(guest, &tret);
387
assert(!ret);
388
ret = pthread_join(host, &tret);
389
assert(!ret);
390
return 0;
391
}
392
393