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