Add vcanbench tool
authorMichal Sojka <sojkam1@fel.cvut.cz>
Tue, 17 Sep 2013 11:43:21 +0000 (13:43 +0200)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Tue, 17 Sep 2013 11:43:21 +0000 (13:43 +0200)
I forgot to commit this tool when I created it yeas ago. If I remember well
it can be used to measure performance of vcan interfaces.

latester/Makefile.omk
latester/vcanbench.c [new file with mode: 0644]

index 0d1e2be..63db1c2 100644 (file)
@@ -1,9 +1,12 @@
 # -*- makefile -*-
 
-bin_PROGRAMS += latester
+bin_PROGRAMS += latester vcanbench
 latester_SOURCES = latester.c
 latester_LIBS = rt pthread m talloc popt #ulut
 
+vcanbench_SOURCES = vcanbench.c
+vcanbench_LIBS = rt m talloc
+
 INCLUDES = -DSO_RXQ_OVFL=40 \
           -DPF_CAN=29 \
           -DAF_CAN=PF_CAN
diff --git a/latester/vcanbench.c b/latester/vcanbench.c
new file mode 100644 (file)
index 0000000..9aab186
--- /dev/null
@@ -0,0 +1,137 @@
+/*******************************************************/
+/* Simple vcan latency benchmark                      */
+/* Copyright (C) 2012 Michal Sojka, DCE FEE CTU Prague */
+/* License: GPLv2                                     */
+/*******************************************************/
+
+#include <errno.h>
+#include <error.h>
+#include <linux/can.h>
+#include <linux/can/raw.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <time.h>
+
+#define MEMSET_ZERO(obj) memset(&(obj), 0, sizeof(obj))
+
+static inline int sock_get_if_index(int s, const char *if_name)
+{
+       struct ifreq ifr;
+       MEMSET_ZERO(ifr);
+
+       strcpy(ifr.ifr_name, if_name);
+       if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
+               error(1, errno, "SIOCGIFINDEX '%s'", if_name);
+       return ifr.ifr_ifindex;
+}
+
+int create_can_socket(const char *dev)
+{
+       int s;
+       struct sockaddr_can addr;
+       if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
+               error(1, errno, "socket");
+
+       addr.can_family = AF_CAN;
+       addr.can_ifindex = sock_get_if_index(s, dev);
+
+       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+               error(1, errno, "bind");
+
+       return s;
+}
+
+/* Subtract the `struct timespec' values X and Y, storing the result in
+   RESULT.  Return 1 if the difference is negative, otherwise 0.  */
+
+int timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *yy)
+{
+       struct timespec ylocal = *yy, *y = &ylocal;
+       /* Perform the carry for the later subtraction by updating Y. */
+       if (x->tv_nsec < y->tv_nsec) {
+               int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
+               y->tv_nsec -= 1000000000 * nsec;
+               y->tv_sec += nsec;
+       }
+       if (x->tv_nsec - y->tv_nsec > 1000000000) {
+               int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
+               y->tv_nsec += 1000000000 * nsec;
+               y->tv_sec -= nsec;
+       }
+
+       /* Compute the time remaining to wait.
+          `tv_nsec' is certainly positive. */
+       result->tv_sec = x->tv_sec - y->tv_sec;
+       result->tv_nsec = x->tv_nsec - y->tv_nsec;
+
+       /* Return 1 if result is negative. */
+       return x->tv_sec < y->tv_sec;
+}
+
+unsigned long timespec_diff_ns(const struct timespec *x, const struct timespec *y)
+{
+       struct timespec r;
+       timespec_subtract(&r, x, y);
+       return r.tv_sec*1000000000 + r.tv_nsec;
+}
+
+#define CHKERR(expr) ({ int __ret = (expr); if (__ret == -1) error(1, errno, #expr); __ret; })
+
+static int cmp(const void *p1, const void *p2)
+{
+       return *(unsigned long*)p1 - *(unsigned long*)p2;
+}
+
+int main(int argc, char *argv[])
+{
+       const char *dev;
+       long count;
+       int s1, s2;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: %s <dev> [ <frame_count> ]\n", argv[0]);
+               exit(1);
+       }
+       dev = argv[1];
+       count = argc > 2 ? atol(argv[2]) : -1;
+
+       CHKERR(s1 = create_can_socket(dev));
+       CHKERR(s2 = create_can_socket(dev));
+
+       unsigned long *ns = NULL;
+
+       if (count > 0)
+               ns = malloc(count*sizeof(*ns));
+
+       unsigned long i;
+       for (i = 0; count == -1 || i < count; i++) {
+               struct can_frame f1 = { .can_id = 0x123, .can_dlc = 8 }, f2;
+               struct timespec t1, t2;
+
+               clock_gettime(CLOCK_MONOTONIC, &t1);
+               CHKERR(write(s1, &f1, sizeof(f1)));
+               CHKERR(read(s2, &f2, sizeof(f2)));
+               clock_gettime(CLOCK_MONOTONIC, &t2);
+               unsigned long delay = timespec_diff_ns(&t2, &t1);
+               if (count >= 0) {
+                       ns[i] = delay;
+               } else
+                       printf("delay %lu ns\n", delay);
+       }
+
+       if (ns) {
+               unsigned long long sum = 0;
+               for (i = 0; i < count; i++)
+                       sum += ns[i];
+               printf("avg=%lld [ns]\n", sum/count);
+
+               qsort(ns, count, sizeof(*ns), cmp);
+               printf("percentiles: 0th:%ld 25th:%d 50th:%d 75th:%d 100th:%d\n",
+                      ns[0], ns[count/4], ns[count/2], ns[count*3/4], ns[count-1]);
+       }
+
+       return 0;
+}