From 25f4f3994a6f0b0bdfbc96f6d33ff03186dbca58 Mon Sep 17 00:00:00 2001 From: Debabrata Purohit Date: Thu, 14 Jun 2018 18:46:41 +0100 Subject: [PATCH] [9610] wlbt: traffic monitor - fix throughput report 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 --- drivers/net/wireless/scsc/dev.h | 10 ++- drivers/net/wireless/scsc/procfs.c | 20 +++--- drivers/net/wireless/scsc/traffic_monitor.c | 68 ++++++++++++++++++--- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/scsc/dev.h b/drivers/net/wireless/scsc/dev.h index a29a86edf7eb..3135477de2e7 100755 --- a/drivers/net/wireless/scsc/dev.h +++ b/drivers/net/wireless/scsc/dev.h @@ -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 { diff --git a/drivers/net/wireless/scsc/procfs.c b/drivers/net/wireless/scsc/procfs.c index d8a8f54a7c85..afafae56deac 100755 --- a/drivers/net/wireless/scsc/procfs.c +++ b/drivers/net/wireless/scsc/procfs.c @@ -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); diff --git a/drivers/net/wireless/scsc/traffic_monitor.c b/drivers/net/wireless/scsc/traffic_monitor.c index 00758f8f483c..7476ea9ff2e1 100644 --- a/drivers/net/wireless/scsc/traffic_monitor.c +++ b/drivers/net/wireless/scsc/traffic_monitor.c @@ -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; } } } -- 2.20.1