kdbus benchmark: measure bandwidth 87/308087/3
authorMichal Bloch <m.bloch@samsung.com>
Fri, 15 Mar 2024 16:38:34 +0000 (17:38 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Tue, 26 Mar 2024 15:52:02 +0000 (16:52 +0100)
Change-Id: Ie6d7f4dc4d7db5e8de5ccca4ae2c4c6e7c89b275

tests/kdbus/kdbus-test.c
tests/kdbus/kdbus-test.h
tests/kdbus/test-benchmark.c

index 058fcb105efd86f9ed12e772b7205546458ec393..37875ef50648224a3e9eb3c88df53d4c341141bc 100644 (file)
@@ -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++;
index def9b7d9cbdce65587489c0f92a89eee3a711dda..2e6bdc4c75060739b0b8fdc5f3a1046ddc92dbd3 100644 (file)
@@ -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);
index af87d85e2ff62e779d200d7ec7778f4e46f843ae..51fbcab7e239f23f72436202dbc7f801ad74a42e 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/time.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
+#include <sys/sysinfo.h>
 #include <math.h>
 
 #include "kdbus-api.h"
 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);
 }