chiark / gitweb /
e2a872c6c5f09c7ed1b08961bb6af566db14ba6f
[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 (1*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         /* size_t psz, i; */
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         /* Touch every page */
84         /* psz = page_size(); */
85         /* for (i = 0; i < sz; i += psz) */
86         /*         p[i] = 'X'; */
87
88         assert_se(sd_bus_send_with_reply_and_block(b, m, 0, NULL, &reply) >= 0);
89 }
90
91 static void client(const char *address) {
92         _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
93         size_t lsize, rsize, csize;
94         sd_bus *b;
95         int r;
96
97         r = sd_bus_new(&b);
98         assert_se(r >= 0);
99
100         r = sd_bus_set_address(b, address);
101         assert_se(r >= 0);
102
103         r = sd_bus_start(b);
104         assert_se(r >= 0);
105
106         assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
107
108         lsize = 1;
109         rsize = MAX_SIZE;
110
111         for (;;) {
112                 usec_t t;
113                 unsigned n_copying, n_memfd;
114
115                 csize = (lsize + rsize) / 2;
116
117                 log_info("Trying size=%zu", csize);
118
119                 if (csize <= lsize)
120                         break;
121
122                 if (csize <= 0)
123                         break;
124
125                 log_info("copying...");
126                 b->use_memfd = 0;
127
128                 t = now(CLOCK_MONOTONIC);
129                 for (n_copying = 0;; n_copying++) {
130                         transaction(b, csize);
131                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
132                                 break;
133                 }
134
135                 log_info("%u copy transactions per second", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
136
137                 log_info("sending memfd...");
138                 b->use_memfd = -1;
139
140                 t = now(CLOCK_MONOTONIC);
141                 for (n_memfd = 0;; n_memfd++) {
142                         transaction(b, csize);
143                         if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
144                                 break;
145                 }
146
147                 log_info("%u memfd transactions per second", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
148
149                 if (n_copying == n_memfd)
150                         break;
151
152                 if (n_copying > n_memfd)
153                         lsize = csize;
154                 else
155                         rsize = csize;
156         }
157
158         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
159         assert_se(sd_bus_message_append(x, "t", csize) >= 0);
160         assert_se(sd_bus_send(b, x, NULL) >= 0);
161
162         sd_bus_unref(b);
163 }
164
165 int main(int argc, char *argv[]) {
166         _cleanup_free_ char *bus_name = NULL, *address = NULL;
167         _cleanup_close_ int bus_ref = -1;
168         cpu_set_t cpuset;
169         size_t result;
170         sd_bus *b;
171         pid_t pid;
172         int r;
173
174         log_set_max_level(LOG_DEBUG);
175
176         if (argc > 1)
177                 assert_se(parse_sec(argv[1], &arg_loop_usec) >= 0);
178
179         assert_se(arg_loop_usec > 0);
180
181         bus_ref = bus_kernel_create("deine-mutter", &bus_name);
182         if (bus_ref == -ENOENT)
183                 exit(EXIT_TEST_SKIP);
184
185         assert_se(bus_ref >= 0);
186
187         address = strappend("kernel:path=", bus_name);
188         assert_se(address);
189
190         r = sd_bus_new(&b);
191         assert_se(r >= 0);
192
193         r = sd_bus_set_address(b, address);
194         assert_se(r >= 0);
195
196         r = sd_bus_start(b);
197         assert_se(r >= 0);
198
199         sync();
200         setpriority(PRIO_PROCESS, 0, -19);
201
202         pid = fork();
203         assert_se(pid >= 0);
204
205         if (pid == 0) {
206                 CPU_ZERO(&cpuset);
207                 CPU_SET(0, &cpuset);
208                 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
209
210                 close_nointr_nofail(bus_ref);
211                 sd_bus_unref(b);
212
213                 client(address);
214                 _exit(0);
215         }
216
217         CPU_ZERO(&cpuset);
218         CPU_SET(1, &cpuset);
219         pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
220
221         server(b, &result);
222
223         log_info("Copying/memfd are equally fast at %zu", result);
224
225         assert_se(waitpid(pid, NULL, 0) == pid);
226
227         sd_bus_unref(b);
228
229         return 0;
230 }