]> rtime.felk.cvut.cz Git - can-benchmark.git/blob - recvmmsg/can_recvmmsg.c
Use new novaboot feature EXITON
[can-benchmark.git] / recvmmsg / can_recvmmsg.c
1 /**************************************************************************/
2 /* CAN performance benchmark for recvmmsg()                               */
3 /* Copyright (C) 2013, 2014 Michal Sojka, DCE, FEE, CTU Prague            */
4 /* License: GPLv2                                                         */
5 /**************************************************************************/
6
7 #define _GNU_SOURCE
8 #include <sys/socket.h>
9 #include <linux/can.h>
10 #include <sys/ioctl.h>
11 #include <net/if.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <time.h>
17 #include <stdbool.h>
18
19 #define CHECK(cmd) do { if ((cmd) == -1) { perror(#cmd); exit(1); } } while (0)
20
21 char *dev = "vcan0";
22 int count = 10000;
23 enum { READ, RECVMMSG } recv_method = READ;
24 bool quiet = false;
25
26 /* Subtract the `struct timespec' values X and Y,
27    storing the result in RESULT (result = x - y).
28    Return 1 if the difference is negative, otherwise 0.  */
29
30 int
31 timespec_subtract (struct timespec *result,
32                    struct timespec *x,
33                    struct timespec *y)
34 {
35         /* Perform the carry for the later subtraction by updating Y. */
36         if (x->tv_nsec < y->tv_nsec) {
37                 int num_sec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
38                 y->tv_nsec -= 1000000000 * num_sec;
39                 y->tv_sec += num_sec;
40         }
41         if (x->tv_nsec - y->tv_nsec > 1000000000) {
42                 int num_sec = (x->tv_nsec - y->tv_nsec) / 1000000000;
43                 y->tv_nsec += 1000000000 * num_sec;
44                 y->tv_sec -= num_sec;
45         }
46
47         /* Compute the time remaining to wait.
48            `tv_nsec' is certainly positive. */
49         result->tv_sec = x->tv_sec - y->tv_sec;
50         result->tv_nsec = x->tv_nsec - y->tv_nsec;
51
52         /* Return 1 if result is negative. */
53         return x->tv_sec < y->tv_sec;
54 }
55
56
57 void benchmark()
58 {
59         int ss, sr;
60         struct sockaddr_can addr;
61         struct ifreq ifr;
62         struct can_frame cf;
63         int ret, i;
64         struct timespec t, t1, t2;
65
66         ss = socket(PF_CAN, SOCK_RAW, CAN_RAW);
67         sr = socket(PF_CAN, SOCK_RAW, CAN_RAW);
68
69         strcpy(ifr.ifr_name, dev);
70         ioctl(ss, SIOCGIFINDEX, &ifr);
71
72         addr.can_family = AF_CAN;
73         addr.can_ifindex = ifr.ifr_ifindex;
74
75         bind(ss, (struct sockaddr *)&addr, sizeof(addr));
76         bind(sr, (struct sockaddr *)&addr, sizeof(addr));
77
78         int rcvbuf = 30 * count * sizeof(cf);
79         CHECK(setsockopt(sr, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof(rcvbuf)));
80
81         memset(&cf, 0, sizeof(cf));
82         cf.can_dlc = 8;
83
84         if (!quiet) fprintf(stderr, "Sending %d frames\n", count);
85         for (i = 0; i < count; i++) {
86                 ret = write(ss, &cf, sizeof(cf));
87                 if (ret != sizeof(cf)) {
88                         perror("write");
89                         exit(1);
90                 }
91         }
92
93         switch (recv_method) {
94         case READ: {
95                 if (!quiet) fprintf(stderr, "Receiving %d frames with read()\n", count);
96                 clock_gettime(CLOCK_MONOTONIC, &t1);
97                 for (i = 0; i < count; i++) {
98                         //fprintf(stderr, "Receiving frame %d\r", i);
99                         ret = read(sr, &cf, sizeof(cf));
100                         if (ret != sizeof(cf)) {
101                                 perror("read");
102                                 exit(1);
103                         }
104                 }
105                 clock_gettime(CLOCK_MONOTONIC, &t2);
106                 //fprintf(stderr, "\n");
107                 break;
108         }
109         case RECVMMSG: {
110                 if (!quiet) fprintf(stderr, "Receiving %d frames with recvmmsg()\n", count);
111                 struct mmsghdr msgs[count];
112                 struct iovec iovecs[count];
113                 char bufs[count][sizeof(struct can_frame)];
114
115                 memset(msgs, 0, sizeof(msgs));
116                 for (i = 0; i < count; i++) {
117                         iovecs[i].iov_base         = bufs[i];
118                         iovecs[i].iov_len          = sizeof(struct can_frame);
119                         msgs[i].msg_hdr.msg_iov    = &iovecs[i];
120                         msgs[i].msg_hdr.msg_iovlen = 1;
121                 }
122
123                 clock_gettime(CLOCK_MONOTONIC, &t1);
124                 ret = recvmmsg(sr, msgs, count, 0, NULL);
125                 clock_gettime(CLOCK_MONOTONIC, &t2);
126                 if (ret == -1) {
127                         perror("recvmmsg()");
128                         exit(1);
129                 } else if (ret != count) {
130                         fprintf(stderr, "Error: Only %d messages received\n", ret);
131                         exit(1);
132                 }
133                 break;
134         }
135         }
136         timespec_subtract(&t, &t2, &t1);
137         printf("%d us\n", t.tv_nsec/1000);
138 }
139
140 int main(int argc, char *argv[])
141 {
142         int opt;
143
144         while ((opt = getopt(argc, argv, "c:mrq")) != -1) {
145                 switch (opt) {
146                 case 'c':
147                         count = atoi(optarg);
148                         break;
149                 case 'm':
150                         recv_method = RECVMMSG;
151                         break;
152                 case 'r':
153                         recv_method = READ;
154                         break;
155                 case 'q':
156                         quiet = true;
157                         break;
158                 default: /* '?' */
159                         fprintf(stderr, "Usage: %s [-c <count>] [-r] [-m]  [interface]\n",
160                                 argv[0]);
161                         exit(EXIT_FAILURE);
162                 }
163         }
164
165         if (optind < argc)
166                 dev = argv[optind];
167
168         benchmark();
169
170         return 0;
171 }