diff mbox

[net-next,07/14] tcp: export data delivery rate

Message ID 1474051743-13311-8-git-send-email-ncardwell@google.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Neal Cardwell Sept. 16, 2016, 6:48 p.m. UTC
From: Yuchung Cheng <ycheng@google.com>

This commit export two new fields in struct tcp_info:

  tcpi_delivery_rate: The most recent goodput, as measured by
    tcp_rate_gen(). If the socket is limited by the sending
    application (e.g., no data to send), it reports the highest
    measurement instead of the most recent. The unit is bytes per
    second (like other rate fields in tcp_info).

  tcpi_delivery_rate_app_limited: A boolean indicating if the goodput
    was measured when the socket's throughput was limited by the
    sending application.

This delivery rate information can be useful for applications that
want to know the current throughput the TCP connection is seeing,
e.g. adaptive bitrate video streaming. It can also be very useful for
debugging or troubleshooting.

Signed-off-by: Van Jacobson <vanj@google.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Nandita Dukkipati <nanditad@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
---
 include/linux/tcp.h      |  5 ++++-
 include/uapi/linux/tcp.h |  3 +++
 net/ipv4/tcp.c           | 11 ++++++++++-
 net/ipv4/tcp_rate.c      | 12 +++++++++++-
 4 files changed, 28 insertions(+), 3 deletions(-)

Comments

Neal Cardwell Sept. 16, 2016, 8:03 p.m. UTC | #1
On Fri, Sep 16, 2016 at 11:56 PM, kbuild test robot <lkp@intel.com> wrote:
>
>>> net/ipv4/tcp.c:2794:3: note: in expansion of macro 'do_div'
>       do_div(rate, intv);
>       ^~~~~~
>    In file included from arch/arm/include/asm/div64.h:126:0,
>                     from include/linux/kernel.h:142,
>                     from include/linux/crypto.h:21,
>                     from include/crypto/hash.h:16,
>                     from net/ipv4/tcp.c:250:
>>> include/asm-generic/div64.h:224:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
>       __rem = __div64_32(&(n), __base); \
...
> > 2794                  do_div(rate, intv);

Looks like 'rate' should be 'rate64'. I will include this fix in the
next version of the patch series.

neal
Eric Dumazet Sept. 16, 2016, 8:04 p.m. UTC | #2
On Sat, 2016-09-17 at 11:56 +0800, kbuild test robot wrote:
> Hi Yuchung,
> 
> [auto build test ERROR on net-next/master]
> 
> url:    https://github.com/0day-ci/linux/commits/Neal-Cardwell/tcp-BBR-congestion-control-algorithm/20160917-025323
> config: arm-nhk8815_defconfig (attached as .config)
> compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
> reproduce:
>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         make.cross ARCH=arm 

Right, we need to include <asm/div64.h>  for some arches.
Eric Dumazet Sept. 16, 2016, 8:11 p.m. UTC | #3
On Fri, Sep 16, 2016 at 1:03 PM, Neal Cardwell <ncardwell@google.com> wrote:

>
> Looks like 'rate' should be 'rate64'. I will include this fix in the
> next version of the patch series.
>
> neal


Oh, right you are !
kernel test robot Sept. 16, 2016, 9:38 p.m. UTC | #4
Hi Yuchung,

