1 /**************************************************************************/
2 /* CAN performance benchmark for recvmmsg() */
3 /* Copyright (C) 2013, 2014 Michal Sojka, DCE, FEE, CTU Prague */
5 /**************************************************************************/
8 #include <sys/socket.h>
10 #include <sys/ioctl.h>
19 #define STRINGIFY(val) #val
20 #define TOSTRING(val) STRINGIFY(val)
21 #define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
25 enum { READWRITE, MMSG } method = READWRITE;
28 /* Subtract the `struct timespec' values X and Y,
29 storing the result in RESULT (result = x - y).
30 Return 1 if the difference is negative, otherwise 0. */
33 timespec_subtract (struct timespec *result,
34 const struct timespec *x,
35 const struct timespec *y)
37 int carry = (x->tv_nsec < y->tv_nsec);
39 result->tv_sec = x->tv_sec - y->tv_sec - carry;
40 result->tv_nsec = x->tv_nsec + carry*1000000000 - y->tv_nsec;
42 /* printf("%ld.%09ld - %ld.%09ld = %ld.%09ld\n", */
43 /* x->tv_sec, x->tv_nsec, */
44 /* y->tv_sec, y->tv_nsec, */
45 /* result->tv_sec, result->tv_nsec); */
47 /* Return 1 if result is negative. */
48 return x->tv_sec < y->tv_sec;
55 struct sockaddr_can addr;
59 struct timespec ttx, trx, t1, t2;
61 ss = socket(PF_CAN, SOCK_RAW, CAN_RAW);
62 sr = socket(PF_CAN, SOCK_RAW, CAN_RAW);
64 strcpy(ifr.ifr_name, dev);
65 ioctl(ss, SIOCGIFINDEX, &ifr);
67 addr.can_family = AF_CAN;
68 addr.can_ifindex = ifr.ifr_ifindex;
70 bind(ss, (struct sockaddr *)&addr, sizeof(addr));
71 bind(sr, (struct sockaddr *)&addr, sizeof(addr));
73 int rcvbuf = 30 * count * sizeof(cf);
74 CHECK(setsockopt(sr, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof(rcvbuf)));
76 memset(&cf, 0, sizeof(cf));
81 if (!quiet) fprintf(stderr, "Sending %d frames via write()\n", count);
82 clock_gettime(CLOCK_MONOTONIC, &t1);
83 for (i = 0; i < count; i++) {
84 ret = write(ss, &cf, sizeof(cf));
85 if (ret != sizeof(cf)) {
90 clock_gettime(CLOCK_MONOTONIC, &t2);
94 if (!quiet) fprintf(stderr, "Sending %d frames via sendmmsg()\n", count);
95 struct mmsghdr msgs[count];
96 struct iovec iovecs[count];
97 memset(msgs, 0, sizeof(msgs));
98 memset(iovecs, 0, sizeof(iovecs));
99 for (i = 0; i < count; i++) {
100 iovecs[i].iov_base = &cf;
101 iovecs[i].iov_len = sizeof(cf);
102 msgs[i].msg_hdr.msg_iov = &iovecs[i];
103 msgs[i].msg_hdr.msg_iovlen = 1;
105 clock_gettime(CLOCK_MONOTONIC, &t1);
106 for (i = 0; i < count; i += ret)
107 ret = CHECK(sendmmsg(ss, &msgs[i], count - i, 0));
108 clock_gettime(CLOCK_MONOTONIC, &t2);
112 timespec_subtract(&ttx, &t2, &t1);
116 if (!quiet) fprintf(stderr, "Receiving %d frames with read()\n", count);
117 clock_gettime(CLOCK_MONOTONIC, &t1);
118 for (i = 0; i < count; i++) {
119 //fprintf(stderr, "Receiving frame %d\r", i);
120 ret = read(sr, &cf, sizeof(cf));
121 if (ret != sizeof(cf)) {
126 clock_gettime(CLOCK_MONOTONIC, &t2);
127 //fprintf(stderr, "\n");
131 if (!quiet) fprintf(stderr, "Receiving %d frames with recvmmsg()\n", count);
132 struct mmsghdr msgs[count];
133 struct iovec iovecs[count];
134 char bufs[count][sizeof(struct can_frame)];
136 memset(msgs, 0, sizeof(msgs));
137 for (i = 0; i < count; i++) {
138 iovecs[i].iov_base = bufs[i];
139 iovecs[i].iov_len = sizeof(struct can_frame);
140 msgs[i].msg_hdr.msg_iov = &iovecs[i];
141 msgs[i].msg_hdr.msg_iovlen = 1;
144 clock_gettime(CLOCK_MONOTONIC, &t1);
145 ret = recvmmsg(sr, msgs, count, 0, NULL);
146 clock_gettime(CLOCK_MONOTONIC, &t2);
148 perror("recvmmsg()");
150 } else if (ret != count) {
151 fprintf(stderr, "Error: Only %d messages received\n", ret);
157 timespec_subtract(&trx, &t2, &t1);
158 printf("tx %ld rx %ld [us]\n", ttx.tv_sec*1000000 + ttx.tv_nsec/1000,
159 trx.tv_sec*1000000 + trx.tv_nsec/1000);
162 int main(int argc, char *argv[])
166 while ((opt = getopt(argc, argv, "c:mrq")) != -1) {
169 count = atoi(optarg);
181 fprintf(stderr, "Usage: %s [-c <count>] [-r] [-m] [interface]\n",