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