[can-utils][PATCH 2/3] canbusload: support busload statistic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux