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