diff options
author | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2016-01-08 14:14:35 -0700 |
---|---|---|
committer | Kyle Yan <kyan@codeaurora.org> | 2016-04-28 16:37:50 -0700 |
commit | db859b609f7b8d62e366837c8e02cc68c28f2aae (patch) | |
tree | 5c4c360dc5f028ef26bde80c76fed6eb1f80da83 /net | |
parent | a5cfe2aa2a59b107a0db34de5a4a145effee530d (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.h | 3 | ||||
-rw-r--r-- | net/rmnet_data/rmnet_data_handlers.c | 35 |
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); |