[9610] wlbt: traffic monitor - fix throughput report
authorDebabrata Purohit <d.purohit@samsung.com>
Thu, 14 Jun 2018 17:46:41 +0000 (18:46 +0100)
committerIvan Priest <i.priest@samsung.com>
Wed, 11 Jul 2018 17:43:17 +0000 (18:43 +0100)
1) The traffic monitor uses a jiffies based timer
which is not exactly accurate as it is not a
High resolution timer.

The throughput calculation assumes the time to be
same as the timer interval. But it causes the
throughput report to be slightly off the mark.

Measure exact time diff between each timer
interrupt to report accurate throughput.

2) report throughput per second instead of per
timer interval.

3) Apply a rough correction to exclude IP and
transport header from payload size calculation.

Change-Id: Icf595b2bd694b2877b67484db0c0bb57ca8c64d5
SCSC-Bug-Id: SSB-40955
Signed-off-by: Debabrata Purohit <d.purohit@samsung.com>
drivers/net/wireless/scsc/dev.h
drivers/net/wireless/scsc/procfs.c
drivers/net/wireless/scsc/traffic_monitor.c

index a29a86edf7eb693c27f94b009180e4bac391e8b0..3135477de2e7ca4425f335ff9132d87c487875b0 100755 (executable)
@@ -720,10 +720,16 @@ struct netdev_vif {
        bool wifi_sharing;
 #endif
        /* traffic monitor */
-       u32 num_bytes_tx;
-       u32 num_bytes_rx;
+       ktime_t last_timer_time;
+       u32 report_time;
+       u32 num_bytes_tx_per_timer;
+       u32 num_bytes_rx_per_timer;
+       u32 num_bytes_tx_per_sec;
+       u32 num_bytes_rx_per_sec;
        u32 throughput_tx;
        u32 throughput_rx;
+       u32 throughput_tx_bps;
+       u32 throughput_rx_bps;
 };
 
 struct slsi_802_11d_reg_domain {
index d8a8f54a7c8541d2ea260be72742a240228c5919..afafae56deac3a2942faf0c0e3c9d9e17da11d74 100755 (executable)
@@ -731,19 +731,19 @@ static ssize_t slsi_procfs_tput_read(struct file *file,  char __user *user_buf,
                if (dev) {
                        ndev_vif = netdev_priv(dev);
                        pos += scnprintf(buf + pos, bufsz - pos, "%s:\t", dev->name);
-                       if (ndev_vif->throughput_tx < 1000)
-                               pos += scnprintf(buf + pos, bufsz - pos, "TX:%u bps\t", ndev_vif->throughput_tx);
-                       else if ((ndev_vif->throughput_tx >= 1000) && (ndev_vif->throughput_tx < (1000 * 1000)))
-                               pos += scnprintf(buf + pos, bufsz - pos, "TX:%u Kbps\t", (ndev_vif->throughput_tx / 1000));
+                       if (ndev_vif->throughput_tx_bps < 1000)
+                               pos += scnprintf(buf + pos, bufsz - pos, "TX:%u bps\t", ndev_vif->throughput_tx_bps);
+                       else if ((ndev_vif->throughput_tx_bps >= 1000) && (ndev_vif->throughput_tx_bps < (1000 * 1000)))
+                               pos += scnprintf(buf + pos, bufsz - pos, "TX:%u Kbps\t", (ndev_vif->throughput_tx_bps / 1000));
                        else
-                               pos += scnprintf(buf + pos, bufsz - pos, "TX:%u Mbps\t", (ndev_vif->throughput_tx / (1000 * 1000)));
+                               pos += scnprintf(buf + pos, bufsz - pos, "TX:%u Mbps\t", (ndev_vif->throughput_tx_bps / (1000 * 1000)));
 
-                       if (ndev_vif->throughput_rx < 1000)
-                               pos += scnprintf(buf + pos, bufsz - pos, "RX:%u bps\n", ndev_vif->throughput_rx);
-                       else if ((ndev_vif->throughput_rx >= 1000) && (ndev_vif->throughput_rx < (1000 * 1000)))
-                               pos += scnprintf(buf + pos, bufsz - pos, "RX:%u Kbps\n", (ndev_vif->throughput_rx / 1000));
+                       if (ndev_vif->throughput_rx_bps < 1000)
+                               pos += scnprintf(buf + pos, bufsz - pos, "RX:%u bps\n", ndev_vif->throughput_rx_bps);
+                       else if ((ndev_vif->throughput_rx_bps >= 1000) && (ndev_vif->throughput_rx_bps < (1000 * 1000)))
+                               pos += scnprintf(buf + pos, bufsz - pos, "RX:%u Kbps\n", (ndev_vif->throughput_rx_bps / 1000));
                        else
-                               pos += scnprintf(buf + pos, bufsz - pos, "RX:%u Mbps\n", (ndev_vif->throughput_rx / (1000 * 1000)));
+                               pos += scnprintf(buf + pos, bufsz - pos, "RX:%u Mbps\n", (ndev_vif->throughput_rx_bps / (1000 * 1000)));
                }
        }
        SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
index 00758f8f483c0c9d9e0693c750ab2076388e76a5..7476ea9ff2e18ba1f1b9b798811a2ebce4a37d99 100644 (file)
@@ -87,10 +87,35 @@ static void traffic_mon_timer(unsigned long data)
                        ndev_vif = netdev_priv(dev);
 
                        if (ndev_vif) {
-                               ndev_vif->throughput_tx = (ndev_vif->num_bytes_tx * 8 / SLSI_TRAFFIC_MON_TIMER_PERIOD) * 1000;
-                               ndev_vif->throughput_rx = (ndev_vif->num_bytes_rx * 8 / SLSI_TRAFFIC_MON_TIMER_PERIOD) * 1000;
-                               ndev_vif->num_bytes_tx = 0;
-                               ndev_vif->num_bytes_rx = 0;
+                               u32 time_in_ms = 0;
+
+                               /* the Timer is jiffies based so resolution is not High and it may
+                                * be off by a few ms. So to accurately measure the throughput find
+                                * the time diff between last timer and this one
+                                */
+                               time_in_ms = ktime_to_ms(ktime_sub(ktime_get(), ndev_vif->last_timer_time));
+
+                               /* the Timer may be any value but it still needs to calculate the
+                                * throughput over a period of 1 second
+                                */
+                               ndev_vif->num_bytes_rx_per_sec += ndev_vif->num_bytes_rx_per_timer;
+                               ndev_vif->num_bytes_tx_per_sec += ndev_vif->num_bytes_tx_per_timer;
+                               ndev_vif->report_time += time_in_ms;
+                               if (ndev_vif->report_time >= 1000) {
+                                       ndev_vif->throughput_rx_bps = (ndev_vif->num_bytes_rx_per_sec * 8 / ndev_vif->report_time) * 1000;
+                                       ndev_vif->throughput_tx_bps = (ndev_vif->num_bytes_tx_per_sec * 8 / ndev_vif->report_time) * 1000;
+                                       ndev_vif->num_bytes_rx_per_sec = 0;
+                                       ndev_vif->num_bytes_tx_per_sec = 0;
+                                       ndev_vif->report_time = 0;
+                               }
+
+                               /* throughput per timer interval is measured but extrapolated to 1 sec */
+                               ndev_vif->throughput_tx = (ndev_vif->num_bytes_tx_per_timer * 8 / time_in_ms) * 1000;
+                               ndev_vif->throughput_rx = (ndev_vif->num_bytes_rx_per_timer * 8 / time_in_ms) * 1000;
+
+                               ndev_vif->num_bytes_tx_per_timer = 0;
+                               ndev_vif->num_bytes_rx_per_timer = 0;
+                               ndev_vif->last_timer_time = ktime_get();
                                tput_tx += ndev_vif->throughput_tx;
                                tput_rx += ndev_vif->throughput_rx;
                        }
@@ -109,7 +134,16 @@ inline void slsi_traffic_mon_event_rx(struct slsi_dev *sdev, struct net_device *
 {
        struct netdev_vif *ndev_vif = netdev_priv(dev);
 
-       ndev_vif->num_bytes_rx += skb->len;
+       /* Apply a correction to length to exclude IP and transport header.
+        * Can either peek into packets to derive the exact payload size
+        * or apply a rough correction to roughly calculate the throughput.
+        * rough correction  is applied with a number inbetween IP header (20 bytes) +
+        * UDP header (8 bytes) or TCP header (can be 20 bytes to 60 bytes) i.e. 40
+        */
+       if (skb->len >= 40)
+               ndev_vif->num_bytes_rx_per_timer += (skb->len - 40);
+       else
+               ndev_vif->num_bytes_rx_per_timer += skb->len;
 }
 
 inline void slsi_traffic_mon_event_tx(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb)
@@ -117,7 +151,10 @@ inline void slsi_traffic_mon_event_tx(struct slsi_dev *sdev, struct net_device *
        struct netdev_vif *ndev_vif = netdev_priv(dev);
        struct slsi_skb_cb *cb = slsi_skb_cb_get(skb);
 
-       ndev_vif->num_bytes_tx += (skb->len - cb->sig_length);
+       if ((skb->len - cb->sig_length) >= 40)
+               ndev_vif->num_bytes_tx_per_timer += ((skb->len - 40) - cb->sig_length);
+       else
+               ndev_vif->num_bytes_tx_per_timer += (skb->len - cb->sig_length);
 }
 
 u8 slsi_traffic_mon_is_running(struct slsi_dev *sdev)
@@ -181,8 +218,14 @@ int slsi_traffic_mon_client_register(
                                if (ndev_vif) {
                                        ndev_vif->throughput_tx = 0;
                                        ndev_vif->throughput_rx = 0;
-                                       ndev_vif->num_bytes_tx = 0;
-                                       ndev_vif->num_bytes_rx = 0;
+                                       ndev_vif->num_bytes_tx_per_timer = 0;
+                                       ndev_vif->num_bytes_rx_per_timer = 0;
+                                       ndev_vif->last_timer_time = ktime_get();
+                                       ndev_vif->num_bytes_rx_per_sec = 0;
+                                       ndev_vif->num_bytes_tx_per_sec = 0;
+                                       ndev_vif->throughput_rx_bps = 0;
+                                       ndev_vif->throughput_tx_bps = 0;
+                                       ndev_vif->report_time = 0;
                                }
                        }
                }
@@ -222,8 +265,13 @@ void slsi_traffic_mon_client_unregister(struct slsi_dev *sdev, void *client_ctx)
                                if (ndev_vif) {
                                        ndev_vif->throughput_tx = 0;
                                        ndev_vif->throughput_rx = 0;
-                                       ndev_vif->num_bytes_tx = 0;
-                                       ndev_vif->num_bytes_rx = 0;
+                                       ndev_vif->num_bytes_tx_per_timer = 0;
+                                       ndev_vif->num_bytes_rx_per_timer = 0;
+                                       ndev_vif->num_bytes_rx_per_sec = 0;
+                                       ndev_vif->num_bytes_tx_per_sec = 0;
+                                       ndev_vif->throughput_rx_bps = 0;
+                                       ndev_vif->throughput_tx_bps = 0;
+                                       ndev_vif->report_time = 0;
                                }
                        }
                }