chiark / gitweb /
bus: make system bus kdbus node world-accessible
[elogind.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_bus("deine-mutter", false, &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 }