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