chiark / gitweb /
bus: rework benchmark test to actually yield useful results
[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 10000
35 #define MAX_SIZE (1*1024*1024)
36
37 static void server(sd_bus *b, size_t *result) {
38         int r;
39
40         for (;;) {
41                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
42
43                 r = sd_bus_process(b, &m);
44                 assert_se(r >= 0);
45
46                 if (r == 0)
47                         assert_se(sd_bus_wait(b, (usec_t) -1) >= 0);
48                 if (!m)
49                         continue;
50
51                 if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping"))
52                         assert_se(sd_bus_reply_method_return(b, m, NULL) >= 0);
53                 else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
54                         const void *p;
55                         size_t sz;
56
57                         /* Make sure the mmap is mapped */
58                         assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
59
60                         assert_se(sd_bus_reply_method_return(b, m, NULL) >= 0);
61                 } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
62                         uint64_t res;
63                         assert_se(sd_bus_message_read(m, "t", &res) > 0);
64
65                         *result = res;
66                         return;
67
68                 } else
69                         assert_not_reached("Unknown method");
70         }
71 }
72
73 static void transaction(sd_bus *b, size_t sz) {
74         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
75         /* size_t psz, i; */
76         uint8_t *p;
77
78         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Work", &m) >= 0);
79         assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
80
81         /* Touch every page */
82         /* psz = page_size(); */
83         /* for (i = 0; i < sz; i += psz) */
84         /*         p[i] = 'X'; */
85
86         assert_se(sd_bus_send_with_reply_and_block(b, m, 0, NULL, &reply) >= 0);
87 }
88
89 static void client(const char *address) {
90         _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
91         size_t lsize, rsize, csize;
92         sd_bus *b;
93         int r;
94
95         r = sd_bus_new(&b);
96         assert_se(r >= 0);
97
98         r = sd_bus_set_address(b, address);
99         assert_se(r >= 0);
100
101         r = sd_bus_start(b);
102         assert_se(r >= 0);
103
104         assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
105
106         lsize = 1;
107         rsize = MAX_SIZE;
108
109         for (;;) {
110                 usec_t copy, memfd, t;
111                 unsigned i;
112
113                 csize = (lsize + rsize) / 2;
114
115                 log_info("Trying size=%zu", csize);
116
117                 if (csize <= lsize)
118                         break;
119
120                 if (csize <= 0)
121                         break;
122
123                 log_info("copying...");
124                 b->use_memfd = 0;
125                 t = now(CLOCK_MONOTONIC);
126                 for (i = 0; i <  N_TRIES; i++)
127                         transaction(b, csize);
128                 copy = (now(CLOCK_MONOTONIC) - t);
129                 log_info("%llu usec per copy transaction", (unsigned long long) (copy / N_TRIES));
130
131                 log_info("sending memfd...");
132                 b->use_memfd = -1;
133                 t = now(CLOCK_MONOTONIC);
134                 for (i = 0; i <  N_TRIES; i++)
135                         transaction(b, csize);
136                 memfd = (now(CLOCK_MONOTONIC) - t);
137                 log_info("%llu usec per memfd transaction", (unsigned long long) (memfd / N_TRIES));
138
139                 if (copy == memfd)
140                         break;
141
142                 if (copy < memfd)
143                         lsize = csize;
144                 else
145                         rsize = csize;
146         }
147
148         assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
149         assert_se(sd_bus_message_append(x, "t", csize) >= 0);
150         assert_se(sd_bus_send(b, x, NULL) >= 0);
151
152         sd_bus_unref(b);
153 }
154
155 int main(int argc, char *argv[]) {
156         _cleanup_free_ char *bus_name = NULL, *address = NULL;
157         _cleanup_close_ int bus_ref = -1;
158         cpu_set_t cpuset;
159         size_t result;
160         sd_bus *b;
161         pid_t pid;
162         int r;
163
164         log_set_max_level(LOG_DEBUG);
165
166         bus_ref = bus_kernel_create("deine-mutter", &bus_name);
167         if (bus_ref == -ENOENT)
168                 exit(EXIT_TEST_SKIP);
169
170         assert_se(bus_ref >= 0);
171
172         address = strappend("kernel:path=", bus_name);
173         assert_se(address);
174
175         r = sd_bus_new(&b);
176         assert_se(r >= 0);
177
178         r = sd_bus_set_address(b, address);
179         assert_se(r >= 0);
180
181         r = sd_bus_start(b);
182         assert_se(r >= 0);
183
184         sync();
185         setpriority(PRIO_PROCESS, 0, -19);
186
187         pid = fork();
188         assert_se(pid >= 0);
189
190         if (pid == 0) {
191                 CPU_ZERO(&cpuset);
192                 CPU_SET(0, &cpuset);
193                 pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
194
195                 close_nointr_nofail(bus_ref);
196                 sd_bus_unref(b);
197
198                 client(address);
199                 _exit(0);
200         }
201
202         CPU_ZERO(&cpuset);
203         CPU_SET(1, &cpuset);
204         pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
205
206         server(b, &result);
207
208         log_info("Copying/memfd are equally fast at %zu", result);
209
210         assert_se(waitpid(pid, NULL, 0) == pid);
211
212         sd_bus_unref(b);
213
214         return 0;
215 }