/**************************************************************************/
/* CAN latency tester */
-/* Copyright (C) 2010, 2011 Michal Sojka, DCE FEE CTU Prague */
+/* Copyright (C) 2010, 2011, 2012 Michal Sojka, DCE FEE CTU Prague */
/* License: GPLv2 */
/**************************************************************************/
/* Temporary variables */
FILE *f_msgs;
FILE *f_hist;
+ FILE *f_hist_gw;
FILE *f_stat;
};
struct timespec ts_rx_onwire, ts_rx_onwire_kern;
struct timespec ts_rx_final, ts_rx_final_kern;
struct can_frame sent, received;
+ unsigned lat_measured_us, tx_time_us;
};
#define MAX_INFOS 10000
struct msg_info msg_infos[MAX_INFOS];
-struct histogram histogram;
+struct histogram histogram, histogram_gw;
void sprint_canframe(char *buf , struct can_frame *cf, int sep) {
/* documentation see lib.h */
tstamp->tv_sec, tstamp->tv_nsec/1000);
}
+/* Functions and types for CRC checks.
+ *
+ * Generated on Wed Sep 21 22:30:11 2011,
+ * by pycrc v0.7.8, http://www.tty1.net/pycrc/
+ * using the configuration:
+ * Width = 15
+ * Poly = 0x4599
+ * XorIn = 0x0000
+ * ReflectIn = False
+ * XorOut = 0x0000
+ * ReflectOut = False
+ * Algorithm = table-driven
+ *****************************************************************************/
+typedef uint16_t crc_t;
+
+static const crc_t crc_table[2] = {
+ 0x0000, 0x4599
+};
+
+crc_t crc_update(crc_t crc, uint32_t data, size_t bit_len)
+{
+ unsigned int tbl_idx;
+/* crc_t bc = crc; */
+/* uint32_t bd = data; */
+/* size_t bl = bit_len; */
+
+ while (bit_len--) {
+ tbl_idx = (crc >> 14) ^ (data >> 31);
+ crc = crc_table[tbl_idx & 0x01] ^ (crc << 1);
+ data <<= 1;
+ }
+ crc = crc & 0x7fff;
+/* printf("crc: 0x%04x -> 0x%04x data: 0x%08x len: %d\n", */
+/* bc, crc, bd, bl); */
+ return crc;
+}
+
unsigned calc_stuff_bits(struct can_frame *frame) {
uint32_t bitmap[4];
unsigned start = 0, end;
- uint32_t mask, ones = 0, basemask = 0xf0000000;
+ uint32_t mask, ones = 0, basemask = 0xf8000000;
unsigned stuffed = 0;
memset(bitmap, 0, sizeof(bitmap));
+ crc_t crc = 0;
+ uint32_t crcx;
+/* char received[64]; */
+/* sprint_canframe(received, frame, true); */
+/* printf("Frame: %s\n", received); */
+
if (frame->can_id & CAN_EFF_FLAG) {
bitmap[0] =
- (frame->can_id >> 25);
+ ((frame->can_id & CAN_EFF_MASK) >> 25);
bitmap[1] =
- (frame->can_id >> 18) << 25 |
- 3 << 23 |
- (frame->can_id & 0x3ffff) << 7 |
- (!!(frame->can_id & CAN_RTR_FLAG)) << 6 |
- 0 << 4 |
+ ((frame->can_id & CAN_EFF_MASK) >> 18) << 25 |
+ 3 << 23 |
+ ((frame->can_id & CAN_EFF_MASK) & 0x3ffff) << 7 |
+ (!!(frame->can_id & CAN_RTR_FLAG)) << 6 |
+ 0 << 4 |
frame->can_dlc & 0xf;
bitmap[2] = htonl(((uint32_t*)frame->data)[0]);
bitmap[3] = htonl(((uint32_t*)frame->data)[1]);
- start = 28;
+ start = 27;
end = 64 + 8*frame->can_dlc;
+ crc = crc_update(crc, bitmap[0] << start, 32-start);
+ crc = crc_update(crc, bitmap[1], 32);
+ crc = crc_update(crc, bitmap[2], end - 64 > 32 ? 32 : end - 64);
+ crc = crc_update(crc, bitmap[3], end > 96 ? end - 96 : 0);
+ crcx = (uint32_t)htons(crc) << 17;
+ if (frame->can_dlc < 4)
+ bitmap[2] |= crcx >> (frame->can_dlc*8);
+ if (frame->can_dlc = 3)
+ bitmap[3] |= crcx << 8;
+ if (frame->can_dlc >= 4)
+ bitmap[3] |= crcx >> (frame->can_dlc*8);
} else {
bitmap[0] =
(frame->can_id << 7) |
frame->can_dlc & 0xf;
bitmap[1] = htonl(((uint32_t*)frame->data)[0]);
bitmap[2] = htonl(((uint32_t*)frame->data)[1]);
- start = 14;
+ start = 13;
end = 32 + 8*frame->can_dlc;
}
/* TODO: Calc stuff bits in CRC */
if (start <= end && !mask) {
stuffed++;
basemask = 0xf0000000;
- printf("stuffed %d\n", !ones);
+ //printf("stuffed %d\n", !ones);
}
}
break;
}
ones = !ones;
}
- printf ("STUFFED %d BITS\n", stuffed);
+ //printf ("STUFFED %d BITS\n", stuffed);
+ return stuffed;
}
-unsigned calc_frame_txtime(struct can_frame *frame) {
+unsigned calc_frame_txtime_us(struct can_frame *frame) {
return calc_stuff_bits(frame) +
1 + /* SOF */
11 + /* ID A */
static long num = 0;
char sent[64], received[64];
+ if (!f)
+ return;
+
sprint_canframe(sent, &mi->sent, true);
sprint_canframe(received, &mi->received, true);
num, S(mi->ts_sent), sent, S(mi->ts_rx_final_kern), S(mi->ts_rx_final), received,
DIFF(mi->ts_sent, mi->ts_rx_final_kern),
DIFF(mi->ts_sent, mi->ts_rx_final),
- calc_frame_txtime(mi->received));
+ mi->tx_time_us);
break;
case 3:
fprintf(f, "%ld: %s %s -> %s (%s) -> %s (%s) %s = %s (%s), %s (%s) %d\n",
DIFF(mi->ts_sent, mi->ts_rx_onwire),
DIFF(mi->ts_rx_onwire_kern, mi->ts_rx_final_kern),
DIFF(mi->ts_rx_onwire, mi->ts_rx_final),
- calc_frame_txtime(mi->received));
+ mi->tx_time_us);
break;
}
#undef S
printf("%s sec=%ld nsec=%ld\n", msg, tv->tv_sec, tv->tv_nsec);
}
-static inline unsigned get_msg_latency_us(struct msg_info *mi)
+static inline void calc_msg_latencies(struct msg_info *mi)
{
struct timespec diff;
switch (num_interfaces) {
timespec_subtract(&diff, &mi->ts_rx_final_kern, &mi->ts_sent);
break;
default:
- return 0;
+ return;
}
- return diff.tv_sec * 1000000 + diff.tv_nsec/1000;
+ mi->lat_measured_us = diff.tv_sec * 1000000 + diff.tv_nsec/1000;
+ mi->tx_time_us = calc_frame_txtime_us(&mi->received);
}
void set_sched_policy_and_prio(int policy, int rtprio)
mi->ts_rx_final = ts_user;
mi->received = frame;
- histogram_add(&histogram, get_msg_latency_us(mi));
+ calc_msg_latencies(mi);
+
+ histogram_add(&histogram, mi->lat_measured_us);
+ histogram_add(&histogram_gw, mi->lat_measured_us - mi->tx_time_us);
ret = write(completion_pipe[1], &mi, sizeof(mi));
if (ret == -1)
}
if (opt.name) {
- char *f = talloc_asprintf(local, "%s-hist.txt", opt.name);
+ char *f = talloc_asprintf(local, "%s-hist-raw.txt", opt.name);
opt.f_hist = fopen(f, "w");
if (!opt.f_hist)
error(1, errno, "fopen: %s", f);
}
+ if (opt.name) {
+ char *f = talloc_asprintf(local, "%s-hist.txt", opt.name);
+ opt.f_hist_gw = fopen(f, "w");
+ if (!opt.f_hist_gw)
+ error(1, errno, "fopen: %s", f);
+ }
+
if (opt.name) {
char *f = talloc_asprintf(local, "%s-stat.txt", opt.name);
opt.f_stat = fopen(f, "w");
msg_infos[i].id = -1;
histogram_init(&histogram, 5000000, 1);
+ histogram_init(&histogram_gw, 5000000, 1);
ret = pipe(completion_pipe);
if (ret == -1)
error(1, errno, "pipe fcntl");
init_ftrace();
+ if (getenv("LATESTER_CONTROL_HACKBENCH")) {
+ char cmd[1000];
+ sprintf(cmd, "ssh -x -a -S $HOME/.ssh/cangw-connection root@192.168.2.3 'kill -CONT -%s'",
+ getenv("LATESTER_CONTROL_HACKBENCH"));
+ printf("Running: %s\n", cmd);
+ system(cmd);
+ }
pthread_create(&thread, 0, measure_thread, NULL);
pthread_join(thread, NULL);
+ if (getenv("LATESTER_CONTROL_HACKBENCH")) {
+ char cmd[1000];
+ sprintf(cmd, "ssh -x -a -S $HOME/.ssh/cangw-connection root@192.168.2.3 'kill -STOP -%s'",
+ getenv("LATESTER_CONTROL_HACKBENCH"));
+ printf("Running: %s\n", cmd);
+ system(cmd);
+ }
+
close(completion_pipe[0]);
close(completion_pipe[1]);
histogram_fprint(&histogram, opt.f_hist);
- fclose(opt.f_hist);
- fclose(opt.f_msgs);
-
-
- fprintf(opt.f_stat, "cmdline='");
- for (i=0; i<argc; i++)
- fprintf(opt.f_stat, "%s%s", argv[i], i < argc-1 ? " " : "");
- fprintf(opt.f_stat, "'\n");
-
- timespec_subtract(&diff, &stats.tac, &stats.tic);
- fprintf(opt.f_stat, "duration=%s # seconds\n", tstamp_str(NULL, &diff));
+ histogram_fprint(&histogram_gw, opt.f_hist_gw);
+ if (opt.f_hist)
+ fclose(opt.f_hist);
+ if (opt.f_hist_gw)
+ fclose(opt.f_hist_gw);
+ if (opt.f_msgs)
+ fclose(opt.f_msgs);
+
+ if (opt.f_stat) {
+ fprintf(opt.f_stat, "cmdline='");
+ for (i=0; i<argc; i++)
+ fprintf(opt.f_stat, "%s%s", argv[i], i < argc-1 ? " " : "");
+ fprintf(opt.f_stat, "'\n");
+
+ timespec_subtract(&diff, &stats.tac, &stats.tic);
+ fprintf(opt.f_stat, "duration=%s # seconds\n", tstamp_str(NULL, &diff));
- fprintf(opt.f_stat, "sent=%d\n", count);
- fprintf(opt.f_stat, "overrun=%d\n", stats.overrun);
- if (stats.overrun && !opt.quiet)
- printf("overrun=%d\n", stats.overrun);
- fprintf(opt.f_stat, "enobufs=%d\n", stats.enobufs);
- if (stats.enobufs && !opt.quiet)
- printf("enobufs=%d\n", stats.enobufs);
- fprintf(opt.f_stat, "lost=%d\n", stats.lost);
- if (stats.lost && !opt.quiet)
- printf("lost=%d\n", stats.lost);
- fprintf(opt.f_stat, "timeouts=%d\n", stats.timeouts);
- if (stats.timeouts && !opt.quiet)
- printf("timeouts=%d\n", stats.timeouts);
- fprintf(opt.f_stat, "invalid_frame=%d\n", stats.timeouts);
- if (stats.timeouts && !opt.quiet)
- printf("invalid_frame=%d\n", stats.timeouts);
-
- fclose(opt.f_stat);
+ fprintf(opt.f_stat, "sent=%d\n", count);
+ fprintf(opt.f_stat, "overrun=%d\n", stats.overrun);
+ if (stats.overrun && !opt.quiet)
+ printf("overrun=%d\n", stats.overrun);
+ fprintf(opt.f_stat, "enobufs=%d\n", stats.enobufs);
+ if (stats.enobufs && !opt.quiet)
+ printf("enobufs=%d\n", stats.enobufs);
+ fprintf(opt.f_stat, "lost=%d\n", stats.lost);
+ if (stats.lost && !opt.quiet)
+ printf("lost=%d\n", stats.lost);
+ fprintf(opt.f_stat, "timeouts=%d\n", stats.timeouts);
+ if (stats.timeouts && !opt.quiet)
+ printf("timeouts=%d\n", stats.timeouts);
+ fprintf(opt.f_stat, "invalid_frame=%d\n", stats.timeouts);
+ if (stats.timeouts && !opt.quiet)
+ printf("invalid_frame=%d\n", stats.timeouts);
+
+ fclose(opt.f_stat);
+ }
return 0;
}