From 6eb97b57c552ddd337d7523cd47e03ca7454bc3f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jan 2025 17:23:30 +0100 Subject: [PATCH 1/3] cangen: support socket priority Add '-P' option for allow user to set the socket priority. This can be useful in conjuction with queuing discipline. Signed-off-by: Zhu Yi Signed-off-by: Hubert Streidl Signed-off-by: Mark Jonas Link: https://lore.kernel.org/r/20250120162332.19157-1-mark.jonas@de.bosch.com Signed-off-by: Marc Kleine-Budde --- cangen.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/cangen.c b/cangen.c index d9a0448..92290e6 100644 --- a/cangen.c +++ b/cangen.c @@ -189,6 +189,7 @@ static void print_usage(char *prg) fprintf(stderr, " -A (CAN XL AF generation mode - see below, no e/o mode)\n"); fprintf(stderr, " -V (CAN XL VCID generation mode - see below, no e/o mode)\n"); fprintf(stderr, " -p (poll on -ENOBUFS to write frames with ms)\n"); + fprintf(stderr, " -P (set socket priority using SO_PRIORITY)\n"); fprintf(stderr, " -n (terminate after CAN frames - default infinite)\n"); fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n"); fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n"); @@ -479,6 +480,7 @@ int main(int argc, char **argv) uint64_t incdata = 0; __u8 *data; /* base pointer for CC/FD or XL data */ int incdlc = 0; + int priority = -1; unsigned long rnd; unsigned char fixdata[CANFD_MAX_DLEN]; unsigned char rand_position[CANFD_MAX_DLEN] = { 0 }; @@ -512,7 +514,7 @@ int main(int argc, char **argv) { 0, 0, 0, 0 }, }; - while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:n:ixc:vh?", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:P:n:ixc:vh?", long_options, NULL)) != -1) { switch (opt) { case 'g': gap = strtod(optarg, NULL); @@ -682,6 +684,14 @@ int main(int argc, char **argv) } break; + case 'P': + priority = atoi(optarg); + if (priority < 0) { + printf("socket priority has to be >= 0\n"); + exit(1); + } + break; + case 'i': ignore_enobufs = true; break; @@ -750,6 +760,16 @@ int main(int argc, char **argv) */ setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); + /* + * user can use tc to configure the queuing discipline (e.g. mqprio), + * together with SO_PRIORITY option to specify the message send from + * this socket should go to which queue. + */ + if (priority >= 0 && + setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority))) { + printf("error setting SO_PRIORITY\n"); + } + if (loopback_disable) { const int loopback = 0; From b85418d75cf52c9b282c8711b6fd34a80e3a4632 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jan 2025 17:23:31 +0100 Subject: [PATCH 2/3] canbusload: support busload statistic Add '-s' option for display busload statistic, the output contains minimal, maximum and exponentially-damped moving sums of one second average (borrowed from Linux load average algorithm) since start or reset (press 'r' while running). canbusload 2024-09-23 17:15:18 (exact bitstuffing) can0@500k 942 107535 60168 0 18% min: 0%, max: 21%, load: 16% 6% 2% |XXX.................| Signed-off-by: Zhu Yi Signed-off-by: Hubert Streidl Signed-off-by: Mark Jonas Link: https://lore.kernel.org/r/20250120162332.19157-2-mark.jonas@de.bosch.com Signed-off-by: Marc Kleine-Budde --- canbusload.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/canbusload.c b/canbusload.c index 753d658..4679da5 100644 --- a/canbusload.c +++ b/canbusload.c @@ -45,14 +45,17 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -72,6 +75,24 @@ #define NUMBAR (100 / PERCENTRES) /* number of bargraph elements */ #define BRSTRLEN 20 +/* + * Inspired from + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ + * include/linux/sched/loadavg.h + * + * Following are the fixed-point math constants and the exponential-damping + * factors for: + * - 1 samples/s in 1 minute + * - 1 samples/s in 5 minutes + * - 1 samples/s in 15 minutes + * in fixed-point representation. + */ +#define FP_SHIFT 12 /* bits of precision */ +#define FP_ONE (1 << FP_SHIFT) /* 1.0 fixed-point representation */ +#define EXP_1 4028 /* (1 / e ^ (1 / 60)) * FP_ONE */ +#define EXP_5 4082 /* (1 / e ^ (1 / 300)) * FP_ONE */ +#define EXP_15 4091 /* (1 / e ^ (1 / 900)) * FP_ONE */ + extern int optind, opterr, optopt; static struct { @@ -85,6 +106,11 @@ static struct { unsigned int recv_bits_total; unsigned int recv_bits_payload; unsigned int recv_bits_dbitrate; + unsigned int load_min; + unsigned int load_max; + unsigned int load_1m; + unsigned int load_5m; + unsigned int load_15m; } stat[MAXDEVS + 1]; static volatile int running = 1; @@ -96,8 +122,11 @@ static unsigned char redraw; static unsigned char timestamp; static unsigned char color; static unsigned char bargraph; +static bool statistic; +static bool reset; static enum cfl_mode mode = CFL_WORSTCASE; static char *prg; +static struct termios old; static void print_usage(char *prg) { @@ -111,6 +140,7 @@ static void print_usage(char *prg) fprintf(stderr, " -r (redraw the terminal - similar to top)\n"); fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n"); fprintf(stderr, " -e (exact calculation of stuffed bits)\n"); + fprintf(stderr, " -s (show statistics, press 'r' to reset)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXDEVS); fprintf(stderr, "commandline in the form: @[,]\n"); @@ -161,6 +191,16 @@ static void create_bitrate_string(int stat_idx, int *max_bitratestr_len) *max_bitratestr_len = ptr; } +static unsigned int calc_load(unsigned int load_fp, + unsigned int exp_fp, + unsigned int sample) +{ + unsigned int sample_fp = sample << FP_SHIFT; + unsigned int damped_sum = (load_fp * exp_fp) + + (sample_fp * (FP_ONE - exp_fp)); + return damped_sum >> FP_SHIFT; +} + static void printstats(int signo) { int i, j, percent; @@ -234,6 +274,30 @@ static void printstats(int signo) stat[i].recv_bits_dbitrate, percent); + if (statistic) { + if (reset) { + stat[i].load_min = UINT_MAX; + stat[i].load_max = 0; + stat[i].load_1m = 0; + stat[i].load_5m = 0; + stat[i].load_15m = 0; + } + + stat[i].load_min = MIN(stat[i].load_min, percent); + stat[i].load_max = MAX(stat[i].load_max, percent); + + stat[i].load_1m = calc_load(stat[i].load_1m, EXP_1, percent); + stat[i].load_5m = calc_load(stat[i].load_5m, EXP_5, percent); + stat[i].load_15m = calc_load(stat[i].load_15m, EXP_15, percent); + + printf(" min:%3d%%, max:%3d%%, load:%3d%% %3d%% %3d%%", + stat[i].load_min, + stat[i].load_max, + (stat[i].load_1m + (FP_ONE >> 1)) >> FP_SHIFT, + (stat[i].load_5m + (FP_ONE >> 1)) >> FP_SHIFT, + (stat[i].load_15m + (FP_ONE >> 1)) >> FP_SHIFT); + } + if (bargraph) { printf(" |"); @@ -264,6 +328,8 @@ static void printstats(int signo) stat[i].recv_direction = '.'; } + reset = false; + if (!redraw) printf("\n"); @@ -272,6 +338,11 @@ static void printstats(int signo) alarm(1); } +void cleanup() +{ + tcsetattr(STDIN_FILENO, TCSANOW, &old); +} + int main(int argc, char **argv) { fd_set rdfs; @@ -288,6 +359,13 @@ int main(int argc, char **argv) unsigned int anydev_bitrate = 0; unsigned int anydev_dbitrate = 0; char anydev_bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */ + struct termios temp; + + tcgetattr(STDIN_FILENO, &old); + atexit(cleanup); + temp = old; + temp.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &temp); signal(SIGTERM, sigterm); signal(SIGHUP, sigterm); @@ -297,7 +375,7 @@ int main(int argc, char **argv) prg = basename(argv[0]); - while ((opt = getopt(argc, argv, "rtbcieh?")) != -1) { + while ((opt = getopt(argc, argv, "rtbciesh?")) != -1) { switch (opt) { case 'r': redraw = 1; @@ -323,6 +401,11 @@ int main(int argc, char **argv) mode = CFL_EXACT; break; + case 's': + statistic = true; + reset = true; + break; + default: print_usage(prg); exit(1); @@ -449,12 +532,19 @@ int main(int argc, char **argv) while (running) { FD_ZERO(&rdfs); FD_SET(s, &rdfs); + FD_SET(STDIN_FILENO, &rdfs); if (select(s + 1, &rdfs, NULL, NULL, NULL) < 0) { //perror("pselect"); continue; } + if (FD_ISSET(STDIN_FILENO, &rdfs)) { + if (getchar() == 'r') { + reset = true; + } + } + /* these settings may be modified by recvmsg() */ iov.iov_len = sizeof(frame); msg.msg_namelen = sizeof(addr); From b3da2f62b93c197c5c4adbc43e37533617f60a2c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jan 2025 17:23:32 +0100 Subject: [PATCH 3/3] canbusload: support busload visualization Add '-v' option for visualize busload, the output shows a moving histogram of the past 90 seconds. canbusload 2024-09-23 17:19:33 (exact bitstuffing) can0@500k 487 55558 31048 0 99% |XXXXXXXXXXXXXXXXXXX.| 100%|.......................................................................................... 95%|..............................................................................XXXXXXXXXXXX 90%|.............................................................................XXXXXXXXXXXXX 85%|.............................................................................XXXXXXXXXXXXX 80%|.............................................................................XXXXXXXXXXXXX 75%|.............................................................................XXXXXXXXXXXXX 70%|.............................................................................XXXXXXXXXXXXX 65%|.............................................................................XXXXXXXXXXXXX 60%|............................................................................XXXXXXXXXXXXXX 55%|............................................................................XXXXXXXXXXXXXX 50%|............................................................................XXXXXXXXXXXXXX 45%|............................................................................XXXXXXXXXXXXXX 40%|............................................................................XXXXXXXXXXXXXX 35%|.........................................XXX................................XXXXXXXXXXXXXX 30%|.........................................XXXX...............................XXXXXXXXXXXXXX 25%|........................................XXXXXX.............................XXXXXXXXXXXXXXX 20%|XXXXXXXX...............................XXXXXXXXXXXXXXXXX....XXXXXXXXXXX...XXXXXXXXXXXXXXXX 15%|XXXXXXXXX.............................XXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 10%|XXXXXXXXX.XXXXXXXXXXXXXXXXXXX..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5%|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Signed-off-by: Zhu Yi Signed-off-by: Hubert Streidl Signed-off-by: Mark Jonas Link: https://lore.kernel.org/r/20250120162332.19157-3-mark.jonas@de.bosch.com Signed-off-by: Marc Kleine-Budde --- canbusload.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/canbusload.c b/canbusload.c index 4679da5..418b2ba 100644 --- a/canbusload.c +++ b/canbusload.c @@ -74,6 +74,7 @@ #define PERCENTRES 5 /* resolution in percent for bargraph */ #define NUMBAR (100 / PERCENTRES) /* number of bargraph elements */ #define BRSTRLEN 20 +#define VISUAL_WINDOW 90 /* window width for visualization */ /* * Inspired from @@ -111,19 +112,22 @@ static struct { unsigned int load_1m; unsigned int load_5m; unsigned int load_15m; + unsigned int loads[VISUAL_WINDOW]; + unsigned int index; } stat[MAXDEVS + 1]; static volatile int running = 1; static volatile sig_atomic_t signal_num; static int max_devname_len; /* to prevent frazzled device name output */ static int max_bitratestr_len; -static int currmax; +static unsigned int currmax; static unsigned char redraw; static unsigned char timestamp; static unsigned char color; static unsigned char bargraph; static bool statistic; static bool reset; +static bool visualize; static enum cfl_mode mode = CFL_WORSTCASE; static char *prg; static struct termios old; @@ -141,6 +145,7 @@ static void print_usage(char *prg) fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n"); fprintf(stderr, " -e (exact calculation of stuffed bits)\n"); fprintf(stderr, " -s (show statistics, press 'r' to reset)\n"); + fprintf(stderr, " -v (show busload visualization)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXDEVS); fprintf(stderr, "commandline in the form: @[,]\n"); @@ -203,7 +208,7 @@ static unsigned int calc_load(unsigned int load_fp, static void printstats(int signo) { - int i, j, percent; + unsigned int i, j, k, percent, index; if (redraw) printf("%s", CSR_HOME); @@ -315,6 +320,28 @@ static void printstats(int signo) printf("|"); } + if (visualize) { + stat[i].loads[stat[i].index] = percent; + stat[i].index = (stat[i].index + 1) % VISUAL_WINDOW; + + printf("\n"); + for (j = 0; j < NUMBAR; j++) { + printf("%3d%%|", (NUMBAR - j) * PERCENTRES); + index = stat[i].index; + for (k = 0; k < VISUAL_WINDOW; k++) { + percent = stat[i].loads[index]; + + if ((percent / PERCENTRES) >= (NUMBAR - j)) + printf("X"); + else + printf("."); + + index = (index + 1) % VISUAL_WINDOW; + } + printf("\n"); + } + } + if (color) printf("%s", ATTRESET); @@ -353,7 +380,8 @@ int main(int argc, char **argv) struct canfd_frame frame; struct iovec iov; struct msghdr msg; - int nbytes, i; + unsigned int i; + int nbytes; int have_anydev = 0; unsigned int anydev_bitrate = 0; @@ -375,7 +403,7 @@ int main(int argc, char **argv) prg = basename(argv[0]); - while ((opt = getopt(argc, argv, "rtbciesh?")) != -1) { + while ((opt = getopt(argc, argv, "rtbciesvh?")) != -1) { switch (opt) { case 'r': redraw = 1; @@ -406,6 +434,10 @@ int main(int argc, char **argv) reset = true; break; + case 'v': + visualize = true; + break; + default: print_usage(prg); exit(1);