summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2016-01-08 14:14:35 -0700
committerKyle Yan <kyan@codeaurora.org>2016-04-28 16:37:50 -0700
commitdb859b609f7b8d62e366837c8e02cc68c28f2aae (patch)
tree5c4c360dc5f028ef26bde80c76fed6eb1f80da83 /net
parenta5cfe2aa2a59b107a0db34de5a4a145effee530d (diff)
net: rmnet_data: Add a GRO flush timer
The current GRO implementation relies on NET_RX to complete processing or the max possible TCP segment size for it to flush the GRO coalesced packets. This leads to coalescing a large number of packets which translates to very few ACKs. Since the number of ACKs are very few and delayed during the slow start phase (stretch ACK's), we see that the initial throughput ramp up is slow compared to normal RFC TCP where we send an ACK per two packets. Note that there is no difference between GRO and non GRO after the max window size is reached. Add a mechanism within rmnet_data to force the flush of packets every 10 micro seconds (experimentally determined) by default. This is controlled by the module parameter "gro_flush_time" and can be configured to any value less than a second. To disable this feature, set this entry to 0. This reduces the coalesce of packets which translates to increased number of ACK's compared to normal GRO but lesser ACK's compared to NO GRO. There is no increase in power for a day to day use case. Note that this optimization is specific to TCP GRO path only. Some useful stats below for TCP DL at 400Mbps - |TCP GRO Default | TCP GRO flush timer 10us ================================================================== iperf 1st second tput | 300Mbps | 330Mbps coalesce ratio | 15 | 4.5 CRs-Fixed: 961186 Change-Id: Ie8d76c493d61f3f4c256dbaa0378b22a361eed49 Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Diffstat (limited to 'net')
-rw-r--r--net/rmnet_data/rmnet_data_config.h3
-rw-r--r--net/rmnet_data/rmnet_data_handlers.c35
2 files changed, 37 insertions, 1 deletions
diff --git a/net/rmnet_data/rmnet_data_config.h b/net/rmnet_data/rmnet_data_config.h
index fe668a86eb45..a76bcef79e6a 100644
--- a/net/rmnet_data/rmnet_data_config.h
+++ b/net/rmnet_data/rmnet_data_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@ struct rmnet_logical_ep_conf_s {
uint8_t refcount;
uint8_t rmnet_mode;
uint8_t mux_id;
+ struct timespec flush_time;
struct net_device *egress_dev;
};
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 8b3ed2cdffbf..7ea599f746c2 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -45,6 +45,11 @@ module_param(dump_pkt_tx, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dump_pkt_tx, "Dump packets exiting egress handler");
#endif /* CONFIG_RMNET_DATA_DEBUG_PKT */
+/* Time in nano seconds. This number must be less that a second. */
+long gro_flush_time __read_mostly = 10000L;
+module_param(gro_flush_time, long, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(gro_flush_time, "Flush GRO when spaced more than this");
+
#define RMNET_DATA_IP_VERSION_4 0x40
#define RMNET_DATA_IP_VERSION_6 0x60
@@ -217,6 +222,35 @@ static int rmnet_check_skb_can_gro(struct sk_buff *skb)
}
/**
+ * rmnet_optional_gro_flush() - Check if GRO handler needs to flush now
+ *
+ * Determines whether GRO handler needs to flush packets which it has
+ * coalesced so far.
+ *
+ * Tuning this parameter will trade TCP slow start performance for GRO coalesce
+ * ratio.
+ */
+static void rmnet_optional_gro_flush(struct napi_struct *napi,
+ struct rmnet_logical_ep_conf_s *ep)
+{
+ struct timespec curr_time, diff;
+
+ if (!gro_flush_time)
+ return;
+
+ if (unlikely(ep->flush_time.tv_sec == 0)) {
+ getnstimeofday(&ep->flush_time);
+ } else {
+ getnstimeofday(&(curr_time));
+ diff = timespec_sub(curr_time, ep->flush_time);
+ if ((diff.tv_sec > 0) || (diff.tv_nsec > gro_flush_time)) {
+ napi_gro_flush(napi, false);
+ getnstimeofday(&ep->flush_time);
+ }
+ }
+}
+
+/**
* __rmnet_deliver_skb() - Deliver skb
*
* Determines where to deliver skb. Options are: consume by network stack,
@@ -256,6 +290,7 @@ static rx_handler_result_t __rmnet_deliver_skb(struct sk_buff *skb,
if (napi != NULL) {
gro_res = napi_gro_receive(napi, skb);
trace_rmnet_gro_downlink(gro_res);
+ rmnet_optional_gro_flush(napi, ep);
} else {
WARN_ONCE(1, "current napi is NULL\n");
netif_receive_skb(skb);