test: beef up benchmark
authorDavid Herrmann <dh.herrmann@gmail.com>
Thu, 2 Oct 2014 08:58:43 +0000 (10:58 +0200)
committerDavid Herrmann <dh.herrmann@gmail.com>
Thu, 2 Oct 2014 08:58:43 +0000 (10:58 +0200)
Make some adjustments to the kdbus benchmark:
 * use CLOCK_THREAD_CPUTIME_ID
 * use nano-second precision
 * make memfd-usage optional
 * add UDS comparison

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
test/test-benchmark.c

index 84dfadfc73dc336de7bb9aae6f8b5fcd9fa7b8e9..82fe038fbe0a5f35a5d8ba51b52fa7e2b225a14b 100644 (file)
@@ -2,6 +2,7 @@
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
+#include <locale.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <unistd.h>
@@ -13,6 +14,7 @@
 #include <sys/time.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/socket.h>
 
 #include "kdbus-test.h"
 #include "kdbus-util.h"
@@ -20,6 +22,8 @@
 
 #define SERVICE_NAME "foo.bar.echo"
 
+static const bool use_memfd = true;            /* transmit memfd? */
+static const bool compare_uds = false;         /* unix-socket comparison? */
 static char stress_payload[8192];
 
 struct stats {
@@ -31,14 +35,12 @@ struct stats {
 
 static struct stats stats;
 
-static uint64_t
-timeval_diff(const struct timeval *hi, const struct timeval *lo)
+static uint64_t now(void)
 {
-       struct timeval r;
+       struct timespec spec;
 
-       timersub(hi, lo, &r);
-
-       return (uint64_t) (r.tv_sec * 1000000ULL) + (uint64_t) r.tv_usec;
+       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &spec);
+       return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec;
 }
 
 static void reset_stats(void)
@@ -49,10 +51,11 @@ static void reset_stats(void)
        stats.latency_high = 0;
 }
 
-static void dump_stats(void)
+static void dump_stats(bool is_uds)
 {
        if (stats.count > 0) {
-               kdbus_printf("stats: %llu packets processed, latency (usecs) min/max/avg %llu/%llu/%llu\n",
+               kdbus_printf("stats %s: %'llu packets processed, latency (nsecs) min/max/avg %'7llu // %'7llu // %'7llu\n",
+                            is_uds ? " (UNIX)" : "(KDBUS)",
                             (unsigned long long) stats.count,
                             (unsigned long long) stats.latency_low,
                             (unsigned long long) stats.latency_high,
@@ -62,13 +65,11 @@ static void dump_stats(void)
        }
 }
 
-static void add_stats(const struct timeval *tv)
+static void add_stats(uint64_t prev)
 {
-       struct timeval now;
        uint64_t diff;
 
-       gettimeofday(&now, NULL);
-       diff = timeval_diff(&now, tv);
+       diff = now() - prev;
 
        stats.count++;
        stats.latency_acc += diff;
@@ -87,23 +88,25 @@ send_echo_request(struct kdbus_conn *conn, uint64_t dst_id)
        uint64_t size;
        int memfd = -1;
        int ret;
-       struct timeval now;
+       uint64_t now_ns;
 
-       gettimeofday(&now, NULL);
+       now_ns = now();
 
        size = sizeof(struct kdbus_msg);
        size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
 
-       memfd = sys_memfd_create("memfd-name", 0);
-       ASSERT_RETURN_VAL(memfd >= 0, memfd);
+       if (use_memfd) {
+               memfd = sys_memfd_create("memfd-name", 0);
+               ASSERT_RETURN_VAL(memfd >= 0, memfd);
 
-       ret = write(memfd, &now, sizeof(now));
-       ASSERT_RETURN_VAL(ret == sizeof(now), -EAGAIN);
+               ret = write(memfd, &now_ns, sizeof(now_ns));
+               ASSERT_RETURN_VAL(ret == sizeof(now_ns), -EAGAIN);
 
-       ret = sys_memfd_seal_set(memfd);
-       ASSERT_RETURN_VAL(ret == 0, -errno);
+               ret = sys_memfd_seal_set(memfd);
+               ASSERT_RETURN_VAL(ret == 0, -errno);
 
-       size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
+               size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
+       }
 
        msg = malloc(size);
        ASSERT_RETURN_VAL(msg, -ENOMEM);
@@ -122,11 +125,13 @@ send_echo_request(struct kdbus_conn *conn, uint64_t dst_id)
        item->vec.size = sizeof(stress_payload);
        item = KDBUS_ITEM_NEXT(item);
 
-       item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
-       item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd);
-       item->memfd.size = sizeof(struct timeval);
-       item->memfd.fd = memfd;
-       item = KDBUS_ITEM_NEXT(item);
+       if (use_memfd) {
+               item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
+               item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd);
+               item->memfd.size = sizeof(now_ns);
+               item->memfd.fd = memfd;
+               item = KDBUS_ITEM_NEXT(item);
+       }
 
        ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg);
        ASSERT_RETURN_VAL(ret == 0, -errno);
