chiark / gitweb /
sd-bus: make sure we properly handle NULL callback functions
[elogind.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 (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, &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 }