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