chiark / gitweb /
403af885c3d44c18c281438d4b714e210e170fa2
[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
28 #include "sd-bus.h"
29 #include "bus-message.h"
30 #include "bus-error.h"
31 #include "bus-kernel.h"
32 #include "bus-internal.h"
33
34 #define N_TRIES 500
35 #define MAX_SIZE (5*1024*1024)
36
37 static void server(sd_bus *b, usec_t *result) {
38         usec_t x = 0;
39         int r;
40
41         for (;;) {
42                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
43
44                 r = sd_bus_process(b, &m);
45                 assert_se(r >= 0);
46
47                 if (r == 0)
48                         assert_se(sd_bus_wait(b, (usec_t) -1) >= 0);
49
50                 if (!m)
51                         continue;
52
53                 /* log_error("huhu %s from %s", sd_bus_message_get_member(m), sd_bus_message_get_sender(m)); */
54
55                 if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
56                         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
57                         size_t i, sz;
58                         char *q;
59                         const char *p;
60
61                         assert_se(sd_bus_message_read_array(m, 'y', (const void**) &p, &sz) > 0);
62                         assert_se(sd_bus_message_new_method_return(b, m, &reply) >= 0);
63                         assert_se(sd_bus_message_append_array_space(reply, 'y', sz, (void**) &q) >= 0);
64
65                         x = now(CLOCK_MONOTONIC);
66
67                         for (i = 0; i < sz; i++)
68                                 q[i] = toupper(p[i]);
69
70                         x = now(CLOCK_MONOTONIC) - x;
71
72                         assert_se(sd_bus_send(b, reply, NULL) >= 0);
73                 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
74                         usec_t t;
75
76                         assert_se(sd_bus_message_read(m, "t", &t) > 0);
77                         assert_se(t >= x);
78                         *result = t - x;
79                         return;
80
81                 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping")) {
82                         assert_se(sd_bus_reply_method_return(b, m, "y", 1) >= 0);
83                 } else
84                         assert_not_reached("Unknown method");
85         }
86 }
87
88 static void client(sd_bus *b, size_t sz) {
89         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
90         char *p;
91         const char *q;
92         usec_t t;
93         size_t l, i;
94
95         assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
96
97         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Work", &m) >= 0);
98         assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
99
100         for (i = 0; i < sz; i++)
101                 p[i] = 'a' + (char) (i % 26);
102
103         t = now(CLOCK_MONOTONIC);
104         assert_se(sd_bus_send_with_reply_and_block(b, m, 0, NULL, &reply) >= 0);
105         t = now(CLOCK_MONOTONIC) - t;
106
107         assert_se(sd_bus_message_read_array(reply, 'y', (const void**) &q, &l) > 0);
108         assert_se(l == sz);
109
110         for (i = 0; i < sz; i++) {
111                 assert_se(q[i] == 'A' + (char) (i % 26));
112         }
113
114         sd_bus_message_unref(m);
115
116         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &m) >= 0);
117         assert_se(sd_bus_message_append(m, "t", t) >= 0);
118         assert_se(sd_bus_send(b, m, NULL) >= 0);
119 }
120
121 static void run_benchmark(size_t sz, bool force_copy, usec_t *result) {
122
123         _cleanup_close_ int bus_ref = -1;
124         _cleanup_free_ char *bus_name = NULL, *address = NULL;
125         sd_bus *b;
126         int r;
127         pid_t pid;
128
129         bus_ref = bus_kernel_create("deine-mutter", &bus_name);
130         if (bus_ref == -ENOENT)
131                 exit(EXIT_TEST_SKIP);
132
133         assert_se(bus_ref >= 0);
134
135         address = strappend("kernel:path=", bus_name);
136         assert_se(address);
137
138         r = sd_bus_new(&b);
139         assert_se(r >= 0);
140
141         b->use_memfd = force_copy ? 0 : -1;
142
143         r = sd_bus_set_address(b, address);
144         assert_se(r >= 0);
145
146         r = sd_bus_start(b);
147         assert_se(r >= 0);
148
149         pid = fork();
150         assert_se(pid >= 0);
151
152         if (pid == 0) {
153                 close_nointr_nofail(bus_ref);
154                 sd_bus_unref(b);
155
156                 r = sd_bus_new(&b);
157                 assert_se(r >= 0);
158
159                 b->use_memfd = force_copy ? 0 : -1;
160
161                 r = sd_bus_set_address(b, address);
162                 assert_se(r >= 0);
163
164                 r = sd_bus_start(b);
165                 assert_se(r >= 0);
166
167                 client(b, sz);
168                 _exit(0);
169         }
170
171         server(b, result);
172         sd_bus_unref(b);
173
174         assert_se(waitpid(pid, NULL, 0) == pid);
175 }
176
177 int main(int argc, char *argv[]) {
178         size_t lsize, rsize, csize;
179
180         log_set_max_level(LOG_DEBUG);
181
182         lsize = 1;
183         rsize = MAX_SIZE;
184
185         for (;;) {
186                 usec_t copy = 0, memfd = 0;
187                 unsigned i;
188
189                 csize = (lsize + rsize) / 2;
190
191                 log_info("Trying size=%zu", csize);
192
193                 if (csize <= lsize)
194                         break;
195
196                 for (i = 0; i <  N_TRIES; i++) {
197                         usec_t t;
198
199                         run_benchmark(csize, true, &t);
200                         copy += t;
201                 }
202
203                 for (i = 0; i < N_TRIES; i++) {
204                         usec_t t;
205
206                         run_benchmark(csize, false, &t);
207                         memfd += t;
208                 }
209
210                 copy /= N_TRIES;
211                 memfd /= N_TRIES;
212
213                 if (copy == memfd)
214                         break;
215
216                 if (copy < memfd)
217                         lsize = csize;
218                 else
219                         rsize = csize;
220         }
221
222         log_info("Copying/memfd are equally fast at %zu", csize);
223
224         return 0;
225 }