[auto build test ERROR on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Neal-Cardwell/tcp-BBR-congestion-control-algorithm/20160917-025323
config: arm-simpad_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   In file included from include/linux/kernel.h:142:0,
                    from include/linux/crypto.h:21,
                    from include/crypto/hash.h:16,
                    from net/ipv4/tcp.c:250:
   net/ipv4/tcp.c: In function 'tcp_get_info':
>> arch/arm/include/asm/div64.h:59:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
    #define do_div(n, base) __div64_32(&(n), base)
                                       ^
   net/ipv4/tcp.c:2794:3: note: in expansion of macro 'do_div'
      do_div(rate, intv);
      ^~~~~~
   arch/arm/include/asm/div64.h:32:24: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'u32 * {aka unsigned int *}'
    static inline uint32_t __div64_32(uint64_t *n, uint32_t base)
                           ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/__div64_32 +59 arch/arm/include/asm/div64.h

040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  43  		: "=r" (__rem), "=r" (__res)
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  44  		: "r" (__n), "r" (__base)
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  45  		: "ip", "lr", "cc");
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  46  	*n = __res;
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  47  	return __rem;
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  48  }
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  49  #define __div64_32 __div64_32
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  50  
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  51  #if !defined(CONFIG_AEABI)
fa4adc614 include/asm-arm/div64.h      Nicolas Pitre 2006-12-06  52  
fa4adc614 include/asm-arm/div64.h      Nicolas Pitre 2006-12-06  53  /*
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  54   * In OABI configurations, some uses of the do_div function
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  55   * cause gcc to run out of registers. To work around that,
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  56   * we can force the use of the out-of-line version for
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  57   * configurations that build a OABI kernel.
fa4adc614 include/asm-arm/div64.h      Nicolas Pitre 2006-12-06  58   */
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02 @59  #define do_div(n, base) __div64_32(&(n), base)
fa4adc614 include/asm-arm/div64.h      Nicolas Pitre 2006-12-06  60  
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  61  #else
fa4adc614 include/asm-arm/div64.h      Nicolas Pitre 2006-12-06  62  
fa4adc614 include/asm-arm/div64.h      Nicolas Pitre 2006-12-06  63  /*
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  64   * gcc versions earlier than 4.0 are simply too problematic for the
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  65   * __div64_const32() code in asm-generic/div64.h. First there is
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  66   * gcc PR 15089 that tend to trig on more complex constructs, spurious
040b323b5 arch/arm/include/asm/div64.h Nicolas Pitre 2015-11-02  67   * .global __udivsi3 are inserted even if none of those symbols are

:::::: The code at line 59 was first introduced by commit
:::::: 040b323b5012b5503561ec7fe15cccd6a4bcaec2 ARM: asm/div64.h: adjust to generic codde

:::::: TO: Nicolas Pitre <nicolas.pitre@linaro.org>
:::::: CC: Nicolas Pitre <nicolas.pitre@linaro.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Sept. 17, 2016, 3:56 a.m. UTC | #5
Hi Yuchung,

[auto build test ERROR on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Neal-Cardwell/tcp-BBR-congestion-control-algorithm/20160917-025323
config: arm-nhk8815_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All error/warnings (new ones prefixed by >>):

   In file included from arch/arm/include/asm/div64.h:126:0,
                    from include/linux/kernel.h:142,
                    from include/linux/crypto.h:21,
                    from include/crypto/hash.h:16,
                    from net/ipv4/tcp.c:250:
   net/ipv4/tcp.c: In function 'tcp_get_info':
   include/asm-generic/div64.h:207:28: warning: comparison of distinct pointer types lacks a cast
     (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \
                               ^
>> net/ipv4/tcp.c:2794:3: note: in expansion of macro 'do_div'
      do_div(rate, intv);
      ^~~~~~
   In file included from arch/arm/include/asm/atomic.h:14:0,
                    from include/linux/atomic.h:4,
                    from include/linux/crypto.h:20,
                    from include/crypto/hash.h:16,
                    from net/ipv4/tcp.c:250:
   include/asm-generic/div64.h:220:25: warning: right shift count >= width of type [-Wshift-count-overflow]
     } else if (likely(((n) >> 32) == 0)) {  \
                            ^
   include/linux/compiler.h:167:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
>> net/ipv4/tcp.c:2794:3: note: in expansion of macro 'do_div'
      do_div(rate, intv);
      ^~~~~~
   In file included from arch/arm/include/asm/div64.h:126:0,
                    from include/linux/kernel.h:142,
                    from include/linux/crypto.h:21,
                    from include/crypto/hash.h:16,
                    from net/ipv4/tcp.c:250:
>> include/asm-generic/div64.h:224:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
      __rem = __div64_32(&(n), __base); \
                         ^
>> net/ipv4/tcp.c:2794:3: note: in expansion of macro 'do_div'
      do_div(rate, intv);
      ^~~~~~
   In file included from include/linux/kernel.h:142:0,
                    from include/linux/crypto.h:21,
                    from include/crypto/hash.h:16,
                    from net/ipv4/tcp.c:250:
   arch/arm/include/asm/div64.h:32:24: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'u32 * {aka unsigned int *}'
    static inline uint32_t __div64_32(uint64_t *n, uint32_t base)
                           ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/do_div +2794 net/ipv4/tcp.c

  2778		} while (u64_stats_fetch_retry_irq(&tp->syncp, start));
  2779		info->tcpi_segs_out = tp->segs_out;
  2780		info->tcpi_segs_in = tp->segs_in;
  2781	
  2782		notsent_bytes = READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt);
  2783		info->tcpi_notsent_bytes = max(0, notsent_bytes);
  2784	
  2785		info->tcpi_min_rtt = tcp_min_rtt(tp);
  2786		info->tcpi_data_segs_in = tp->data_segs_in;
  2787		info->tcpi_data_segs_out = tp->data_segs_out;
  2788	
  2789		info->tcpi_delivery_rate_app_limited = tp->rate_app_limited ? 1 : 0;
  2790		rate = READ_ONCE(tp->rate_delivered);
  2791		intv = READ_ONCE(tp->rate_interval_us);
  2792		if (rate && intv) {
  2793			rate = rate * tp->mss_cache * USEC_PER_SEC;
> 2794			do_div(rate, intv);
  2795			put_unaligned(rate, &info->tcpi_delivery_rate);
  2796		}
  2797	}
  2798	EXPORT_SYMBOL_GPL(tcp_get_info);
  2799	
  2800	static int do_tcp_getsockopt(struct sock *sk, int level,
  2801			int optname, char __user *optval, int __user *optlen)
  2802	{

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index fdcd00f..a17ae7b 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -213,7 +213,8 @@  struct tcp_sock {
 		u8 reord;    /* reordering detected */
 	} rack;
 	u16	advmss;		/* Advertised MSS			*/
