]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-kernel-benchmark.c
tmpfiles: accurately report creation results
[thirdparty/systemd.git] / src / libsystemd / sd-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 (2*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_INFINITY) >= 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, &m, ":1.1", "/", "benchmark.server", "Work") >= 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, &x, ":1.1", "/", "benchmark.server", "Exit") >= 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, &x, ":1.1", "/", "benchmark.server", "Exit") >= 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 *name = NULL, *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 assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
243
244 bus_ref = bus_kernel_create_bus(name, false, &bus_name);
245 if (bus_ref == -ENOENT)
246 exit(EXIT_TEST_SKIP);
247
248 assert_se(bus_ref >= 0);
249
250 address = strappend("kernel:path=", bus_name);
251 assert_se(address);
252
253 r = sd_bus_new(&b);
254 assert_se(r >= 0);
255
256 r = sd_bus_set_address(b, address);
257 assert_se(r >= 0);
258
259 r = sd_bus_start(b);
260 assert_se(r >= 0);
261
262 sync();
263 setpriority(PRIO_PROCESS, 0, -19);
264
265 pid = fork();
266 assert_se(pid >= 0);
267
268 if (pid == 0) {
269 CPU_ZERO(&cpuset);
270 CPU_SET(0, &cpuset);
271 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
272
273 safe_close(bus_ref);
274 sd_bus_unref(b);
275
276 switch (mode) {
277 case MODE_BISECT:
278 client_bisect(address);
279 break;
280
281 case MODE_CHART:
282 client_chart(address);
283 break;
284 }
285
286 _exit(0);
287 }
288
289 CPU_ZERO(&cpuset);
290 CPU_SET(1, &cpuset);
291 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
292
293 server(b, &result);
294
295 if (mode == MODE_BISECT)
296 printf("Copying/memfd are equally fast at %zu bytes\n", result);
297
298 assert_se(waitpid(pid, NULL, 0) == pid);
299
300 sd_bus_unref(b);
301
302 return 0;
303 }