From: Zhu Yi <yi.zhu5@xxxxxxxxxxxx> 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 <yi.zhu5@xxxxxxxxxxxx> Signed-off-by: Hubert Streidl <hubert.streidl@xxxxxxxxxxxx> Signed-off-by: Mark Jonas <mark.jonas@xxxxxxxxxxxx> --- canbusload.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/canbusload.c b/canbusload.c index 753d658..577d99c 100644 --- a/canbusload.c +++ b/canbusload.c @@ -48,11 +48,13 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <termios.h> #include <time.h> #include <unistd.h> #include <net/if.h> #include <sys/ioctl.h> +#include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> @@ -72,6 +74,34 @@ #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 */ + +inline 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; +} + extern int optind, opterr, optopt; static struct { @@ -85,6 +115,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 +131,11 @@ static unsigned char redraw; static unsigned char timestamp; static unsigned char color; static unsigned char bargraph; +static unsigned char statistic; +static unsigned char reset; static enum cfl_mode mode = CFL_WORSTCASE; static char *prg; +static struct termios old; static void print_usage(char *prg) { @@ -111,6 +149,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: <ifname>@<bitrate>[,<dbitrate>]\n"); @@ -234,6 +273,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 +327,8 @@ static void printstats(int signo) stat[i].recv_direction = '.'; } + reset = 0; + if (!redraw) printf("\n"); @@ -272,6 +337,11 @@ static void printstats(int signo) alarm(1); } +void cleanup() +{ + tcsetattr(STDIN_FILENO, TCSANOW, &old); +} + int main(int argc, char **argv) { fd_set rdfs; @@ -289,6 +359,14 @@ int main(int argc, char **argv) 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); signal(SIGINT, 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 = 1; + reset = 1; + 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 = 1; + } + } + /* these settings may be modified by recvmsg() */ iov.iov_len = sizeof(frame); msg.msg_namelen = sizeof(addr); -- 2.34.1