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