1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
26 #include "alloc-util.h"
27 #include "bus-internal.h"
28 #include "bus-kernel.h"
32 #include "time-util.h"
35 #define MAX_SIZE (2*1024*1024)
37 static usec_t arg_loop_usec
= 100 * USEC_PER_MSEC
;
45 static void server(sd_bus
*b
, size_t *result
) {
49 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
51 r
= sd_bus_process(b
, &m
);
55 assert_se(sd_bus_wait(b
, USEC_INFINITY
) >= 0);
59 if (sd_bus_message_is_method_call(m
, "benchmark.server", "Ping"))
60 assert_se(sd_bus_reply_method_return(m
, NULL
) >= 0);
61 else if (sd_bus_message_is_method_call(m
, "benchmark.server", "Work")) {
65 /* Make sure the mmap is mapped */
66 assert_se(sd_bus_message_read_array(m
, 'y', &p
, &sz
) > 0);
68 r
= sd_bus_reply_method_return(m
, NULL
);
70 } else if (sd_bus_message_is_method_call(m
, "benchmark.server", "Exit")) {
72 assert_se(sd_bus_message_read(m
, "t", &res
) > 0);
77 } else if (!sd_bus_message_is_signal(m
, NULL
, NULL
))
78 assert_not_reached("Unknown method");
82 static void transaction(sd_bus
*b
, size_t sz
, const char *server_name
) {
83 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
86 assert_se(sd_bus_message_new_method_call(b
, &m
, server_name
, "/", "benchmark.server", "Work") >= 0);
87 assert_se(sd_bus_message_append_array_space(m
, 'y', sz
, (void**) &p
) >= 0);
91 assert_se(sd_bus_call(b
, m
, 0, NULL
, &reply
) >= 0);
94 static void client_bisect(const char *address
, const char *server_name
) {
95 _cleanup_bus_message_unref_ sd_bus_message
*x
= NULL
;
96 size_t lsize
, rsize
, csize
;
103 r
= sd_bus_set_address(b
, address
);
109 r
= sd_bus_call_method(b
, server_name
, "/", "benchmark.server", "Ping", NULL
, NULL
, NULL
);
115 printf("SIZE\tCOPY\tMEMFD\n");
119 unsigned n_copying
, n_memfd
;
121 csize
= (lsize
+ rsize
) / 2;
129 printf("%zu\t", csize
);
133 t
= now(CLOCK_MONOTONIC
);
134 for (n_copying
= 0;; n_copying
++) {
135 transaction(b
, csize
, server_name
);
136 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
139 printf("%u\t", (unsigned) ((n_copying
* USEC_PER_SEC
) / arg_loop_usec
));
143 t
= now(CLOCK_MONOTONIC
);
144 for (n_memfd
= 0;; n_memfd
++) {
145 transaction(b
, csize
, server_name
);
146 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
149 printf("%u\n", (unsigned) ((n_memfd
* USEC_PER_SEC
) / arg_loop_usec
));
151 if (n_copying
== n_memfd
)
154 if (n_copying
> n_memfd
)
161 assert_se(sd_bus_message_new_method_call(b
, &x
, server_name
, "/", "benchmark.server", "Exit") >= 0);
162 assert_se(sd_bus_message_append(x
, "t", csize
) >= 0);
163 assert_se(sd_bus_send(b
, x
, NULL
) >= 0);
168 static void client_chart(Type type
, const char *address
, const char *server_name
, int fd
) {
169 _cleanup_bus_message_unref_ sd_bus_message
*x
= NULL
;
177 if (type
== TYPE_DIRECT
) {
178 r
= sd_bus_set_fd(b
, fd
, fd
);
181 r
= sd_bus_set_address(b
, address
);
184 r
= sd_bus_set_bus_client(b
, true);
191 r
= sd_bus_call_method(b
, server_name
, "/", "benchmark.server", "Ping", NULL
, NULL
, NULL
);
196 printf("SIZE\tCOPY\tMEMFD\n");
199 printf("SIZE\tLEGACY\n");
202 printf("SIZE\tDIRECT\n");
206 for (csize
= 1; csize
<= MAX_SIZE
; csize
*= 2) {
208 unsigned n_copying
, n_memfd
;
210 printf("%zu\t", csize
);
212 if (type
== TYPE_KDBUS
) {
215 t
= now(CLOCK_MONOTONIC
);
216 for (n_copying
= 0;; n_copying
++) {
217 transaction(b
, csize
, server_name
);
218 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
222 printf("%u\t", (unsigned) ((n_copying
* USEC_PER_SEC
) / arg_loop_usec
));
227 t
= now(CLOCK_MONOTONIC
);
228 for (n_memfd
= 0;; n_memfd
++) {
229 transaction(b
, csize
, server_name
);
230 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
234 printf("%u\n", (unsigned) ((n_memfd
* USEC_PER_SEC
) / arg_loop_usec
));
238 assert_se(sd_bus_message_new_method_call(b
, &x
, server_name
, "/", "benchmark.server", "Exit") >= 0);
239 assert_se(sd_bus_message_append(x
, "t", csize
) >= 0);
240 assert_se(sd_bus_send(b
, x
, NULL
) >= 0);
245 int main(int argc
, char *argv
[]) {
249 } mode
= MODE_BISECT
;
250 Type type
= TYPE_KDBUS
;
251 int i
, pair
[2] = { -1, -1 };
252 _cleanup_free_
char *name
= NULL
, *bus_name
= NULL
, *address
= NULL
, *server_name
= NULL
;
253 _cleanup_close_
int bus_ref
= -1;
261 for (i
= 1; i
< argc
; i
++) {
262 if (streq(argv
[i
], "chart")) {
265 } else if (streq(argv
[i
], "legacy")) {
268 } else if (streq(argv
[i
], "direct")) {
273 assert_se(parse_sec(argv
[i
], &arg_loop_usec
) >= 0);
276 assert_se(!MODE_BISECT
|| TYPE_KDBUS
);
278 assert_se(arg_loop_usec
> 0);
280 if (type
== TYPE_KDBUS
) {
281 assert_se(asprintf(&name
, "deine-mutter-%u", (unsigned) getpid()) >= 0);
283 bus_ref
= bus_kernel_create_bus(name
, false, &bus_name
);
284 if (bus_ref
== -ENOENT
)
285 exit(EXIT_TEST_SKIP
);
287 assert_se(bus_ref
>= 0);
289 address
= strappend("kernel:path=", bus_name
);
291 } else if (type
== TYPE_LEGACY
) {
294 e
= secure_getenv("DBUS_SESSION_BUS_ADDRESS");
304 if (type
== TYPE_DIRECT
) {
305 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, pair
) >= 0);
307 r
= sd_bus_set_fd(b
, pair
[0], pair
[0]);
310 r
= sd_bus_set_server(b
, true, SD_ID128_NULL
);
313 r
= sd_bus_set_address(b
, address
);
316 r
= sd_bus_set_bus_client(b
, true);
323 if (type
!= TYPE_DIRECT
) {
324 r
= sd_bus_get_unique_name(b
, &unique
);
327 server_name
= strdup(unique
);
328 assert_se(server_name
);
332 setpriority(PRIO_PROCESS
, 0, -19);
340 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t
), &cpuset
);
347 client_bisect(address
, server_name
);
351 client_chart(type
, address
, server_name
, pair
[1]);
360 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t
), &cpuset
);
364 if (mode
== MODE_BISECT
)
365 printf("Copying/memfd are equally fast at %zu bytes\n", result
);
367 assert_se(waitpid(pid
, NULL
, 0) == pid
);