44#include <string.h>
55#include <stdlib.h>
66#include <signal.h>
7+ #include <limits.h>
78#include <sys/select.h>
89#include <termios.h>
910#include <time.h>
@@ -130,11 +131,13 @@ struct overview_metrics {
130131 unsigned long long rss_kb ;
131132 unsigned long long rx_bytes ;
132133 unsigned long long tx_bytes ;
134+ unsigned long long read_bytes ;
133135 unsigned long long write_bytes ;
134136 int has_cpu ;
135137 int has_rss ;
136138 int has_rx ;
137139 int has_tx ;
140+ int has_read ;
138141 int has_write ;
139142};
140143
@@ -469,6 +472,48 @@ static int parse_first_u64(const char *line, unsigned long long *value)
469472 return sscanf (cursor , "%llu" , value ) == 1 ;
470473}
471474
475+ static int parse_size_field_bytes (const char * line , unsigned long long * value )
476+ {
477+ char unit [8 ] = {0 };
478+ const char * cursor ;
479+ unsigned long long number ;
480+ unsigned long long multiplier = 1 ;
481+
482+ if (!line || !value )
483+ return 0 ;
484+
485+ cursor = line ;
486+ while (* cursor && (* cursor < '0' || * cursor > '9' ))
487+ cursor ++ ;
488+
489+ if (* cursor == '\0' )
490+ return 0 ;
491+
492+ if (sscanf (cursor , "%llu %7s" , & number , unit ) < 1 )
493+ return 0 ;
494+
495+ if (unit [0 ] != '\0' ) {
496+ if (strcmp (unit , "B" ) == 0 )
497+ multiplier = 1 ;
498+ else if (strcmp (unit , "KB" ) == 0 )
499+ multiplier = 1024ULL ;
500+ else if (strcmp (unit , "MB" ) == 0 )
501+ multiplier = 1024ULL * 1024ULL ;
502+ else if (strcmp (unit , "GB" ) == 0 )
503+ multiplier = 1024ULL * 1024ULL * 1024ULL ;
504+ else if (strcmp (unit , "TB" ) == 0 )
505+ multiplier = 1024ULL * 1024ULL * 1024ULL * 1024ULL ;
506+ else
507+ return 0 ;
508+ }
509+
510+ if (number > (ULLONG_MAX / multiplier ))
511+ return 0 ;
512+
513+ * value = number * multiplier ;
514+ return 1 ;
515+ }
516+
472517static void extract_overview_metrics (const struct live_snapshot * snapshot ,
473518 struct overview_metrics * metrics )
474519{
@@ -495,17 +540,22 @@ static void extract_overview_metrics(const struct live_snapshot *snapshot,
495540 }
496541
497542 if (copy_line_with_prefix (snapshot -> det_content , "rx_bytes:" , line , sizeof (line )) &&
498- parse_first_u64 (line , & metrics -> rx_bytes )) {
543+ parse_size_field_bytes (line , & metrics -> rx_bytes )) {
499544 metrics -> has_rx = 1 ;
500545 }
501546
502547 if (copy_line_with_prefix (snapshot -> det_content , "tx_bytes:" , line , sizeof (line )) &&
503- parse_first_u64 (line , & metrics -> tx_bytes )) {
548+ parse_size_field_bytes (line , & metrics -> tx_bytes )) {
504549 metrics -> has_tx = 1 ;
505550 }
506551
552+ if (copy_line_with_prefix (snapshot -> det_content , "read_bytes:" , line , sizeof (line )) &&
553+ parse_size_field_bytes (line , & metrics -> read_bytes )) {
554+ metrics -> has_read = 1 ;
555+ }
556+
507557 if (copy_line_with_prefix (snapshot -> det_content , "write_bytes:" , line , sizeof (line )) &&
508- parse_first_u64 (line , & metrics -> write_bytes )) {
558+ parse_size_field_bytes (line , & metrics -> write_bytes )) {
509559 metrics -> has_write = 1 ;
510560 }
511561}
@@ -592,6 +642,7 @@ static int collect_overview_series(const struct live_snapshot *history,
592642 unsigned long long * rss_values ,
593643 unsigned long long * rx_rate_values ,
594644 unsigned long long * tx_rate_values ,
645+ unsigned long long * read_rate_values ,
595646 unsigned long long * write_rate_values ,
596647 int max_values )
597648{
@@ -636,6 +687,13 @@ static int collect_overview_series(const struct live_snapshot *history,
636687 tx_rate_values [points ] = 0 ;
637688 }
638689
690+ if (have_previous && metrics .has_read && previous_metrics .has_read &&
691+ metrics .read_bytes >= previous_metrics .read_bytes ) {
692+ read_rate_values [points ] = metrics .read_bytes - previous_metrics .read_bytes ;
693+ } else {
694+ read_rate_values [points ] = 0 ;
695+ }
696+
639697 if (have_previous && metrics .has_write && previous_metrics .has_write &&
640698 metrics .write_bytes >= previous_metrics .write_bytes ) {
641699 write_rate_values [points ] =
@@ -662,47 +720,56 @@ static void print_overview_plots(const struct live_snapshot *snapshot,
662720 unsigned long long rss_values [OVERVIEW_PLOT_WIDTH ];
663721 unsigned long long rx_rate_values [OVERVIEW_PLOT_WIDTH ];
664722 unsigned long long tx_rate_values [OVERVIEW_PLOT_WIDTH ];
723+ unsigned long long read_rate_values [OVERVIEW_PLOT_WIDTH ];
665724 unsigned long long write_rate_values [OVERVIEW_PLOT_WIDTH ];
666725 struct overview_metrics current_metrics ;
667726 char cpu_plot [OVERVIEW_PLOT_BUF_SIZE ];
668727 char rss_plot [OVERVIEW_PLOT_BUF_SIZE ];
669728 char rx_plot [OVERVIEW_PLOT_BUF_SIZE ];
670729 char tx_plot [OVERVIEW_PLOT_BUF_SIZE ];
730+ char read_plot [OVERVIEW_PLOT_BUF_SIZE ];
671731 char write_plot [OVERVIEW_PLOT_BUF_SIZE ];
672732 char rss_label [32 ];
673733 char rx_label [32 ];
674734 char tx_label [32 ];
735+ char read_label [32 ];
675736 char write_label [32 ];
676737 unsigned long long current_rx_rate = 0 ;
677738 unsigned long long current_tx_rate = 0 ;
739+ unsigned long long current_read_rate = 0 ;
678740 unsigned long long current_write_rate = 0 ;
679741 int point_count ;
680742
681743 memset (cpu_values , 0 , sizeof (cpu_values ));
682744 memset (rss_values , 0 , sizeof (rss_values ));
683745 memset (rx_rate_values , 0 , sizeof (rx_rate_values ));
684746 memset (tx_rate_values , 0 , sizeof (tx_rate_values ));
747+ memset (read_rate_values , 0 , sizeof (read_rate_values ));
685748 memset (write_rate_values , 0 , sizeof (write_rate_values ));
686749
687- point_count = collect_overview_series (
688- history , history_count , history_next , browse_offset , cpu_values , rss_values ,
689- rx_rate_values , tx_rate_values , write_rate_values , ARRAY_SIZE (cpu_values ));
750+ point_count = collect_overview_series (history , history_count , history_next , browse_offset ,
751+ cpu_values , rss_values , rx_rate_values ,
752+ tx_rate_values , read_rate_values , write_rate_values ,
753+ ARRAY_SIZE (cpu_values ));
690754 render_sparkline (cpu_values , point_count , cpu_plot , sizeof (cpu_plot ));
691755 render_sparkline (rss_values , point_count , rss_plot , sizeof (rss_plot ));
692756 render_sparkline (rx_rate_values , point_count , rx_plot , sizeof (rx_plot ));
693757 render_sparkline (tx_rate_values , point_count , tx_plot , sizeof (tx_plot ));
758+ render_sparkline (read_rate_values , point_count , read_plot , sizeof (read_plot ));
694759 render_sparkline (write_rate_values , point_count , write_plot , sizeof (write_plot ));
695760
696761 extract_overview_metrics (snapshot , & current_metrics );
697762 if (point_count > 0 ) {
698763 current_rx_rate = rx_rate_values [point_count - 1 ];
699764 current_tx_rate = tx_rate_values [point_count - 1 ];
765+ current_read_rate = read_rate_values [point_count - 1 ];
700766 current_write_rate = write_rate_values [point_count - 1 ];
701767 }
702768
703769 format_compact_size (current_metrics .rss_kb * 1024ULL , rss_label , sizeof (rss_label ), NULL );
704770 format_compact_size (current_rx_rate , rx_label , sizeof (rx_label ), "/s" );
705771 format_compact_size (current_tx_rate , tx_label , sizeof (tx_label ), "/s" );
772+ format_compact_size (current_read_rate , read_label , sizeof (read_label ), "/s" );
706773 format_compact_size (current_write_rate , write_label , sizeof (write_label ), "/s" );
707774
708775 printf ("%s%sTRENDS%s\n" , color_code (C_CYAN ), color_code (C_BOLD ), color_code (C_RESET ));
@@ -725,6 +792,9 @@ static void print_overview_plots(const struct live_snapshot *snapshot,
725792 printf ("%s TX/s |%s| %s%s\n" , color_code (C_CYAN ), tx_plot , tx_label ,
726793 color_code (C_RESET ));
727794 puts ("" );
795+ printf ("%s RD/s |%s| %s%s\n" , color_code (C_CYAN ), read_plot , read_label ,
796+ color_code (C_RESET ));
797+ puts ("" );
728798 printf ("%s WR/s |%s| %s%s\n" , color_code (C_CYAN ), write_plot , write_label ,
729799 color_code (C_RESET ));
730800 puts ("" );
0 commit comments