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