#include <time.h>
#include <stdbool.h>
-#define CHECK(cmd) do { if ((cmd) == -1) { perror(#cmd); exit(1); } } while (0)
+#define STRINGIFY(val) #val
+#define TOSTRING(val) STRINGIFY(val)
+#define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
char *dev = "vcan0";
int count = 10000;
-enum { READ, RECVMMSG } recv_method = READ;
+enum { READWRITE, MMSG } method = READWRITE;
bool quiet = false;
/* Subtract the `struct timespec' values X and Y,
int
timespec_subtract (struct timespec *result,
- struct timespec *x,
- struct timespec *y)
+ const struct timespec *x,
+ const struct timespec *y)
{
- /* Perform the carry for the later subtraction by updating Y. */
- if (x->tv_nsec < y->tv_nsec) {
- int num_sec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
- y->tv_nsec -= 1000000000 * num_sec;
- y->tv_sec += num_sec;
- }
- if (x->tv_nsec - y->tv_nsec > 1000000000) {
- int num_sec = (x->tv_nsec - y->tv_nsec) / 1000000000;
- y->tv_nsec += 1000000000 * num_sec;
- y->tv_sec -= num_sec;
- }
+ int carry = (x->tv_nsec < y->tv_nsec);
+
+ result->tv_sec = x->tv_sec - y->tv_sec - carry;
+ result->tv_nsec = x->tv_nsec + carry*1000000000 - y->tv_nsec;
- /* Compute the time remaining to wait.
- `tv_nsec' is certainly positive. */
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_nsec = x->tv_nsec - y->tv_nsec;
+/* printf("%ld.%09ld - %ld.%09ld = %ld.%09ld\n", */
+/* x->tv_sec, x->tv_nsec, */
+/* y->tv_sec, y->tv_nsec, */
+/* result->tv_sec, result->tv_nsec); */
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
struct ifreq ifr;
struct can_frame cf;
int ret, i;
- struct timespec t, t1, t2;
+ struct timespec ttx, trx, t1, t2;
ss = socket(PF_CAN, SOCK_RAW, CAN_RAW);
sr = socket(PF_CAN, SOCK_RAW, CAN_RAW);
memset(&cf, 0, sizeof(cf));
cf.can_dlc = 8;
- if (!quiet) fprintf(stderr, "Sending %d frames\n", count);
- for (i = 0; i < count; i++) {
- ret = write(ss, &cf, sizeof(cf));
- if (ret != sizeof(cf)) {
- perror("write");
- exit(1);
+ switch (method) {
+ case READWRITE: {
+ if (!quiet) fprintf(stderr, "Sending %d frames via write()\n", count);
+ clock_gettime(CLOCK_MONOTONIC, &t1);
+ for (i = 0; i < count; i++) {
+ ret = write(ss, &cf, sizeof(cf));
+ if (ret != sizeof(cf)) {
+ perror("write");
+ exit(1);
+ }
}
+ clock_gettime(CLOCK_MONOTONIC, &t2);
+ break;
+ }
+ case MMSG: {
+ if (!quiet) fprintf(stderr, "Sending %d frames via sendmmsg()\n", count);
+ struct mmsghdr msgs[count];
+ struct iovec iovecs[count];
+ memset(msgs, 0, sizeof(msgs));
+ memset(iovecs, 0, sizeof(iovecs));
+ for (i = 0; i < count; i++) {
+ iovecs[i].iov_base = &cf;
+ iovecs[i].iov_len = sizeof(cf);
+ msgs[i].msg_hdr.msg_iov = &iovecs[i];
+ msgs[i].msg_hdr.msg_iovlen = 1;
+ }
+ clock_gettime(CLOCK_MONOTONIC, &t1);
+ for (i = 0; i < count; i += ret)
+ ret = CHECK(sendmmsg(ss, &msgs[i], count - i, 0));
+ clock_gettime(CLOCK_MONOTONIC, &t2);
+ break;
+ }
}
+ timespec_subtract(&ttx, &t2, &t1);
- switch (recv_method) {
- case READ: {
+ switch (method) {
+ case READWRITE: {
if (!quiet) fprintf(stderr, "Receiving %d frames with read()\n", count);
clock_gettime(CLOCK_MONOTONIC, &t1);
for (i = 0; i < count; i++) {
//fprintf(stderr, "\n");
break;
}
- case RECVMMSG: {
+ case MMSG: {
if (!quiet) fprintf(stderr, "Receiving %d frames with recvmmsg()\n", count);
struct mmsghdr msgs[count];
struct iovec iovecs[count];
break;
}
}
- timespec_subtract(&t, &t2, &t1);
- printf("%d us\n", t.tv_nsec/1000);
+ timespec_subtract(&trx, &t2, &t1);
+ printf("tx %ld rx %ld [us]\n", ttx.tv_sec*1000000 + ttx.tv_nsec/1000,
+ trx.tv_sec*1000000 + trx.tv_nsec/1000);
}
int main(int argc, char *argv[])
count = atoi(optarg);
break;
case 'm':
- recv_method = RECVMMSG;
+ method = MMSG;
break;
case 'r':
- recv_method = READ;
+ method = READWRITE;
break;
case 'q':
quiet = true;
set grid
set xlabel "Frames [×1000]"
-set ylabel "Time [ms]"
+set ylabel "RX Time [ms]"
+set y2label "TX Time [ms]"
+set y2tics
set key left reverse Left
-fit a1*x+b1 "data" using 1:2 via a1, b1
-fit a2*x+b2 "data" using 1:4 via a2, b2
+fit ard*x+brd "data" using 1:5 via ard, brd
+fit arm*x+brm "data" using 1:10 via arm, brm
+
+fit awr*x+bwr "data" using 1:3 via awr, bwr
+fit asm*x+bsm "data" using 1:8 via asm, bsm
set yrange [0:]
+set y2range [0:]
+
+brd=brd/1000
+brm=brm/1000
+bwr=bwr/1000
+bsm=bsm/1000
-b1=b1/1000
-b2=b2/1000
+plot 'data' using ($1/1000):($5/1000) lc 1 title 'read()', \
+ 'data' using ($1/1000):($10/1000) lc 1 title 'recvmmsg()', \
+ 'data' using ($1/1000):($3/1000) lc 2 axes x1y2 title 'write()', \
+ 'data' using ($1/1000):($8/1000) lc 2 axes x1y2 title 'sendmmsg()', \
+ ard*x+brd with lines lt 1 lc rgbcolor "#aa0000" lw 1 title "", \
+ arm*x+brm with lines lt 2 lc rgbcolor "#aa0000" lw 1 title "", \
+ awr*x+bwr with lines axes x1y2 lt 1 lc rgbcolor "#00aa00" lw 1 title "", \
+ asm*x+bsm with lines axes x1y2 lt 2 lc rgbcolor "#00aa00" lw 1 title ""
-plot 'data' using ($1/1000):($2/1000) title 'read()', \
- 'data' using ($1/1000):($4/1000) title 'recvmmsg()', \
- a1*x+b1 with lines lt 1 lc rgbcolor "#aa0000" lw 5 title "", \
- a2*x+b2 with lines lt 1 lc rgbcolor "#00aa00" lw 5 title ""
+# aread*x+bread - arecv*x-brecv = 0
+# (aread-arecv)*x = brecv-bread
+xeq = (brm-brd)/(ard-arm)
+print "ard = ", ard
+print "arm = ", arm
+print "arm/ard = ", arm/ard
+print "Intersection at x = ", xeq
+print ""
-# a1*x+b1 - a2*x-b2 = 0
-# (a1-a2)*x = b2-b1
-xeq = (b2-b1)/(a1-a2)
-print "ar = ", a1
-print "am = ", a2
-print "ar/am = ", a1/a2
+xeq = (bsm-bwr)/(awr-asm)
+print "awr = ", awr
+print "asm = ", asm
+print "asm/awr = ", asm/awr
print "Intersection at x = ", xeq