]> git.ipfire.org Git - fireperf.git/commitdiff
ui: Add a graph and plot the sent/received traffic
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Sep 2024 14:15:18 +0000 (14:15 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Sep 2024 14:15:18 +0000 (14:15 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/stats.c
src/stats.h
src/tui.c

index f9629d36db2d6ff2ad84633ff05008cca5bb9bb7..46a94f62499bb75b87378defb0d3e699d5a0e73c 100644 (file)
 #include "stats.h"
 #include "util.h"
 
+struct fireperf_stats fireperf_stats_step(
+               const struct fireperf_stats* old, const struct fireperf_stats* new) {
+       struct fireperf_stats stats = {
+               .t                    = new->t,
+               .open_connections     = new->open_connections,
+               .connections          = new->connections - old->connections,
+               .total_bytes_received = new->total_bytes_received,
+               .bytes_received       = new->total_bytes_received - old->total_bytes_received,
+               .total_bytes_sent     = new->total_bytes_sent,
+               .bytes_sent           = new->total_bytes_sent - old->total_bytes_sent,
+       };
+
+       return stats;
+}
+
 int fireperf_stats_dump(struct fireperf_ctx* ctx,
                struct fireperf_stats* old, struct fireperf_stats* new) {
        // Compute the delta since the last dump
@@ -38,16 +53,7 @@ int fireperf_stats_dump(struct fireperf_ctx* ctx,
                return 0;
 
        // Compute the changes
-       const struct fireperf_stats stats = {
-               .t                    = new->t,
-               .open_connections     = new->open_connections,
-               .connections          = new->connections - old->connections,
-               .total_bytes_received = new->total_bytes_received,
-               .bytes_received       = new->total_bytes_received - old->total_bytes_received,
-               .total_bytes_sent     = new->total_bytes_sent,
-               .bytes_sent           = new->total_bytes_sent - old->total_bytes_sent,
-
-       };
+       const struct fireperf_stats stats = fireperf_stats_step(old, new);
 
        // Format timestamp
        const char* timestamp = format_timespec(&stats.t);
index 273fbdeba2d5b36688275e122c11a2b8869a35da..d15f49c2eaee0cbaebb50eb5f64454b11b1b1fc7 100644 (file)
@@ -43,6 +43,9 @@ struct fireperf_stats {
 // Forward declararion
 struct fireperf_ctx;
 
+struct fireperf_stats fireperf_stats_step(
+       const struct fireperf_stats* old, const struct fireperf_stats* new);
+
 int fireperf_stats_dump(struct fireperf_ctx* ctx,
        struct fireperf_stats* old, struct fireperf_stats* new);
 
index 8bab23f50a2fcb8f5b987aa584e5d8fb52cd632d..0e6433b9f1d5f73fb6bd7ac738e1104da6046abb 100644 (file)
--- a/src/tui.c
+++ b/src/tui.c
@@ -30,7 +30,7 @@
 #include "stats.h"
 #include "tui.h"
 
-#define MAX_STATS 128
+#define MAX_STATS 1024
 
 struct fireperf_tui {
        struct fireperf_ctx* ctx;
@@ -45,10 +45,27 @@ struct fireperf_tui {
        // The frame around the screen
        WINDOW* frame;
 
+       // The graph inside the frame
+       WINDOW* graph;
+
        // The status bar
        WINDOW* status;
 };
 
+static int fireperf_tui_setup_graph(struct fireperf_tui* tui) {
+       int r;
+
+       // Create the graph
+       tui->graph = newwin(LINES - 3, COLS - 3, 1, 1);
+       if (!tui->graph)
+               return 1;
+
+       // Refresh
+       wrefresh(tui->graph);
+
+       return 0;
+}
+
 static int fireperf_tui_setup_frame(struct fireperf_tui* tui) {
        int r;
 
@@ -117,7 +134,7 @@ static int fireperf_tui_setup(struct fireperf_tui* tui) {
 
        // Configure a few colours
        init_pair(1, COLOR_RED,    COLOR_BLACK);
-       init_pair(2, COLOR_YELLOW, COLOR_BLACK);
+       init_pair(2, COLOR_GREEN,  COLOR_BLACK);
        init_pair(3, COLOR_BLUE,   COLOR_BLACK);
        init_pair(4, COLOR_BLACK,  COLOR_WHITE);
 
@@ -147,6 +164,11 @@ static int fireperf_tui_setup(struct fireperf_tui* tui) {
        if (r)
                return r;
 
+       // Setup the graph
+       r = fireperf_tui_setup_graph(tui);
+       if (r)
+               return r;
+
        // Setup the status bar
        r = fireperf_tui_setup_status(tui);
        if (r)
@@ -229,17 +251,91 @@ int fireperf_tui_action(struct fireperf_tui* tui) {
        return 0;
 }
 
+static const struct fireperf_stats* fireperf_tui_get_stats(struct fireperf_tui* tui, int i) {
+       return &tui->stats[(tui->s - i) % MAX_STATS];
+}
+
+static size_t fireperf_tui_get_peak_bps(struct fireperf_tui* tui, int max) {
+       const struct fireperf_stats* stats = NULL;
+       size_t peak = 0;
+
+       for (unsigned int i = 0; i < max; i++) {
+               stats = fireperf_tui_get_stats(tui, i);
+
+               if (stats->bytes_sent > peak)
+                       peak = stats->bytes_sent;
+
+               if (stats->bytes_received > peak)
+                       peak = stats->bytes_received;
+       }
+
+       return peak;
+}
+
+/*
+       Draws the big graph
+*/
+static int fireperf_tui_draw_graph(struct fireperf_tui* tui) {
+       const struct fireperf_stats* stats = NULL;
+
+       int max_x = 0;
+       int max_y = 0;
+
+       // Clear any previous content
+       wclear(tui->graph);
+
+       // Fetch the dimensions of the frame
+       getmaxyx(tui->graph, max_y, max_x);
+
+       size_t peak_bps = fireperf_tui_get_peak_bps(tui, max_x);
+
+       // Figure out how many bps a step represents
+       double step = peak_bps / (max_y + 1);
+
+       // Make the brush red
+       wattron(tui->graph, COLOR_PAIR(1));
+
+       // Draw any sent traffic
+       for (unsigned int x = 0; x < max_x; x++) {
+               stats = fireperf_tui_get_stats(tui, x);
+
+               mvwaddch(tui->graph, max_y - (stats->bytes_sent / step), x, '#');
+       }
+
+       wattroff(tui->graph, COLOR_PAIR(1));
+
+       // Make the brush green
+       wattron(tui->graph, COLOR_PAIR(2));
+
+       // Draw any received traffic
+       for (unsigned int x = 0; x < max_x; x++) {
+               stats = fireperf_tui_get_stats(tui, x);
+
+               mvwaddch(tui->graph, max_y - (stats->bytes_received / step), x, '#');
+       }
+
+       wattroff(tui->graph, COLOR_PAIR(2));
+
+       wrefresh(tui->graph);
+
+       return 0;
+}
+
 /*
        Called when there is new data to update the UI
 */
 int fireperf_tui_update(struct fireperf_tui* tui, struct fireperf_stats stats) {
        int r;
 
+       // Fetch the previous stats
+       const struct fireperf_stats* prev_stats = fireperf_tui_get_stats(tui, 1);
+
        // Store stats
-       tui->stats[tui->s++] = stats;
+       tui->stats[tui->s++] = fireperf_stats_step(prev_stats, &stats);
 
        // Wrap the pointer around
        tui->s %= MAX_STATS;
 
-       return 0;
+       // Draw the graph
+       return fireperf_tui_draw_graph(tui);
 }