From: Michael Tremer Date: Thu, 19 Sep 2024 14:15:18 +0000 (+0000) Subject: ui: Add a graph and plot the sent/received traffic X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c846fc3851559658fd6d7d0de738cf1860aaad6a;p=fireperf.git ui: Add a graph and plot the sent/received traffic Signed-off-by: Michael Tremer --- diff --git a/src/stats.c b/src/stats.c index f9629d3..46a94f6 100644 --- a/src/stats.c +++ b/src/stats.c @@ -28,6 +28,21 @@ #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); diff --git a/src/stats.h b/src/stats.h index 273fbde..d15f49c 100644 --- a/src/stats.h +++ b/src/stats.h @@ -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); diff --git a/src/tui.c b/src/tui.c index 8bab23f..0e6433b 100644 --- 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); }