union {
                struct {
                        /* There is space for up to 24 bytes */
-                       __u32 in_flight;/* Bytes in flight when packet sent */
+                       __u32 in_flight:30,/* Bytes in flight at transmit */
+                             is_app_limited:1, /* cwnd not fully used? */
+                             unused:1;
                        /* pkts S/ACKed so far upon tx of skb, incl retrans: */
                        __u32 delivered;
                        /* start of send pipeline phase */
        int  losses;            /* number of packets marked lost upon ACK */
        u32  acked_sacked;      /* number of packets newly (S)ACKed upon ACK */
        u32  prior_in_flight;   /* in flight before this ACK */
+       bool is_app_limited;    /* is sample from packet with bubble in pipe? */
        bool is_retrans;        /* is sample from retransmission? */
 };
 
                            struct rate_sample *rs);
 void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost,
                  struct skb_mstamp *now, struct rate_sample *rs);
+void tcp_rate_check_app_limited(struct sock *sk);
 
 /* These functions determine how the current flow behaves in respect of SACK
  * handling. SACK is negotiated with the peer, and therefore it can vary
 
         */
        tp->snd_cwnd = TCP_INIT_CWND;
 
+       /* There's a bubble in the pipe until at least the first ACK. */
+       tp->app_limited = ~0U;
+
        /* See draft-stevens-tcpca-spec-01 for discussion of the
         * initialization of these values.
         */
                                        flags);
 
        lock_sock(sk);
+
+       tcp_rate_check_app_limited(sk);  /* is sending application-limited? */
+
        res = do_tcp_sendpages(sk, page, offset, size, flags);
        release_sock(sk);
        return res;
 
        timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
+       tcp_rate_check_app_limited(sk);  /* is sending application-limited? */
+
        /* Wait for a connection to finish. One exception is TCP Fast Open
         * (passive side) where data is allowed to be sent before a connection
         * is fully established.
 
  * other factors like applications or receiver window limits.  The estimator
  * deliberately avoids using the inter-packet spacing approach because that
  * approach requires a large number of samples and sophisticated filtering.
+ *
+ * TCP flows can often be application-limited in request/response workloads.
+ * The estimator marks a bandwidth sample as application-limited if there
+ * was some moment during the sampled window of packets when there was no data
+ * ready to send in the write queue.
  */
 
-
 /* Snapshot the current delivery information in the skb, to generate
  * a rate sample later when the skb is (s)acked in tcp_rate_skb_delivered().
  */
        TCP_SKB_CB(skb)->tx.first_tx_mstamp     = tp->first_tx_mstamp;
        TCP_SKB_CB(skb)->tx.delivered_mstamp    = tp->delivered_mstamp;
        TCP_SKB_CB(skb)->tx.delivered           = tp->delivered;
+       TCP_SKB_CB(skb)->tx.is_app_limited      = tp->app_limited ? 1 : 0;
 }
 
 /* When an skb is sacked or acked, we fill in the rate sample with the (prior)
            after(scb->tx.delivered, rs->prior_delivered)) {
                rs->prior_delivered  = scb->tx.delivered;
                rs->prior_mstamp     = scb->tx.delivered_mstamp;
+               rs->is_app_limited   = scb->tx.is_app_limited;
                rs->is_retrans       = scb->sacked & TCPCB_RETRANS;
 
                /* Find the duration of the "send phase" of this window: */
        struct tcp_sock *tp = tcp_sk(sk);
        u32 snd_us, ack_us;
 
+       /* Clear app limited if bubble is acked and gone. */
+       if (tp->app_limited && after(tp->delivered, tp->app_limited))
+               tp->app_limited = 0;
+
        /* TODO: there are multiple places throughout tcp_ack() to get
         * current time. Refactor the code using a new "tcp_acktag_state"
         * to carry current time, flags, stats like "tcp_sacktag_state".
                                 tp->rx_opt.sack_ok, tcp_min_rtt(tp));
        }
 }
+
+/* If a gap is detected between sends, mark the socket application-limited. */
+void tcp_rate_check_app_limited(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+
+       if (/* We have less than one packet to send. */
+           tp->write_seq - tp->snd_nxt < tp->mss_cache &&
+           /* Nothing in sending host's qdisc queues or NIC tx queue. */
+           sk_wmem_alloc_get(sk) < SKB_TRUESIZE(1) &&
+           /* We are not limited by CWND. */
+           tcp_packets_in_flight(tp) < tp->snd_cwnd &&
+           /* All lost packets have been retransmitted. */
+           tp->lost_out <= tp->retrans_out)
+               tp->app_limited =
+                       (tp->delivered + tcp_packets_in_flight(tp)) ? : 1;
+}