]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8f155917
LP
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
8f155917
LP
21#include <sys/wait.h>
22
8f155917 23#include "sd-bus.h"
07630cea 24
b5efdb8a 25#include "alloc-util.h"
8f155917 26#include "bus-internal.h"
07630cea 27#include "bus-kernel.h"
057171ef 28#include "bus-util.h"
07630cea 29#include "def.h"
3ffd4af2 30#include "fd-util.h"
07630cea
LP
31#include "time-util.h"
32#include "util.h"
8f155917 33
1679ddc4 34#define MAX_SIZE (2*1024*1024)
8f155917 35
59967d30 36static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
061b2c43 37
77cfd113 38typedef enum Type {
77cfd113
TG
39 TYPE_LEGACY,
40 TYPE_DIRECT,
41} Type;
42
832d16a6 43static void server(sd_bus *b, size_t *result) {
8f155917
LP
44 int r;
45
46 for (;;) {
4afd3348 47 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
8f155917
LP
48
49 r = sd_bus_process(b, &m);
50 assert_se(r >= 0);
51
52 if (r == 0)
3a43da28 53 assert_se(sd_bus_wait(b, USEC_INFINITY) >= 0);
8f155917
LP
54 if (!m)
55 continue;
56
832d16a6 57 if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping"))
df2d202e 58 assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
832d16a6
LP
59 else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
60 const void *p;
61 size_t sz;
8f155917 62
832d16a6
LP
63 /* Make sure the mmap is mapped */
64 assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
8f155917 65
def3f524
DM
66 r = sd_bus_reply_method_return(m, NULL);
67 assert_se(r >= 0);
8f155917 68 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
832d16a6
LP
69 uint64_t res;
70 assert_se(sd_bus_message_read(m, "t", &res) > 0);
8f155917 71
832d16a6 72 *result = res;
8f155917
LP
73 return;
74
77cfd113 75 } else if (!sd_bus_message_is_signal(m, NULL, NULL))
8f155917
LP
76 assert_not_reached("Unknown method");
77 }
78}
79
def3f524 80static void transaction(sd_bus *b, size_t sz, const char *server_name) {
4afd3348 81 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
832d16a6 82 uint8_t *p;
8f155917 83
def3f524 84 assert_se(sd_bus_message_new_method_call(b, &m, server_name, "/", "benchmark.server", "Work") >= 0);
8f155917
LP
85 assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
86
31175451 87 memset(p, 0x80, sz);
8f155917 88
c49b30a2 89 assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0);
832d16a6
LP
90}
91
def3f524 92static void client_bisect(const char *address, const char *server_name) {
4afd3348 93 _cleanup_(sd_bus_message_unrefp) sd_bus_message *x = NULL;
832d16a6
LP
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
def3f524
DM
107 r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
108 assert_se(r >= 0);
832d16a6
LP
109
110 lsize = 1;
111 rsize = MAX_SIZE;
112
31175451
KS
113 printf("SIZE\tCOPY\tMEMFD\n");
114
832d16a6 115 for (;;) {
061b2c43
LP
116 usec_t t;
117 unsigned n_copying, n_memfd;
832d16a6
LP
118
119 csize = (lsize + rsize) / 2;
120
832d16a6
LP
121 if (csize <= lsize)
122 break;
123
124 if (csize <= 0)
125 break;
8f155917 126
83d97ce6 127 printf("%zu\t", csize);
31175451 128
832d16a6 129 b->use_memfd = 0;
061b2c43 130
832d16a6 131 t = now(CLOCK_MONOTONIC);
061b2c43 132 for (n_copying = 0;; n_copying++) {
def3f524 133 transaction(b, csize, server_name);
061b2c43
LP
134 if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
135 break;
136 }
31175451 137 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
061b2c43 138
832d16a6 139 b->use_memfd = -1;
061b2c43 140
832d16a6 141 t = now(CLOCK_MONOTONIC);
061b2c43 142 for (n_memfd = 0;; n_memfd++) {
def3f524 143 transaction(b, csize, server_name);
061b2c43
LP
144 if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
145 break;
146 }
6cbf6931 147 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
061b2c43
LP
148
149 if (n_copying == n_memfd)
832d16a6
LP
150 break;
151
061b2c43 152 if (n_copying > n_memfd)
832d16a6
LP
153 lsize = csize;
154 else
155 rsize = csize;
8f155917
LP
156 }
157
31175451 158 b->use_memfd = 1;
def3f524 159 assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
31175451
KS
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
77cfd113 166static void client_chart(Type type, const char *address, const char *server_name, int fd) {
4afd3348 167 _cleanup_(sd_bus_message_unrefp) sd_bus_message *x = NULL;
31175451
KS
168 size_t csize;
169 sd_bus *b;
170 int r;
171
172 r = sd_bus_new(&b);
173 assert_se(r >= 0);
174
77cfd113
TG
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 }
31175451
KS
185
186 r = sd_bus_start(b);
187 assert_se(r >= 0);
188
77cfd113
TG
189 r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
190 assert_se(r >= 0);
31175451 191
77cfd113 192 switch (type) {
77cfd113
TG
193 case TYPE_LEGACY:
194 printf("SIZE\tLEGACY\n");
195 break;
196 case TYPE_DIRECT:
197 printf("SIZE\tDIRECT\n");
198 break;
199 }
31175451 200
83d97ce6 201 for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
31175451 202 usec_t t;
a132bef0 203 unsigned n_memfd;
31175451 204
83d97ce6 205 printf("%zu\t", csize);
31175451 206
31175451
KS
207 t = now(CLOCK_MONOTONIC);
208 for (n_memfd = 0;; n_memfd++) {
def3f524 209 transaction(b, csize, server_name);
31175451
KS
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;
def3f524 218 assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
832d16a6
LP
219 assert_se(sd_bus_message_append(x, "t", csize) >= 0);
220 assert_se(sd_bus_send(b, x, NULL) >= 0);
8f155917 221
832d16a6 222 sd_bus_unref(b);
8f155917
LP
223}
224
832d16a6 225int main(int argc, char *argv[]) {
31175451
KS
226 enum {
227 MODE_BISECT,
228 MODE_CHART,
229 } mode = MODE_BISECT;
a132bef0 230 Type type = TYPE_LEGACY;
77cfd113 231 int i, pair[2] = { -1, -1 };
ac097c84 232 _cleanup_free_ char *address = NULL, *server_name = NULL;
832d16a6 233 _cleanup_close_ int bus_ref = -1;
def3f524 234 const char *unique;
832d16a6
LP
235 cpu_set_t cpuset;
236 size_t result;
8f155917 237 sd_bus *b;
8f155917 238 pid_t pid;
832d16a6
LP
239 int r;
240
31175451
KS
241 for (i = 1; i < argc; i++) {
242 if (streq(argv[i], "chart")) {
243 mode = MODE_CHART;
244 continue;
77cfd113
TG
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;
31175451
KS
251 }
252
253 assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
254 }
061b2c43
LP
255
256 assert_se(arg_loop_usec > 0);
257
a132bef0 258 if (type == TYPE_LEGACY) {
77cfd113 259 const char *e;
8f155917 260
77cfd113
TG
261 e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
262 assert_se(e);
263
264 address = strdup(e);
265 assert_se(address);
266 }
8f155917
LP
267
268 r = sd_bus_new(&b);
269 assert_se(r >= 0);
270
77cfd113
TG
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 }
8f155917
LP
286
287 r = sd_bus_start(b);
288 assert_se(r >= 0);
289
77cfd113
TG
290 if (type != TYPE_DIRECT) {
291 r = sd_bus_get_unique_name(b, &unique);
292 assert_se(r >= 0);
def3f524 293
77cfd113
TG
294 server_name = strdup(unique);
295 assert_se(server_name);
296 }
def3f524 297
832d16a6
LP
298 sync();
299 setpriority(PRIO_PROCESS, 0, -19);
300
8f155917
LP
301 pid = fork();
302 assert_se(pid >= 0);
303
304 if (pid == 0) {
832d16a6
LP
305 CPU_ZERO(&cpuset);
306 CPU_SET(0, &cpuset);
307 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
308
03e334a1 309 safe_close(bus_ref);
8f155917
LP
310 sd_bus_unref(b);
311
31175451
KS
312 switch (mode) {
313 case MODE_BISECT:
def3f524 314 client_bisect(address, server_name);
31175451
KS
315 break;
316
317 case MODE_CHART:
77cfd113 318 client_chart(type, address, server_name, pair[1]);
31175451
KS
319 break;
320 }
321
8f155917
LP
322 _exit(0);
323 }
324
832d16a6
LP
325 CPU_ZERO(&cpuset);
326 CPU_SET(1, &cpuset);
327 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
8f155917 328
832d16a6 329 server(b, &result);
8f155917 330
31175451
KS
331 if (mode == MODE_BISECT)
332 printf("Copying/memfd are equally fast at %zu bytes\n", result);
8f155917 333
832d16a6 334 assert_se(waitpid(pid, NULL, 0) == pid);
8f155917 335
77cfd113 336 safe_close(pair[1]);
832d16a6 337 sd_bus_unref(b);
8f155917
LP
338
339 return 0;
340}