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 "time-util.h"
29 #include "bus-kernel.h"
30 #include "bus-internal.h"
33 #define MAX_SIZE (2*1024*1024)
35 static usec_t arg_loop_usec
= 100 * USEC_PER_MSEC
;
43 static void server(sd_bus
*b
, size_t *result
) {
47 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
49 r
= sd_bus_process(b
, &m
);
53 assert_se(sd_bus_wait(b
, USEC_INFINITY
) >= 0);
57 if (sd_bus_message_is_method_call(m
, "benchmark.server", "Ping"))
58 assert_se(sd_bus_reply_method_return(m
, NULL
) >= 0);
59 else if (sd_bus_message_is_method_call(m
, "benchmark.server", "Work")) {
63 /* Make sure the mmap is mapped */
64 assert_se(sd_bus_message_read_array(m
, 'y', &p
, &sz
) > 0);
66 r
= sd_bus_reply_method_return(m
, NULL
);
68 } else if (sd_bus_message_is_method_call(m
, "benchmark.server", "Exit")) {
70 assert_se(sd_bus_message_read(m
, "t", &res
) > 0);
75 } else if (!sd_bus_message_is_signal(m
, NULL
, NULL
))
76 assert_not_reached("Unknown method");
80 static void transaction(sd_bus
*b
, size_t sz
, const char *server_name
) {
81 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
84 assert_se(sd_bus_message_new_method_call(b
, &m
, server_name
, "/", "benchmark.server", "Work") >= 0);
85 assert_se(sd_bus_message_append_array_space(m
, 'y', sz
, (void**) &p
) >= 0);
89 assert_se(sd_bus_call(b
, m
, 0, NULL
, &reply
) >= 0);
92 static void client_bisect(const char *address
, const char *server_name
) {
93 _cleanup_bus_message_unref_ sd_bus_message
*x
= NULL
;
94 size_t lsize
, rsize
, csize
;
101 r
= sd_bus_set_address(b
, address
);
107 r
= sd_bus_call_method(b
, server_name
, "/", "benchmark.server", "Ping", NULL
, NULL
, NULL
);
113 printf("SIZE\tCOPY\tMEMFD\n");
117 unsigned n_copying
, n_memfd
;
119 csize
= (lsize
+ rsize
) / 2;
127 printf("%zu\t", csize
);
131 t
= now(CLOCK_MONOTONIC
);
132 for (n_copying
= 0;; n_copying
++) {
133 transaction(b
, csize
, server_name
);
134 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
137 printf("%u\t", (unsigned) ((n_copying
* USEC_PER_SEC
) / arg_loop_usec
));
141 t
= now(CLOCK_MONOTONIC
);
142 for (n_memfd
= 0;; n_memfd
++) {
143 transaction(b
, csize
, server_name
);
144 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
147 printf("%u\n", (unsigned) ((n_memfd
* USEC_PER_SEC
) / arg_loop_usec
));
149 if (n_copying
== n_memfd
)
152 if (n_copying
> n_memfd
)
159 assert_se(sd_bus_message_new_method_call(b
, &x
, server_name
, "/", "benchmark.server", "Exit") >= 0);
160 assert_se(sd_bus_message_append(x
, "t", csize
) >= 0);
161 assert_se(sd_bus_send(b
, x
, NULL
) >= 0);
166 static void client_chart(Type type
, const char *address
, const char *server_name
, int fd
) {
167 _cleanup_bus_message_unref_ sd_bus_message
*x
= NULL
;
175 if (type
== TYPE_DIRECT
) {
176 r
= sd_bus_set_fd(b
, fd
, fd
);
179 r
= sd_bus_set_address(b
, address
);
182 r
= sd_bus_set_bus_client(b
, true);
189 r
= sd_bus_call_method(b
, server_name
, "/", "benchmark.server", "Ping", NULL
, NULL
, NULL
);
194 printf("SIZE\tCOPY\tMEMFD\n");
197 printf("SIZE\tLEGACY\n");
200 printf("SIZE\tDIRECT\n");
204 for (csize
= 1; csize
<= MAX_SIZE
; csize
*= 2) {
206 unsigned n_copying
, n_memfd
;
208 printf("%zu\t", csize
);
210 if (type
== TYPE_KDBUS
) {
213 t
= now(CLOCK_MONOTONIC
);
214 for (n_copying
= 0;; n_copying
++) {
215 transaction(b
, csize
, server_name
);
216 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
220 printf("%u\t", (unsigned) ((n_copying
* USEC_PER_SEC
) / arg_loop_usec
));
225 t
= now(CLOCK_MONOTONIC
);
226 for (n_memfd
= 0;; n_memfd
++) {
227 transaction(b
, csize
, server_name
);
228 if (now(CLOCK_MONOTONIC
) >= t
+ arg_loop_usec
)
232 printf("%u\n", (unsigned) ((n_memfd
* USEC_PER_SEC
) / arg_loop_usec
));
236 assert_se(sd_bus_message_new_method_call(b
, &x
, server_name
, "/", "benchmark.server", "Exit") >= 0);
237 assert_se(sd_bus_message_append(x
, "t", csize
) >= 0);
238 assert_se(sd_bus_send(b
, x
, NULL
) >= 0);
243 int main(int argc
, char *argv
[]) {
247 } mode
= MODE_BISECT
;
248 Type type
= TYPE_KDBUS
;
249 int i
, pair
[2] = { -1, -1 };
250 _cleanup_free_
char *name
= NULL
, *bus_name
= NULL
, *address
= NULL
, *server_name
= NULL
;
251 _cleanup_close_
int bus_ref
= -1;
259 for (i
= 1; i
< argc
; i
++) {
260 if (streq(argv
[i
], "chart")) {
263 } else if (streq(argv
[i
], "legacy")) {
266 } else if (streq(argv
[i
], "direct")) {
271 assert_se(parse_sec(argv
[i
], &arg_loop_usec
) >= 0);
274 assert_se(!MODE_BISECT
|| TYPE_KDBUS
);
276 assert_se(arg_loop_usec
> 0);
278 if (type
== TYPE_KDBUS
) {
279 assert_se(asprintf(&name
, "deine-mutter-%u", (unsigned) getpid()) >= 0);
281 bus_ref
= bus_kernel_create_bus(name
, false, &bus_name
);
282 if (bus_ref
== -ENOENT
)
283 exit(EXIT_TEST_SKIP
);
285 assert_se(bus_ref
>= 0);
287 address
= strappend("kernel:path=", bus_name
);
289 } else if (type
== TYPE_LEGACY
) {
292 e
= secure_getenv("DBUS_SESSION_BUS_ADDRESS");
302 if (type
== TYPE_DIRECT
) {
303 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, pair
) >= 0);
305 r
= sd_bus_set_fd(b
, pair
[0], pair
[0]);
308 r
= sd_bus_set_server(b
, true, SD_ID128_NULL
);
311 r
= sd_bus_set_address(b
, address
);
314 r
= sd_bus_set_bus_client(b
, true);
321 if (type
!= TYPE_DIRECT
) {
322 r
= sd_bus_get_unique_name(b
, &unique
);
325 server_name
= strdup(unique
);
326 assert_se(server_name
);
330 setpriority(PRIO_PROCESS
, 0, -19);
338 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t
), &cpuset
);
345 client_bisect(address
, server_name
);
349 client_chart(type
, address
, server_name
, pair
[1]);
358 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t
), &cpuset
);
362 if (mode
== MODE_BISECT
)
363 printf("Copying/memfd are equally fast at %zu bytes\n", result
);
365 assert_se(waitpid(pid
, NULL
, 0) == pid
);