@@ -138,14 +143,18 @@ send_echo_request(struct kdbus_conn *conn, uint64_t dst_id)
 }
 
 static int
-handle_echo_reply(struct kdbus_conn *conn)
+handle_echo_reply(struct kdbus_conn *conn, uint64_t send_ns)
 {
        int ret;
        struct kdbus_cmd_recv recv = {};
        struct kdbus_msg *msg;
        const struct kdbus_item *item;
+       bool has_memfd = false;
 
        ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv);
+       if (ret < 0 && errno == EAGAIN)
+               return -EAGAIN;
+
        ASSERT_RETURN_VAL(ret == 0, -errno);
 
        msg = (struct kdbus_msg *)(conn->buf + recv.offset);
@@ -159,10 +168,13 @@ handle_echo_reply(struct kdbus_conn *conn)
                        buf = mmap(NULL, item->memfd.size, PROT_READ,
                                   MAP_PRIVATE, item->memfd.fd, 0);
                        ASSERT_RETURN_VAL(buf != MAP_FAILED, -EINVAL);
+                       ASSERT_RETURN_VAL(item->memfd.size == sizeof(uint64_t),
+                                         -EINVAL);
 
-                       add_stats((struct timeval *) buf);
+                       add_stats(*(uint64_t*)buf);
                        munmap(buf, item->memfd.size);
                        close(item->memfd.fd);
+                       has_memfd = true;
                        break;
                }
 
@@ -173,6 +185,9 @@ handle_echo_reply(struct kdbus_conn *conn)
                }
        }
 
+       if (!has_memfd)
+               add_stats(send_ns);
+
        ret = kdbus_free(conn, recv.offset);
        ASSERT_RETURN_VAL(ret == 0, -errno);
 
@@ -181,15 +196,21 @@ handle_echo_reply(struct kdbus_conn *conn)
 
 int kdbus_test_benchmark(struct kdbus_test_env *env)
 {
+       static char buf[sizeof(stress_payload)];
        int ret;
        struct kdbus_conn *conn_a, *conn_b;
        struct pollfd fds[2];
-       struct timeval start;
+       uint64_t start, send_ns, now_ns, diff;
        unsigned int i;
+       int uds[2];
+
+       setlocale(LC_ALL, "");
 
        for (i = 0; i < sizeof(stress_payload); i++)
                stress_payload[i] = i;
 
+       /* setup kdbus pair */
+
        conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
        conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
        ASSERT_RETURN(conn_a && conn_b);
@@ -200,56 +221,124 @@ int kdbus_test_benchmark(struct kdbus_test_env *env)
        ret = kdbus_add_match_empty(conn_b);
        ASSERT_RETURN(ret == 0);
 
-       fds[0].fd = conn_a->fd;
-       fds[1].fd = conn_b->fd;
-
        ret = kdbus_name_acquire(conn_a, SERVICE_NAME, NULL);
        ASSERT_RETURN(ret == 0);
 
-       gettimeofday(&start, NULL);
-       reset_stats();
+       /* setup UDS pair */
 
-       ret = send_echo_request(conn_b, conn_a->id);
+       ret = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0, uds);
        ASSERT_RETURN(ret == 0);
 