-	u8	unused;
+	u8	rate_app_limited:1,  /* rate_{delivered,interval_us} limited? */
+		unused:7;
 	u8	nonagle     : 4,/* Disable Nagle algorithm?             */
 		thin_lto    : 1,/* Use linear timeouts for thin streams */
 		thin_dupack : 1,/* Fast retransmit on first dupack      */
@@ -271,6 +272,8 @@  struct tcp_sock {
 	u32	app_limited;	/* limited until "delivered" reaches this val */
 	struct skb_mstamp first_tx_mstamp;  /* start of window send phase */
 	struct skb_mstamp delivered_mstamp; /* time we reached "delivered" */
+	u32	rate_delivered;    /* saved rate sample: packets delivered */
+	u32	rate_interval_us;  /* saved rate sample: time elapsed */
 
  	u32	rcv_wnd;	/* Current receiver window		*/
 	u32	write_seq;	/* Tail(+1) of data held in tcp send buffer */
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index 482898f..73ac0db 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -167,6 +167,7 @@  struct tcp_info {
 	__u8	tcpi_backoff;
 	__u8	tcpi_options;
 	__u8	tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+	__u8	tcpi_delivery_rate_app_limited:1;
 
 	__u32	tcpi_rto;
 	__u32	tcpi_ato;
@@ -211,6 +212,8 @@  struct tcp_info {
 	__u32	tcpi_min_rtt;
 	__u32	tcpi_data_segs_in;	/* RFC4898 tcpEStatsDataSegsIn */
 	__u32	tcpi_data_segs_out;	/* RFC4898 tcpEStatsDataSegsOut */
+
+	__u64   tcpi_delivery_rate;
 };
 
 /* for TCP_MD5SIG socket option */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 6c7a6fc..7358101 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2695,7 +2695,7 @@  void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
 	const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */
 	const struct inet_connection_sock *icsk = inet_csk(sk);
-	u32 now = tcp_time_stamp;
+	u32 now = tcp_time_stamp, intv;
 	unsigned int start;
 	int notsent_bytes;
 	u64 rate64;
@@ -2785,6 +2785,15 @@  void tcp_get_info(struct sock *sk, struct tcp_info *info)
 	info->tcpi_min_rtt = tcp_min_rtt(tp);
 	info->tcpi_data_segs_in = tp->data_segs_in;
 	info->tcpi_data_segs_out = tp->data_segs_out;
+
+	info->tcpi_delivery_rate_app_limited = tp->rate_app_limited ? 1 : 0;
+	rate = READ_ONCE(tp->rate_delivered);
+	intv = READ_ONCE(tp->rate_interval_us);
+	if (rate && intv) {
+		rate = rate * tp->mss_cache * USEC_PER_SEC;
+		do_div(rate, intv);
+		put_unaligned(rate, &info->tcpi_delivery_rate);
+	}
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
diff --git a/net/ipv4/tcp_rate.c b/net/ipv4/tcp_rate.c
index 52ff84b..9be1581 100644
--- a/net/ipv4/tcp_rate.c
+++ b/net/ipv4/tcp_rate.c
@@ -149,12 +149,22 @@  void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost,
 	 * for connections suffer heavy or prolonged losses.
 	 */
 	if (unlikely(rs->interval_us < tcp_min_rtt(tp))) {
-		rs->interval_us = -1;
 		if (!rs->is_retrans)
 			pr_debug("tcp rate: %ld %d %u %u %u\n",
 				 rs->interval_us, rs->delivered,
 				 inet_csk(sk)->icsk_ca_state,
 				 tp->rx_opt.sack_ok, tcp_min_rtt(tp));
+		rs->interval_us = -1;
+		return;
+	}
+
+	/* Record the last non-app-limited or the highest app-limited bw */
+	if (!rs->is_app_limited ||
+	    ((u64)rs->delivered * tp->rate_interval_us >=
+	     (u64)tp->rate_delivered * rs->interval_us)) {
+		tp->rate_delivered = rs->delivered;
+		tp->rate_interval_us = rs->interval_us;
+		tp->rate_app_limited = rs->is_app_limited;
 	}
 }