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