]> granicus.if.org Git - sysstat/commitdiff
%ifutil: Add NIC utilization percentage to sar network stats
authorSebastien GODARD <sysstat@orange.fr.fake>
Sun, 23 Jun 2013 14:57:06 +0000 (16:57 +0200)
committerSebastien GODARD <sysstat@orange.fr.fake>
Sun, 23 Jun 2013 14:57:06 +0000 (16:57 +0200)
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
pr_stats.c
rd_stats.c
rd_stats.h
sa.h
sa_common.c
sa_wrap.c

index 2f9bc43a3224521ae171fe705f402768c902a272..5985cb2254713e3206657ea76b3c18f186c01cea 100644 (file)
@@ -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,
index 71e1045be8226917a607c5d242d9d8be63d95361..c59da6d5e89847450471f659830d2f80e1d07f96 100644 (file)
@@ -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);
        }
 }
 
index e760fb1fb7521a38174f0e71f429ba4d75881fc7..1115eb851d0151507290c2352fc3ac2220493e16 100644 (file)
@@ -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.
index ab499df34fe905868ff4c89a50db8f49b98aa8fa..827691078a6880546a14a52dd46ea84ab63adb21 100644 (file)
 #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 d13be4c287f5bc5e3eccf82cb2bbcb533175f13c..b21baa2567c19bd1aa2c658ad7f83f4fc95c01d8 100644 (file)
--- 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);
index fd0e19ee85ae1827ca977796ba91edbe9c57d487..f0a2a6080a7ebed8ce7c385442b7cf74e6e7e971 100644 (file)
@@ -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;
+}
+
index 13c59cd690302da7fb61c4a3c477b721213a9d63..4954b3fd6cda11244eace96f8e53f5cabef5eecd 100644 (file)
--- 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;
 }