From 194bdd87bb3eb88f87ff017b006c7073fde0154b Mon Sep 17 00:00:00 2001 From: Sebastien GODARD Date: Sun, 23 Jun 2013 16:57:06 +0200 Subject: [PATCH] %ifutil: Add NIC utilization percentage to sar network stats This patch adds %ifutil to statistics displayed by sar -n. %ifutil is a new metric giving the utilization percentage of the corresponding network interface. --- activity.c | 4 +-- pr_stats.c | 15 +++++++++--- rd_stats.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++-- rd_stats.h | 16 ++++++++++-- sa.h | 2 ++ sa_common.c | 39 +++++++++++++++++++++++++++++ sa_wrap.c | 9 ++++++- 7 files changed, 144 insertions(+), 11 deletions(-) diff --git a/activity.c b/activity.c index 2f9bc43..5985cb2 100644 --- a/activity.c +++ b/activity.c @@ -415,7 +415,7 @@ struct activity disk_act = { struct activity net_dev_act = { .id = A_NET_DEV, .options = AO_COLLECTED, - .magic = ACTIVITY_MAGIC_BASE + 1, + .magic = ACTIVITY_MAGIC_BASE + 2, .group = G_DEFAULT, #ifdef SOURCE_SADC .f_count = wrap_get_iface_nr, @@ -430,7 +430,7 @@ struct activity net_dev_act = { .f_render = render_net_dev_stats, .f_xml_print = xml_print_net_dev_stats, .f_json_print = json_print_net_dev_stats, - .hdr_line = "IFACE;rxpck/s;txpck/s;rxkB/s;txkB/s;rxcmp/s;txcmp/s;rxmcst/s", + .hdr_line = "IFACE;rxpck/s;txpck/s;rxkB/s;txkB/s;rxcmp/s;txcmp/s;rxmcst/s;%ifutil", .name = "A_NET_DEV", #endif .nr = -1, diff --git a/pr_stats.c b/pr_stats.c index 71e1045..c59da6d 100644 --- a/pr_stats.c +++ b/pr_stats.c @@ -905,10 +905,11 @@ __print_funct_t print_net_dev_stats(struct activity *a, int prev, int curr, { int i, j; struct stats_net_dev *sndc, *sndp; + double rxkb, txkb, ifutil; if (dis) { printf("\n%-11s IFACE rxpck/s txpck/s rxkB/s txkB/s" - " rxcmp/s txcmp/s rxmcst/s\n", timestamp[!curr]); + " rxcmp/s txcmp/s rxmcst/s %%ifutil\n", timestamp[!curr]); } for (i = 0; i < a->nr; i++) { @@ -923,14 +924,20 @@ __print_funct_t print_net_dev_stats(struct activity *a, int prev, int curr, printf("%-11s %9s", timestamp[curr], sndc->interface); - printf(" %9.2f %9.2f %9.2f %9.2f %9.2f %9.2f %9.2f\n", + rxkb = S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv); + txkb = S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv); + + printf(" %9.2f %9.2f %9.2f %9.2f %9.2f %9.2f %9.2f", S_VALUE(sndp->rx_packets, sndc->rx_packets, itv), S_VALUE(sndp->tx_packets, sndc->tx_packets, itv), - S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv) / 1024, - S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv) / 1024, + rxkb / 1024, + txkb / 1024, S_VALUE(sndp->rx_compressed, sndc->rx_compressed, itv), S_VALUE(sndp->tx_compressed, sndc->tx_compressed, itv), S_VALUE(sndp->multicast, sndc->multicast, itv)); + + ifutil = compute_ifutil(sndc, rxkb, txkb); + printf(" %6.2f\n", ifutil); } } diff --git a/rd_stats.c b/rd_stats.c index e760fb1..1115eb8 100644 --- a/rd_stats.c +++ b/rd_stats.c @@ -726,9 +726,12 @@ void read_kernel_tables(struct stats_ktables *st_ktables) * * OUT: * @st_net_dev Structure with statistics. + * + * RETURNS: + * Number of interfaces for which stats have been read. *************************************************************************** */ -void read_net_dev(struct stats_net_dev *st_net_dev, int nbr) +int read_net_dev(struct stats_net_dev *st_net_dev, int nbr) { FILE *fp; struct stats_net_dev *st_net_dev_i; @@ -738,7 +741,7 @@ void read_net_dev(struct stats_net_dev *st_net_dev, int nbr) int pos; if ((fp = fopen(NET_DEV, "r")) == NULL) - return; + return 0; while ((fgets(line, 256, fp) != NULL) && (dev < nbr)) { @@ -762,8 +765,71 @@ void read_net_dev(struct stats_net_dev *st_net_dev, int nbr) } fclose(fp); + + return dev; +} + +/* + *************************************************************************** + * Read duplex and speed data for network interface cards. + *void + * IN: + * @st_net_dev Structure where stats will be saved. + * @nbr Real number of network interfaces available. + * + * OUT: + * @st_net_dev Structure with statistics. + *************************************************************************** + */ +void read_if_info(struct stats_net_dev *st_net_dev, int nbr) +{ + FILE *fp; + struct stats_net_dev *st_net_dev_i; + char filename[128], duplex[32]; + int dev, n; + + for (dev = 0; dev < nbr; dev++) { + + st_net_dev_i = st_net_dev + dev; + + /* Read speed info */ + sprintf(filename, IF_DUPLEX, st_net_dev_i->interface); + + if ((fp = fopen(filename, "r")) == NULL) + /* Cannot read NIC duplex */ + continue; + + n = fscanf(fp, "%s", duplex); + + fclose(fp); + + if (n != 1) + /* Cannot read NIC duplex */ + continue; + + if (!strcmp(duplex, K_DUPLEX_FULL)) { + st_net_dev_i->duplex = C_DUPLEX_FULL; + } + else if (!strcmp(duplex, K_DUPLEX_HALF)) { + st_net_dev_i->duplex = C_DUPLEX_HALF; + } + else + continue; + + /* Read speed info */ + sprintf(filename, IF_SPEED, st_net_dev_i->interface); + + if ((fp = fopen(filename, "r")) == NULL) + /* Cannot read NIC speed */ + continue; + + fscanf(fp, "%u", &st_net_dev_i->speed); + + fclose(fp); + } } + /* *************************************************************************** * Read network interfaces errors statistics from /proc/net/dev. diff --git a/rd_stats.h b/rd_stats.h index ab499df..8276910 100644 --- a/rd_stats.h +++ b/rd_stats.h @@ -34,6 +34,12 @@ #define CNT_ALL_DEV 0 #define CNT_USED_DEV 1 +#define K_DUPLEX_HALF "half" +#define K_DUPLEX_FULL "full" + +#define C_DUPLEX_HALF 1 +#define C_DUPLEX_FULL 2 + /* *************************************************************************** * System files containing statistics @@ -58,6 +64,8 @@ #define NET_SNMP6 "/proc/net/snmp6" #define CPUINFO "/proc/cpuinfo" #define MTAB "/etc/mtab" +#define IF_DUPLEX "/sys/class/net/%s/duplex" +#define IF_SPEED "/sys/class/net/%s/speed" /* @@ -225,7 +233,9 @@ struct stats_net_dev { unsigned long long rx_compressed __attribute__ ((aligned (16))); unsigned long long tx_compressed __attribute__ ((aligned (16))); unsigned long long multicast __attribute__ ((aligned (16))); - char interface[MAX_IFACE_LEN] __attribute__ ((aligned (16))); + unsigned int speed __attribute__ ((aligned (16))); + char interface[MAX_IFACE_LEN] __attribute__ ((aligned (4))); + char duplex; }; #define STATS_NET_DEV_SIZE (sizeof(struct stats_net_dev)) @@ -565,8 +575,10 @@ extern void read_tty_driver_serial(struct stats_serial *, int); extern void read_kernel_tables(struct stats_ktables *); -extern void +extern int read_net_dev(struct stats_net_dev *, int); +extern void + read_if_info(struct stats_net_dev *, int); extern void read_net_edev(struct stats_net_edev *, int); extern void diff --git a/sa.h b/sa.h index d13be4c..b21baa2 100644 --- a/sa.h +++ b/sa.h @@ -803,6 +803,8 @@ extern unsigned int check_net_dev_reg(struct activity *, int, int, unsigned int); extern unsigned int check_net_edev_reg(struct activity *, int, int, unsigned int); +extern double + compute_ifutil(struct stats_net_dev *, double, double); extern void copy_structures(struct activity * [], unsigned int [], struct record_header [], int, int); diff --git a/sa_common.c b/sa_common.c index fd0e19e..f0a2a60 100644 --- a/sa_common.c +++ b/sa_common.c @@ -1664,3 +1664,42 @@ int parse_sa_P_opt(char *argv[], int *opt, unsigned int *flags, struct activity return 0; } +/* + *************************************************************************** + * Compute network interface utilization. + * + * IN: + * @st_net_dev Structure with network interface stats. + * @rx Number of bytes received per second. + * @tx Number of bytes transmitted per second. + * + * RETURNS: + * NIC utilization (0-100%). + *************************************************************************** + */ +double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx) +{ + unsigned long long speed; + + if (st_net_dev->speed) { + + speed = st_net_dev->speed * 1000000; + + if (st_net_dev->duplex == C_DUPLEX_FULL) { + /* Full duplex */ + if (rx > tx) { + return (rx * 800 / speed); + } + else { + return (tx * 800 / speed); + } + } + else { + /* Half duplex */ + return ((rx + tx) * 800 / speed); + } + } + + return 0; +} + diff --git a/sa_wrap.c b/sa_wrap.c index 13c59cd..4954b3f 100644 --- a/sa_wrap.c +++ b/sa_wrap.c @@ -284,9 +284,16 @@ __read_funct_t wrap_read_net_dev(struct activity *a) { struct stats_net_dev *st_net_dev = (struct stats_net_dev *) a->_buf0; + int dev; /* Read network interfaces stats */ - read_net_dev(st_net_dev, a->nr); + dev = read_net_dev(st_net_dev, a->nr); + if (!dev) + /* No data read. Exit */ + return; + + /* Read duplex and speed info for each interface */ + read_if_info(st_net_dev, dev); return; } -- 2.40.0