chiark / gitweb /
Fix write-only use of a few variables
[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
35 #define MAX_SIZE (4*1024*1024)
36
37 static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
38
39 static void server(sd_bus *b, size_t *result) {
40         int r;
41
42         for (;;) {
43                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
44
45                 r = sd_bus_process(b, &m);
46                 assert_se(r >= 0);
47
48                 if (r == 0)
49                         assert_se(sd_bus_wait(b, (usec_t) -1) >= 0);
50                 if (!m)
51                         continue;
52
53                 if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping"))
54                         assert_se(sd_bus_reply_method_return(b, m, NULL) >= 0);
55                 else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
56                         const void *p;
57                         size_t sz;
58
59                         /* Make sure the mmap is mapped */
60                         assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
61
62                         assert_se(sd_bus_reply_method_return(b, m, NULL) >= 0);
63                 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
64                         uint64_t res;
65                         assert_se(sd_bus_message_read(m, "t", &res) > 0);
66
67                         *result = res;
68                         return;
69
70                 } else
71                         assert_not_reached("Unknown method");
72         }
73 }
74
75 static void transaction(sd_bus *b, size_t sz) {
76         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
77         uint8_t *p;
78
79         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Work", &m) >= 0);
80         assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
81
82         memset(p, 0x80, sz);
83
84         assert_se(sd_bus_send_with_reply_and_block(b, m, 0, NULL, &reply) >= 0);
85 }
86
87 static void client_bisect(const char *address) {
88         _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
89         size_t lsize, rsize, csize;
90         sd_bus *b;
91         int r;
92
93         r = sd_bus_new(&b);
94         assert_se(r >= 0);
95
96         r = sd_bus_set_address(b, address);
97         assert_se(r >= 0);
98
99         r = sd_bus_start(b);
100         assert_se(r >= 0);
101
102         assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
103
104         lsize = 1;
105         rsize = MAX_SIZE;
106
107         printf("SIZE\tCOPY\tMEMFD\n");
108
109         for (;;) {
110                 usec_t t;
111                 unsigned n_copying, n_memfd;
112
113                 csize = (lsize + rsize) / 2;
114
115                 if (csize <= lsize)
116                         break;
117
118                 if (csize <= 0)
119                         break;
120
121                 printf("%zu\t", csize);
122
123                 b->use_memfd = 0;
124
125                 t = now(CLOCK_MONOTONIC);
126                 for (n_copying = 0;; n_copying++) {
127                         transaction(b, csize);
128                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
129                                 break;
130                 }
131                 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
132
133                 b->use_memfd = -1;
134
135                 t = now(CLOCK_MONOTONIC);
136                 for (n_memfd = 0;; n_memfd++) {
137                         transaction(b, csize);
138                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
139                                 break;
140                 }
141                 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
142
143                 if (n_copying == n_memfd)
144                         break;
145
146                 if (n_copying > n_memfd)
147                         lsize = csize;
148                 else
149                         rsize = csize;
150         }
151
152         b->use_memfd = 1;
153         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
154         assert_se(sd_bus_message_append(x, "t", csize) >= 0);
155         assert_se(sd_bus_send(b, x, NULL) >= 0);
156
157         sd_bus_unref(b);
158 }
159
160 static void client_chart(const char *address) {
161         _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
162         size_t csize;
163         sd_bus *b;
164         int r;
165
166         r = sd_bus_new(&b);
167         assert_se(r >= 0);
168
169         r = sd_bus_set_address(b, address);
170         assert_se(r >= 0);
171
172         r = sd_bus_start(b);
173         assert_se(r >= 0);
174
175         assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
176
177         printf("SIZE\tCOPY\tMEMFD\n");
178
179         for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
180                 usec_t t;
181                 unsigned n_copying, n_memfd;
182
183                 printf("%zu\t", csize);
184
185                 b->use_memfd = 0;
186
187                 t = now(CLOCK_MONOTONIC);
188                 for (n_copying = 0;; n_copying++) {
189                         transaction(b, csize);
190                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
191                                 break;
192                 }
193
194                 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
195
196                 b->use_memfd = -1;
197
198                 t = now(CLOCK_MONOTONIC);
199                 for (n_memfd = 0;; n_memfd++) {
200                         transaction(b, csize);
201                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
202                                 break;
203                 }
204
205                 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
206         }
207
208         b->use_memfd = 1;
209         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
210         assert_se(sd_bus_message_append(x, "t", csize) >= 0);
211         assert_se(sd_bus_send(b, x, NULL) >= 0);
212
213         sd_bus_unref(b);
214 }
215
216 int main(int argc, char *argv[]) {
217         enum {
218                 MODE_BISECT,
219                 MODE_CHART,
220         } mode = MODE_BISECT;
221         int i;
222         _cleanup_free_ char *bus_name = NULL, *address = NULL;
223         _cleanup_close_ int bus_ref = -1;
224         cpu_set_t cpuset;
225         size_t result;
226         sd_bus *b;
227         pid_t pid;
228         int r;
229
230         log_set_max_level(LOG_DEBUG);
231
232         for (i = 1; i < argc; i++) {
233                 if (streq(argv[i], "chart")) {
234                         mode = MODE_CHART;
235                         continue;
236                 }
237
238                 assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
239         }
240
241         assert_se(arg_loop_usec > 0);
242
243         bus_ref = bus_kernel_create("deine-mutter", &bus_name);
244         if (bus_ref == -ENOENT)
245                 exit(EXIT_TEST_SKIP);
246
247         assert_se(bus_ref >= 0);
248
249         address = strappend("kernel:path=", bus_name);
250         assert_se(address);
251
252         r = sd_bus_new(&b);
253         assert_se(r >= 0);
254
255         r = sd_bus_set_address(b, address);
256         assert_se(r >= 0);
257
258         r = sd_bus_start(b);
259         assert_se(r >= 0);
260
261         sync();
262         setpriority(PRIO_PROCESS, 0, -19);
263
264         pid = fork();
265         assert_se(pid >= 0);
266
267         if (pid == 0) {
268                 CPU_ZERO(&cpuset);
269                 CPU_SET(0, &cpuset);
270                 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
271
272                 close_nointr_nofail(bus_ref);
273                 sd_bus_unref(b);
274
275                 switch (mode) {
276                 case MODE_BISECT:
277                         client_bisect(address);
278                         break;
279
280                 case MODE_CHART:
281                         client_chart(address);
282                         break;
283                 }
284
285                 _exit(0);
286         }
287
288         CPU_ZERO(&cpuset);
289         CPU_SET(1, &cpuset);
290         pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
291
292         server(b, &result);
293
294         if (mode == MODE_BISECT)
295                 printf("Copying/memfd are equally fast at %zu bytes\n", result);
296
297         assert_se(waitpid(pid, NULL, 0) == pid);
298
299         sd_bus_unref(b);
300
301         return 0;
302 }