latester: Fix GCC 4.9 warnings
[can-benchmark.git] / latester / vcanbench.c
1 /*******************************************************/
2 /* Simple vcan latency benchmark                       */
3 /* Copyright (C) 2012 Michal Sojka, DCE FEE CTU Prague */
4 /* License: GPLv2                                      */
5 /*******************************************************/
6
7 #include <errno.h>
8 #include <error.h>
9 #include <linux/can.h>
10 #include <linux/can/raw.h>
11 #include <net/if.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <time.h>
17
18 #define MEMSET_ZERO(obj) memset(&(obj), 0, sizeof(obj))
19
20 static inline int sock_get_if_index(int s, const char *if_name)
21 {
22         struct ifreq ifr;
23         MEMSET_ZERO(ifr);
24
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;
29 }
30
31 int create_can_socket(const char *dev)
32 {
33         int s;
34         struct sockaddr_can addr;
35         if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
36                 error(1, errno, "socket");
37
38         addr.can_family = AF_CAN;
39         addr.can_ifindex = sock_get_if_index(s, dev);
40
41         if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
42                 error(1, errno, "bind");
43
44         return s;
45 }
46
47 /* Subtract the `struct timespec' values X and Y, storing the result in
48    RESULT.  Return 1 if the difference is negative, otherwise 0.  */
49
50 int timespec_subtract (struct timespec *result, const struct timespec *x, const struct timespec *yy)
51 {
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;
57                 y->tv_sec += nsec;
58         }
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;
62                 y->tv_sec -= nsec;
63         }
64
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;
69
70         /* Return 1 if result is negative. */
71         return x->tv_sec < y->tv_sec;
72 }
73
74 unsigned long timespec_diff_ns(const struct timespec *x, const struct timespec *y)
75 {
76         struct timespec r;
77         timespec_subtract(&r, x, y);
78         return r.tv_sec*1000000000 + r.tv_nsec;
79 }
80
81 #define CHKERR(expr) ({ int __ret = (expr); if (__ret == -1) error(1, errno, #expr); __ret; })
82
83 static int cmp(const void *p1, const void *p2)
84 {
85         return *(unsigned long*)p1 - *(unsigned long*)p2;
86 }
87
88 int main(int argc, char *argv[])
89 {
90         const char *dev;
91         long count;
92         int s1, s2;
93
94         if (argc < 2) {
95                 fprintf(stderr, "Usage: %s <dev> [ <frame_count> ]\n", argv[0]);
96                 exit(1);
97         }
98         dev = argv[1];
99         count = argc > 2 ? atol(argv[2]) : -1;
100
101         CHKERR(s1 = create_can_socket(dev));
102         CHKERR(s2 = create_can_socket(dev));
103
104         unsigned long *ns = NULL;
105
106         if (count > 0)
107                 ns = malloc(count*sizeof(*ns));
108
109         unsigned long i;
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;
113
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);
119                 if (count >= 0) {
120                         ns[i] = delay;
121                 } else
122                         printf("delay %lu ns\n", delay);
123         }
124
125         if (ns) {
126                 unsigned long long sum = 0;
127                 for (i = 0; i < count; i++)
128                         sum += ns[i];
129                 printf("avg=%lld [ns]\n", sum/count);
130
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]);
134         }
135
136         return 0;
137 }