chiark / gitweb /
Prep v220: Use new cgroups functions
[elogind.git] / src / libelogind / 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                         r = sd_bus_reply_method_return(m, NULL);
60                         assert_se(r >= 0);
61                 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
62                         uint64_t res;
63                         assert_se(sd_bus_message_read(m, "t", &res) > 0);
64
65                         *result = res;
66                         return;
67
68                 } else
69                         assert_not_reached("Unknown method");
70         }
71 }
72
73 static void transaction(sd_bus *b, size_t sz, const char *server_name) {
74         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
75         uint8_t *p;
76
77         assert_se(sd_bus_message_new_method_call(b, &m, server_name, "/", "benchmark.server", "Work") >= 0);
78         assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
79
80         memset(p, 0x80, sz);
81
82         assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0);
83 }
84
85 static void client_bisect(const char *address, const char *server_name) {
86         _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
87         size_t lsize, rsize, csize;
88         sd_bus *b;
89         int r;
90
91         r = sd_bus_new(&b);
92         assert_se(r >= 0);
93
94         r = sd_bus_set_address(b, address);
95         assert_se(r >= 0);
96
97         r = sd_bus_start(b);
98         assert_se(r >= 0);
99
100         r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
101         assert_se(r >= 0);
102
103         lsize = 1;
104         rsize = MAX_SIZE;
105
106         printf("SIZE\tCOPY\tMEMFD\n");
107
108         for (;;) {
109                 usec_t t;
110                 unsigned n_copying, n_memfd;
111
112                 csize = (lsize + rsize) / 2;
113
114                 if (csize <= lsize)
115                         break;
116
117                 if (csize <= 0)
118                         break;
119
120                 printf("%zu\t", csize);
121
122                 b->use_memfd = 0;
123
124                 t = now(CLOCK_MONOTONIC);
125                 for (n_copying = 0;; n_copying++) {
126                         transaction(b, csize, server_name);
127                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
128                                 break;
129                 }
130                 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
131
132                 b->use_memfd = -1;
133
134                 t = now(CLOCK_MONOTONIC);
135                 for (n_memfd = 0;; n_memfd++) {
136                         transaction(b, csize, server_name);
137                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
138                                 break;
139                 }
140                 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
141
142                 if (n_copying == n_memfd)
143                         break;
144
145                 if (n_copying > n_memfd)
146                         lsize = csize;
147                 else
148                         rsize = csize;
149         }
150
151         b->use_memfd = 1;
152         assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
153         assert_se(sd_bus_message_append(x, "t", csize) >= 0);
154         assert_se(sd_bus_send(b, x, NULL) >= 0);
155
156         sd_bus_unref(b);
157 }
158
159 static void client_chart(const char *address, const char *server_name) {
160         _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
161         size_t csize;
162         sd_bus *b;
163         int r;
164
165         r = sd_bus_new(&b);
166         assert_se(r >= 0);
167
168         r = sd_bus_set_address(b, address);
169         assert_se(r >= 0);
170
171         r = sd_bus_start(b);
172         assert_se(r >= 0);
173
174         assert_se(sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
175
176         printf("SIZE\tCOPY\tMEMFD\n");
177
178         for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
179                 usec_t t;
180                 unsigned n_copying, n_memfd;
181
182                 printf("%zu\t", csize);
183
184                 b->use_memfd = 0;
185
186                 t = now(CLOCK_MONOTONIC);
187                 for (n_copying = 0;; n_copying++) {
188                         transaction(b, csize, server_name);
189                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
190                                 break;
191                 }
192
193                 printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
194
195                 b->use_memfd = -1;
196
197                 t = now(CLOCK_MONOTONIC);
198                 for (n_memfd = 0;; n_memfd++) {
199                         transaction(b, csize, server_name);
200                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
201                                 break;
202                 }
203
204                 printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
205         }
206
207         b->use_memfd = 1;
208         assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
209         assert_se(sd_bus_message_append(x, "t", csize) >= 0);
210         assert_se(sd_bus_send(b, x, NULL) >= 0);
211
212         sd_bus_unref(b);
213 }
214
215 int main(int argc, char *argv[]) {
216         enum {
217                 MODE_BISECT,
218                 MODE_CHART,
219         } mode = MODE_BISECT;
220         int i;
221         _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *server_name = NULL;
222         _cleanup_close_ int bus_ref = -1;
223         const char *unique;
224         cpu_set_t cpuset;
225         size_t result;
226         sd_bus *b;
227         pid_t pid;
228         int r;
229
230         for (i = 1; i < argc; i++) {
231                 if (streq(argv[i], "chart")) {
232                         mode = MODE_CHART;
233                         continue;
234                 }
235
236                 assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
237         }
238
239         assert_se(arg_loop_usec > 0);
240
241         assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
242
243         bus_ref = bus_kernel_create_bus(name, false, &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         r = sd_bus_get_unique_name(b, &unique);
262         assert_se(r >= 0);
263
264         server_name = strdup(unique);
265         assert_se(server_name);
266
267         sync();
268         setpriority(PRIO_PROCESS, 0, -19);
269
270         pid = fork();
271         assert_se(pid >= 0);
272
273         if (pid == 0) {
274                 CPU_ZERO(&cpuset);
275                 CPU_SET(0, &cpuset);
276                 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
277
278                 safe_close(bus_ref);
279                 sd_bus_unref(b);
280
281                 switch (mode) {
282                 case MODE_BISECT:
283                         client_bisect(address, server_name);
284                         break;
285
286                 case MODE_CHART:
287                         client_chart(address, server_name);
288                         break;
289                 }
290
291                 _exit(0);
292         }
293
294         CPU_ZERO(&cpuset);
295         CPU_SET(1, &cpuset);
296         pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
297
298         server(b, &result);
299
300         if (mode == MODE_BISECT)
301                 printf("Copying/memfd are equally fast at %zu bytes\n", result);
302
303         assert_se(waitpid(pid, NULL, 0) == pid);
304
305         sd_bus_unref(b);
306
307         return 0;
308 }