1 /*******************************************************/
2 /* Simple vcan latency benchmark */
3 /* Copyright (C) 2012 Michal Sojka, DCE FEE CTU Prague */
5 /*******************************************************/
10 #include <linux/can/raw.h>
15 #include <sys/ioctl.h>
18 #define MEMSET_ZERO(obj) memset(&(obj), 0, sizeof(obj))
20 static inline int sock_get_if_index(int s, const char *if_name)
25 strcpy(ifr.ifr_name, if_name);
26 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
27 error(1, errno, "SIOCGIFINDEX '%s'", if_name);
28 return ifr.ifr_ifindex;
31 int create_can_socket(const char *dev)
34 struct sockaddr_can addr;
35 if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
36 error(1, errno, "socket");
38 addr.can_family = AF_CAN;
39 addr.can_ifindex = sock_get_if_index(s, dev);
41 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
42 error(1, errno, "bind");
47 /* Subtract the `struct timespec' values X and Y, storing the result in
48 RESULT. Return 1 if the difference is negative, otherwise 0. */
50 int timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *yy)
52 struct timespec ylocal = *yy, *y = &ylocal;
53 /* Perform the carry for the later subtraction by updating Y. */
54 if (x->tv_nsec < y->tv_nsec) {
55 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
56 y->tv_nsec -= 1000000000 * nsec;
59 if (x->tv_nsec - y->tv_nsec > 1000000000) {
60 int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
61 y->tv_nsec += 1000000000 * nsec;
65 /* Compute the time remaining to wait.
66 `tv_nsec' is certainly positive. */
67 result->tv_sec = x->tv_sec - y->tv_sec;
68 result->tv_nsec = x->tv_nsec - y->tv_nsec;
70 /* Return 1 if result is negative. */
71 return x->tv_sec < y->tv_sec;
74 unsigned long timespec_diff_ns(const struct timespec *x, const struct timespec *y)
77 timespec_subtract(&r, x, y);
78 return r.tv_sec*1000000000 + r.tv_nsec;
81 #define CHKERR(expr) ({ int __ret = (expr); if (__ret == -1) error(1, errno, #expr); __ret; })
83 static int cmp(const void *p1, const void *p2)
85 return *(unsigned long*)p1 - *(unsigned long*)p2;
88 int main(int argc, char *argv[])
95 fprintf(stderr, "Usage: %s <dev> [ <frame_count> ]\n", argv[0]);
99 count = argc > 2 ? atol(argv[2]) : -1;
101 CHKERR(s1 = create_can_socket(dev));
102 CHKERR(s2 = create_can_socket(dev));
104 unsigned long *ns = NULL;
107 ns = malloc(count*sizeof(*ns));
110 for (i = 0; count == -1 || i < count; i++) {
111 struct can_frame f1 = { .can_id = 0x123, .can_dlc = 8 }, f2;
112 struct timespec t1, t2;
114 clock_gettime(CLOCK_MONOTONIC, &t1);
115 CHKERR(write(s1, &f1, sizeof(f1)));
116 CHKERR(read(s2, &f2, sizeof(f2)));
117 clock_gettime(CLOCK_MONOTONIC, &t2);
118 unsigned long delay = timespec_diff_ns(&t2, &t1);
122 printf("delay %lu ns\n", delay);
126 unsigned long long sum = 0;
127 for (i = 0; i < count; i++)
129 printf("avg=%lld [ns]\n", sum/count);
131 qsort(ns, count, sizeof(*ns), cmp);
132 printf("percentiles: 0th:%ld 25th:%d 50th:%d 75th:%d 100th:%d\n",
133 ns[0], ns[count/4], ns[count/2], ns[count*3/4], ns[count-1]);