+       /* start benchmark */
+
        kdbus_printf("-- entering poll loop ...\n");
 
-       while (1) {
-               struct timeval now;
-               unsigned int nfds = sizeof(fds) / sizeof(fds[0]);
-               unsigned int i;
+       do {
+               /* run kdbus benchmark */
 
-               for (i = 0; i < nfds; i++) {
-                       fds[i].events = POLLIN | POLLPRI | POLLHUP;
-                       fds[i].revents = 0;
-               }
+               fds[0].fd = conn_a->fd;
+               fds[1].fd = conn_b->fd;
 
-               ret = poll(fds, nfds, 10);
-               if (ret < 0)
-                       break;
+               /* cancel any prending message */
+               handle_echo_reply(conn_a, 0);
+
+               start = now();
+               reset_stats();
 
-               if (fds[0].revents & POLLIN) {
-                       ret = handle_echo_reply(conn_a);
-                       if (ret)
+               send_ns = now();
+               ret = send_echo_request(conn_b, conn_a->id);
+               ASSERT_RETURN(ret == 0);
+
+               while (1) {
+                       unsigned int nfds = sizeof(fds) / sizeof(fds[0]);
+                       unsigned int i;
+
+                       for (i = 0; i < nfds; i++) {
+                               fds[i].events = POLLIN | POLLPRI | POLLHUP;
+                               fds[i].revents = 0;
+                       }
+
+                       ret = poll(fds, nfds, 10);
+                       if (ret < 0)
                                break;
 
-                       ret = send_echo_request(conn_b, conn_a->id);
-                       if (ret)
+                       if (fds[0].revents & POLLIN) {
+                               ret = handle_echo_reply(conn_a, send_ns);
+                               if (ret)
+                                       break;
+
+                               send_ns = now();
+                               ret = send_echo_request(conn_b, conn_a->id);
+                               if (ret)
+                                       break;
+                       }
+
+                       now_ns = now();
+                       diff = now_ns - start;
+                       if (diff > 1000000000ULL) {
+                               start = now_ns;
+
+                               dump_stats(false);
+                               reset_stats();
+
                                break;
+                       }
                }
 
-               gettimeofday(&now, NULL);
-               if (timeval_diff(&now, &start) / 1000ULL > 1000ULL) {
-                       start.tv_sec = now.tv_sec;
-                       start.tv_usec = now.tv_usec;
+               if (!compare_uds)
+                       continue;
+
+               /* run unix-socket benchmark as comparison */
+
+               fds[0].fd = uds[0];
+               fds[1].fd = uds[1];
+
+               /* cancel any pendign message */
+               read(uds[1], buf, sizeof(buf));
+
+               start = now();
+               reset_stats();
+
+               send_ns = now();
+               ret = write(uds[0], stress_payload, sizeof(stress_payload));
+               ASSERT_RETURN(ret == sizeof(stress_payload));
+
+               while (1) {
+                       unsigned int nfds = sizeof(fds) / sizeof(fds[0]);
+                       unsigned int i;
 
-                       if (!kdbus_util_verbose)
+                       for (i = 0; i < nfds; i++) {
+                               fds[i].events = POLLIN | POLLPRI | POLLHUP;
+                               fds[i].revents = 0;
+                       }
+
+                       ret = poll(fds, nfds, 10);
+                       if (ret < 0)
                                break;
 
-                       dump_stats();
-                       reset_stats();
+                       if (fds[1].revents & POLLIN) {
+                               ret = read(uds[1], buf, sizeof(buf));
+                               ASSERT_RETURN(ret == sizeof(buf));
+                               add_stats(send_ns);
+
+                               send_ns = now();
+                               ret = write(uds[0], buf, sizeof(buf));
+                               ASSERT_RETURN(ret == sizeof(buf));
+                       }
+
+                       now_ns = now();
+                       diff = now_ns - start;
+                       if (diff > 1000000000ULL) {
+                               start = now_ns;
+
+                               dump_stats(true);
+                               reset_stats();
+
+                               break;
+                       }
                }
-       }
+
+       } while (kdbus_util_verbose);
 
        kdbus_printf("-- closing bus connections\n");