lib: optimize sprint_[long_]canframe()
Inspired by the SLCAN rework from Andre Naujoks this patch replaces the extensive use of sprintf() with simple and efficient ASCII helpers. valgrind/kcachegrind reported a cyle estimation of about 5.3 million cycles before and about 1.5 million cycles after the rework (factor 3.55) for the logging of the exact same CAN content. Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>pull/1/head
parent
31ccf45dc4
commit
4a68366bac
92
lib.c
92
lib.c
|
|
@ -54,6 +54,29 @@
|
||||||
#define CANID_DELIM '#'
|
#define CANID_DELIM '#'
|
||||||
#define DATA_SEPERATOR '.'
|
#define DATA_SEPERATOR '.'
|
||||||
|
|
||||||
|
const char hex_asc_upper[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
#define hex_asc_upper_lo(x) hex_asc_upper[((x) & 0x0F)]
|
||||||
|
#define hex_asc_upper_hi(x) hex_asc_upper[((x) & 0xF0) >> 4]
|
||||||
|
|
||||||
|
static inline void put_hex_byte(char *buf, __u8 byte)
|
||||||
|
{
|
||||||
|
buf[0] = hex_asc_upper_hi(byte);
|
||||||
|
buf[1] = hex_asc_upper_lo(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _put_id(char *buf, int end_offset, canid_t id)
|
||||||
|
{
|
||||||
|
/* build 3 (SFF) or 8 (EFF) digit CAN identifier */
|
||||||
|
while (end_offset >= 0) {
|
||||||
|
buf[end_offset--] = hex_asc_upper[id & 0xF];
|
||||||
|
id >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define put_sff_id(buf, id) _put_id(buf, 2, id)
|
||||||
|
#define put_eff_id(buf, id) _put_id(buf, 7, id)
|
||||||
|
|
||||||
/* CAN DLC to real data length conversion helpers */
|
/* CAN DLC to real data length conversion helpers */
|
||||||
|
|
||||||
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
|
@ -229,42 +252,46 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
||||||
int len = (cf->len > maxdlen) ? maxdlen : cf->len;
|
int len = (cf->len > maxdlen) ? maxdlen : cf->len;
|
||||||
|
|
||||||
if (cf->can_id & CAN_ERR_FLAG) {
|
if (cf->can_id & CAN_ERR_FLAG) {
|
||||||
sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
|
put_eff_id(buf, cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
|
||||||
|
buf[8] = '#';
|
||||||
offset = 9;
|
offset = 9;
|
||||||
} else if (cf->can_id & CAN_EFF_FLAG) {
|
} else if (cf->can_id & CAN_EFF_FLAG) {
|
||||||
sprintf(buf, "%08X#", cf->can_id & CAN_EFF_MASK);
|
put_eff_id(buf, cf->can_id & CAN_EFF_MASK);
|
||||||
|
buf[8] = '#';
|
||||||
offset = 9;
|
offset = 9;
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "%03X#", cf->can_id & CAN_SFF_MASK);
|
put_sff_id(buf, cf->can_id & CAN_SFF_MASK);
|
||||||
|
buf[3] = '#';
|
||||||
offset = 4;
|
offset = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
|
/* standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
|
||||||
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
|
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
|
||||||
|
buf[offset++] = 'R';
|
||||||
/* print a given CAN 2.0B DLC if it's not zero */
|
/* print a given CAN 2.0B DLC if it's not zero */
|
||||||
if (cf->len && cf->len <= CAN_MAX_DLC)
|
if (cf->len && cf->len <= CAN_MAX_DLC)
|
||||||
sprintf(buf+offset, "R%d", cf->len);
|
buf[offset++] = hex_asc_upper[cf->len & 0xF];
|
||||||
else
|
|
||||||
sprintf(buf+offset, "R");
|
|
||||||
|
|
||||||
|
buf[offset] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxdlen == CANFD_MAX_DLEN) {
|
if (maxdlen == CANFD_MAX_DLEN) {
|
||||||
/* add CAN FD specific escape char and flags */
|
/* add CAN FD specific escape char and flags */
|
||||||
sprintf(buf+offset, "#%X", cf->flags & 0xF);
|
buf[offset++] = '#';
|
||||||
offset += 2;
|
buf[offset++] = hex_asc_upper[cf->flags & 0xF];
|
||||||
if (sep && len)
|
if (sep && len)
|
||||||
sprintf(buf+offset++, ".");
|
buf[offset++] = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
sprintf(buf+offset, "%02X", cf->data[i]);
|
put_hex_byte(buf + offset, cf->data[i]);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
if (sep && (i+1 < len))
|
if (sep && (i+1 < len))
|
||||||
sprintf(buf+offset++, ".");
|
buf[offset++] = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf[offset] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen) {
|
void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen) {
|
||||||
|
|
@ -288,31 +315,41 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||||
int i, j, dlen, offset;
|
int i, j, dlen, offset;
|
||||||
int len = (cf->len > maxdlen)? maxdlen : cf->len;
|
int len = (cf->len > maxdlen)? maxdlen : cf->len;
|
||||||
|
|
||||||
|
/* initialize space for CAN-ID and length information */
|
||||||
|
memset(buf, ' ', 15);
|
||||||
|
|
||||||
if (cf->can_id & CAN_ERR_FLAG) {
|
if (cf->can_id & CAN_ERR_FLAG) {
|
||||||
sprintf(buf, "%08X ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
|
put_eff_id(buf, cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
|
||||||
offset = 10;
|
offset = 10;
|
||||||
} else if (cf->can_id & CAN_EFF_FLAG) {
|
} else if (cf->can_id & CAN_EFF_FLAG) {
|
||||||
sprintf(buf, "%08X ", cf->can_id & CAN_EFF_MASK);
|
put_eff_id(buf, cf->can_id & CAN_EFF_MASK);
|
||||||
offset = 10;
|
offset = 10;
|
||||||
} else {
|
} else {
|
||||||
if (view & CANLIB_VIEW_INDENT_SFF) {
|
if (view & CANLIB_VIEW_INDENT_SFF) {
|
||||||
sprintf(buf, " %03X ", cf->can_id & CAN_SFF_MASK);
|
put_sff_id(buf + 5, cf->can_id & CAN_SFF_MASK);
|
||||||
offset = 10;
|
offset = 10;
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "%03X ", cf->can_id & CAN_SFF_MASK);
|
put_sff_id(buf, cf->can_id & CAN_SFF_MASK);
|
||||||
offset = 5;
|
offset = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The len value is sanitized by maxdlen (see above) */
|
||||||
if (maxdlen == CAN_MAX_DLEN) {
|
if (maxdlen == CAN_MAX_DLEN) {
|
||||||
sprintf(buf+offset, " [%d] ", len);
|
buf[offset + 1] = '[';
|
||||||
|
buf[offset + 2] = len + '0';
|
||||||
|
buf[offset + 3] = ']';
|
||||||
|
|
||||||
/* standard CAN frames may have RTR enabled */
|
/* standard CAN frames may have RTR enabled */
|
||||||
if (cf->can_id & CAN_RTR_FLAG) {
|
if (cf->can_id & CAN_RTR_FLAG) {
|
||||||
sprintf(buf+offset+5, " remote request");
|
sprintf(buf+offset+5, " remote request");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf+offset, "[%02d] ", len);
|
buf[offset] = '[';
|
||||||
|
buf[offset + 1] = (len/10) + '0';
|
||||||
|
buf[offset + 2] = (len%10) + '0';
|
||||||
|
buf[offset + 3] = ']';
|
||||||
}
|
}
|
||||||
offset += 5;
|
offset += 5;
|
||||||
|
|
||||||
|
|
@ -331,24 +368,29 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||||
buf[offset++] = (1<<j & cf->data[i])?'1':'0';
|
buf[offset++] = (1<<j & cf->data[i])?'1':'0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[offset] = 0; /* terminate string */
|
|
||||||
} else {
|
} else {
|
||||||
dlen = 3; /* _AA */
|
dlen = 3; /* _AA */
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
for (i = len - 1; i >= 0; i--) {
|
for (i = len - 1; i >= 0; i--) {
|
||||||
sprintf(buf+offset, "%c%02X",
|
if (i == len-1)
|
||||||
(i == len-1)?' ':SWAP_DELIMITER,
|
buf[offset++] = ' ';
|
||||||
cf->data[i]);
|
else
|
||||||
offset += dlen;
|
buf[offset++] = SWAP_DELIMITER;
|
||||||
|
|
||||||
|
put_hex_byte(buf + offset, cf->data[i]);
|
||||||
|
offset += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
sprintf(buf+offset, " %02X", cf->data[i]);
|
buf[offset++] = ' ';
|
||||||
offset += dlen;
|
put_hex_byte(buf + offset, cf->data[i]);
|
||||||
|
offset += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf[offset] = 0; /* terminate string */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The ASCII & ERRORFRAME output is put at a fixed len behind the data.
|
* The ASCII & ERRORFRAME output is put at a fixed len behind the data.
|
||||||
* For now we support ASCII output only for payload length up to 8 bytes.
|
* For now we support ASCII output only for payload length up to 8 bytes.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue