From 681b638417d041772b8058feb9c0b664656f7afc Mon Sep 17 00:00:00 2001 From: Michal Bloch Date: Fri, 15 Mar 2024 17:38:34 +0100 Subject: [PATCH] kdbus benchmark: measure bandwidth Change-Id: Ie6d7f4dc4d7db5e8de5ccca4ae2c4c6e7c89b275 --- tests/kdbus/kdbus-test.c | 21 +++++-- tests/kdbus/kdbus-test.h | 1 + tests/kdbus/test-benchmark.c | 114 ++++++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 6 deletions(-) diff --git a/tests/kdbus/kdbus-test.c b/tests/kdbus/kdbus-test.c index 058fcb1..37875ef 100644 --- a/tests/kdbus/kdbus-test.c +++ b/tests/kdbus/kdbus-test.c @@ -33,6 +33,7 @@ struct kdbus_test { int (*func)(struct kdbus_test_env *env); unsigned int flags; unsigned timeout; + bool manual_only; }; struct kdbus_test_args { @@ -339,25 +340,33 @@ static const struct kdbus_test tests[] = { }, { .name = "benchmark", - .desc = "benchmark", + .desc = "latency benchmark", .func = kdbus_test_benchmark, .flags = TEST_CREATE_BUS, .timeout = 10, }, { .name = "benchmark-nomemfds", - .desc = "benchmark without using memfds", + .desc = "latency benchmark without using memfds", .func = kdbus_test_benchmark_nomemfds, .flags = TEST_CREATE_BUS, .timeout = 10, }, { .name = "benchmark-uds", - .desc = "benchmark comparison to UDS", + .desc = "latency benchmark comparison to UDS", .func = kdbus_test_benchmark_uds, .flags = TEST_CREATE_BUS, .timeout = 10, }, + { + .name = "benchmark-bandwidth", + .desc = "bandwidth benchmark", + .func = kdbus_test_benchmark_bandwidth, + .flags = TEST_CREATE_BUS, + .timeout = 10, + .manual_only = true, + }, }; #define N_TESTS ((int) (sizeof(tests) / sizeof(tests[0]))) @@ -530,7 +539,11 @@ static wur int start_all_tests(struct kdbus_test_args const *kdbus_args) print(" "); } - ret = test_run_forked(t, kdbus_args, 0); + if (t->manual_only) + ret = TEST_SKIP; + else + ret = test_run_forked(t, kdbus_args, 0); + switch (ret) { case TEST_OK: ok_cnt++; diff --git a/tests/kdbus/kdbus-test.h b/tests/kdbus/kdbus-test.h index def9b7d..2e6bdc4 100644 --- a/tests/kdbus/kdbus-test.h +++ b/tests/kdbus/kdbus-test.h @@ -81,6 +81,7 @@ wur int kdbus_test_activator(struct kdbus_test_env *env); wur int kdbus_test_benchmark(struct kdbus_test_env *env); wur int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env); wur int kdbus_test_benchmark_uds(struct kdbus_test_env *env); +wur int kdbus_test_benchmark_bandwidth(struct kdbus_test_env *env); wur int kdbus_test_bus_make(struct kdbus_test_env *env); wur int kdbus_test_byebye(struct kdbus_test_env *env); wur int kdbus_test_chat(struct kdbus_test_env *env); diff --git a/tests/kdbus/test-benchmark.c b/tests/kdbus/test-benchmark.c index af87d85..51fbcab 100644 --- a/tests/kdbus/test-benchmark.c +++ b/tests/kdbus/test-benchmark.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "kdbus-api.h" @@ -33,10 +34,14 @@ static bool use_memfd = true; /* transmit memfd? */ static bool compare_uds = false; /* unix-socket comparison? */ static bool attach_none = false; /* clear attach-flags? */ +static bool is_bandwidth = false; /* is this a bandwidth test? */ static char *stress_payload; struct stats { - uint64_t count; + _Atomic uint64_t count; + + /* These are for latency measurement, which is + * single-threaded so doesn't need to be atomic */ uint64_t latency_acc; uint64_t latency_low; uint64_t latency_high; @@ -191,7 +196,8 @@ send_echo_request(struct kdbus_conn *conn, void *kdbus_msg, off_t memfd_item_off cmd.msg_address = (uintptr_t)kdbus_msg; ret = kdbus_cmd_send(conn->fd, &cmd); - ASSERT_RETURN_VAL(ret,==,0, ret); + if (!is_bandwidth || ret != -ENOBUFS) // bandwidth test often exhausts buffer space, it's fine + ASSERT_RETURN_VAL(ret,==,0, ret); if (-1 != memfd) CLOSE(memfd); @@ -412,19 +418,122 @@ static wur int benchmark(struct kdbus_test_env *env) return (stats.count > 1) ? TEST_OK : TEST_ERR; } +struct bandwidth_worker_data { + int i; + struct kdbus_test_env *env; +}; + +void *bandwidth_receiver_thread(void *conn) +{ + while (1) { + if (handle_echo_reply((struct kdbus_conn *) conn, 0)) { + // no can do + } + } + + return NULL; +} + +int bandwidth_sender_thread(struct bandwidth_worker_data *data) +{ + struct kdbus_msg *kdbus_msg; + struct kdbus_conn *conn_a, *conn_b; + char name[sizeof SERVICE_NAME + 20]; + + /* I don't know if the order of these matters, I copied it + * from the latency benchmark. It would probably be cleaner + * to let the receiver set itself up otherwise. */ + conn_a = kdbus_hello(data->env->buspath, 0, NULL, 0); + ASSERT_NONZERO(conn_a); + conn_b = kdbus_hello(data->env->buspath, 0, NULL, 0); + ASSERT_NONZERO(conn_b); + ASSERT_ZERO(kdbus_add_match_empty(conn_a)); + ASSERT_ZERO(kdbus_add_match_empty(conn_b)); + snprintf(name, sizeof name, SERVICE_NAME "%d", data->i); + ASSERT_ZERO(kdbus_name_acquire(conn_a, name, NULL)); + ASSERT_ZERO(setup_simple_kdbus_msg(conn_b, conn_a->id, data->env->payload, &kdbus_msg)); + ASSERT_NO_PENDING(conn_a); + + pthread_t p; + pthread_create(&p, NULL, bandwidth_receiver_thread, conn_a); + + while (1) { + if (send_echo_request(conn_b, kdbus_msg, 0)) { + // no can do + } + } + + return TEST_OK; +} + +void *bandwidth_sender_thread_wrap(void *data) +{ + // ASSERT_BLA macros expect the func to return int + bandwidth_sender_thread(data); + return NULL; +} + +static wur int benchmark_bandwidth(struct kdbus_test_env *env) +{ + setlocale(LC_ALL, ""); + + stress_payload = malloc(env->payload); + ASSERT_NONZERO(stress_payload); + for (int i = 0; i < env->payload; i++) + stress_payload[i] = i; + + // A pair consists of a reader and a sender + int proc_pairs = get_nprocs() / 2; + if (proc_pairs <= 1) + proc_pairs = 1; + + while (proc_pairs--) { + struct bandwidth_worker_data* data = malloc(sizeof *data); + data->i = proc_pairs; + data->env = env; + + pthread_t p; + pthread_create(&p, NULL, bandwidth_sender_thread_wrap, data); // sender spawns the reader + } + + sleep(2); // give threads a moment to initialize + reset_stats(); + + while (1) { + const int PERIOD_S = 5; + sleep(PERIOD_S); + uint64_t kilobytes_received = (stats.count * env->payload) / 1024; + kdbus_printf("%llu kB/s\n", kilobytes_received / PERIOD_S); + reset_stats(); + } + + return TEST_OK; +} + wur int kdbus_test_benchmark(struct kdbus_test_env *env) { use_memfd = true; attach_none = false; compare_uds = false; + is_bandwidth = false; return benchmark(env); } +wur int kdbus_test_benchmark_bandwidth(struct kdbus_test_env *env) +{ + use_memfd = false; + attach_none = false; + compare_uds = false; + is_bandwidth = true; + return benchmark_bandwidth(env); +} + wur int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env) { use_memfd = false; attach_none = false; compare_uds = false; + is_bandwidth = false; return benchmark(env); } @@ -433,5 +542,6 @@ wur int kdbus_test_benchmark_uds(struct kdbus_test_env *env) use_memfd = false; attach_none = true; compare_uds = true; + is_bandwidth = false; return benchmark(env); } -- 2.34.1