]> git.proxmox.com Git - systemd.git/blob - src/libsystemd/sd-bus/test-bus-benchmark.c
Enable seccomp support on powerpc, ppc64el, and s390x
[systemd.git] / src / libsystemd / sd-bus / test-bus-benchmark.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/wait.h>
23
24 #include "sd-bus.h"
25
26 #include "alloc-util.h"
27 #include "bus-internal.h"
28 #include "bus-kernel.h"
29 #include "bus-util.h"
30 #include "def.h"
31 #include "fd-util.h"
32 #include "time-util.h"
33 #include "util.h"
34
35 #define MAX_SIZE (2*1024*1024)
36
37 static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
38
39 typedef enum Type {
40 TYPE_KDBUS,
41 TYPE_LEGACY,
42 TYPE_DIRECT,
43 } Type;
44
45 static void server(sd_bus *b, size_t *result) {
46 int r;
47
48 for (;;) {
49 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
50
51 r = sd_bus_process(b, &m);
52 assert_se(r >= 0);
53
54 if (r == 0)
55 assert_se(sd_bus_wait(b, USEC_INFINITY) >= 0);
56 if (!m)
57 continue;
58
59 if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping"))
60 assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
61 else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
62 const void *p;
63 size_t sz;
64
65 /* Make sure the mmap is mapped */
66 assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
67
68 r = sd_bus_reply_method_return(m, NULL);
69 assert_se(r >= 0);
70 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
71 uint64_t res;
72 assert_se(sd_bus_message_read(m, "t", &res) > 0);
73
74 *result = res;
75 return;
76
77 } else if (!sd_bus_message_is_signal(m, NULL, NULL))
78 assert_not_reached("Unknown method");
79 }
80 }
81
82 static void transaction(sd_bus *b, size_t sz, const char *server_name) {
83 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
84 uint8_t *p;
85
86 assert_se(sd_bus_message_new_method_call(b, &m, server_name, "/", "benchmark.server", "Work") >= 0);
87 assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
88
89 memset(p, 0x80, sz);
90
91 assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0);
92 }
93
94 static void client_bisect(const char *address, const char *server_name) {
95 _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
96 size_t lsize, rsize, csize;
97 sd_bus *b;
98 int r;
99
100 r = sd_bus_new(&b);
101 assert_se(r >= 0);
102
103 r = sd_bus_set_address(b, address);
104 assert_se(r >= 0);
105
106 r = sd_bus_start(b);
107 assert_se(r >= 0);
108
109 r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
110 assert_se(r >= 0);
111
112 lsize = 1;
113 rsize = MAX_SIZE;
114
115 printf("SIZE\tCOPY\tMEMFD\n");
116
117 for (;;) {
118 usec_t t;
119 unsigned n_copying, n_memfd;
120
121 csize = (lsize + rsize) / 2;
122
123 if (csize <= lsize)
124 break;
125
126 if (csize <= 0)
127 break;
128
129 printf("%zu\t", csize);
130
131 b->use_memfd = 0;
132
133 t = now(CLOCK_MONOTONIC);
134 for (n_copying = 0;; n_copying++) {
135 transaction(b, csize, server_name);
136 if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
137 break;
138 }
139 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
140
141 b->use_memfd = -1;
142
143 t = now(CLOCK_MONOTONIC);
144 for (n_memfd = 0;; n_memfd++) {
145 transaction(b, csize, server_name);
146 if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
147 break;
148 }
149 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
150
151 if (n_copying == n_memfd)
152 break;
153
154 if (n_copying > n_memfd)
155 lsize = csize;
156 else
157 rsize = csize;
158 }
159
160 b->use_memfd = 1;
161 assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
162 assert_se(sd_bus_message_append(x, "t", csize) >= 0);
163 assert_se(sd_bus_send(b, x, NULL) >= 0);
164
165 sd_bus_unref(b);
166 }
167
168 static void client_chart(Type type, const char *address, const char *server_name, int fd) {
169 _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
170 size_t csize;
171 sd_bus *b;
172 int r;
173
174 r = sd_bus_new(&b);
175 assert_se(r >= 0);
176
177 if (type == TYPE_DIRECT) {
178 r = sd_bus_set_fd(b, fd, fd);
179 assert_se(r >= 0);
180 } else {
181 r = sd_bus_set_address(b, address);
182 assert_se(r >= 0);
183
184 r = sd_bus_set_bus_client(b, true);
185 assert_se(r >= 0);
186 }
187
188 r = sd_bus_start(b);
189 assert_se(r >= 0);
190
191 r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
192 assert_se(r >= 0);
193
194 switch (type) {
195 case TYPE_KDBUS:
196 printf("SIZE\tCOPY\tMEMFD\n");
197 break;
198 case TYPE_LEGACY:
199 printf("SIZE\tLEGACY\n");
200 break;
201 case TYPE_DIRECT:
202 printf("SIZE\tDIRECT\n");
203 break;
204 }
205
206 for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
207 usec_t t;
208 unsigned n_copying, n_memfd;
209
210 printf("%zu\t", csize);
211
212 if (type == TYPE_KDBUS) {
213 b->use_memfd = 0;
214
215 t = now(CLOCK_MONOTONIC);
216 for (n_copying = 0;; n_copying++) {
217 transaction(b, csize, server_name);
218 if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
219 break;
220 }
221
222 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
223
224 b->use_memfd = -1;
225 }
226
227 t = now(CLOCK_MONOTONIC);
228 for (n_memfd = 0;; n_memfd++) {
229 transaction(b, csize, server_name);
230 if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
231 break;
232 }
233
234 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
235 }
236
237 b->use_memfd = 1;
238 assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
239 assert_se(sd_bus_message_append(x, "t", csize) >= 0);
240 assert_se(sd_bus_send(b, x, NULL) >= 0);
241
242 sd_bus_unref(b);
243 }
244
245 int main(int argc, char *argv[]) {
246 enum {
247 MODE_BISECT,
248 MODE_CHART,
249 } mode = MODE_BISECT;
250 Type type = TYPE_KDBUS;
251 int i, pair[2] = { -1, -1 };
252 _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *server_name = NULL;
253 _cleanup_close_ int bus_ref = -1;
254 const char *unique;
255 cpu_set_t cpuset;
256 size_t result;
257 sd_bus *b;
258 pid_t pid;
259 int r;
260
261 for (i = 1; i < argc; i++) {
262 if (streq(argv[i], "chart")) {
263 mode = MODE_CHART;
264 continue;
265 } else if (streq(argv[i], "legacy")) {
266 type = TYPE_LEGACY;
267 continue;
268 } else if (streq(argv[i], "direct")) {
269 type = TYPE_DIRECT;
270 continue;
271 }
272
273 assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
274 }
275
276 assert_se(!MODE_BISECT || TYPE_KDBUS);
277
278 assert_se(arg_loop_usec > 0);
279
280 if (type == TYPE_KDBUS) {
281 assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
282
283 bus_ref = bus_kernel_create_bus(name, false, &bus_name);
284 if (bus_ref == -ENOENT)
285 exit(EXIT_TEST_SKIP);
286
287 assert_se(bus_ref >= 0);
288
289 address = strappend("kernel:path=", bus_name);
290 assert_se(address);
291 } else if (type == TYPE_LEGACY) {
292 const char *e;
293
294 e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
295 assert_se(e);
296
297 address = strdup(e);
298 assert_se(address);
299 }
300
301 r = sd_bus_new(&b);
302 assert_se(r >= 0);
303
304 if (type == TYPE_DIRECT) {
305 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) >= 0);
306
307 r = sd_bus_set_fd(b, pair[0], pair[0]);
308 assert_se(r >= 0);
309
310 r = sd_bus_set_server(b, true, SD_ID128_NULL);
311 assert_se(r >= 0);
312 } else {
313 r = sd_bus_set_address(b, address);
314 assert_se(r >= 0);
315
316 r = sd_bus_set_bus_client(b, true);
317 assert_se(r >= 0);
318 }
319
320 r = sd_bus_start(b);
321 assert_se(r >= 0);
322
323 if (type != TYPE_DIRECT) {
324 r = sd_bus_get_unique_name(b, &unique);
325 assert_se(r >= 0);
326
327 server_name = strdup(unique);
328 assert_se(server_name);
329 }
330
331 sync();
332 setpriority(PRIO_PROCESS, 0, -19);
333
334 pid = fork();
335 assert_se(pid >= 0);
336
337 if (pid == 0) {
338 CPU_ZERO(&cpuset);
339 CPU_SET(0, &cpuset);
340 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
341
342 safe_close(bus_ref);
343 sd_bus_unref(b);
344
345 switch (mode) {
346 case MODE_BISECT:
347 client_bisect(address, server_name);
348 break;
349
350 case MODE_CHART:
351 client_chart(type, address, server_name, pair[1]);
352 break;
353 }
354
355 _exit(0);
356 }
357
358 CPU_ZERO(&cpuset);
359 CPU_SET(1, &cpuset);
360 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
361
362 server(b, &result);
363
364 if (mode == MODE_BISECT)
365 printf("Copying/memfd are equally fast at %zu bytes\n", result);
366
367 assert_se(waitpid(pid, NULL, 0) == pid);
368
369 safe_close(pair[1]);
370 sd_bus_unref(b);
371
372 return 0;
373 }