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