session: allow small pacer bursts

Instead of enforcing a "strict" release of data, which relies on
frequent rescheduling of sessions, allow some pacer coalescing, i.e.,
short bursts, that can minimize load on scheduler/session layer and
potentially leverage tso.

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I67e38e5b8dc335bd214113b70c68c27ae92bd6da
diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c
index 8a350d4..1208012 100644
--- a/src/vnet/session/session_node.c
+++ b/src/vnet/session/session_node.c
@@ -1037,7 +1037,8 @@
       return SESSION_TX_NO_BUFFERS;
     }
 
-  transport_connection_update_tx_bytes (ctx->tc, ctx->max_len_to_snd);
+  if (transport_connection_is_tx_paced (ctx->tc))
+    transport_connection_tx_pacer_update_bytes (ctx->tc, ctx->max_len_to_snd);
 
   ctx->left_to_snd = ctx->max_len_to_snd;
   n_left = ctx->n_segs_per_evt;
diff --git a/src/vnet/session/transport.c b/src/vnet/session/transport.c
index 967ff5d..a7fd85f 100644
--- a/src/vnet/session/transport.c
+++ b/src/vnet/session/transport.c
@@ -632,9 +632,9 @@
 
   now = transport_us_time_now (thread_index);
   diff = now - pacer->last_update;
-  s = format (s, "rate %lu bucket %lu t/p %.3f last_update %U idle %u",
+  s = format (s, "rate %lu bucket %lu t/p %.3f last_update %U burst %u",
 	      pacer->bytes_per_sec, pacer->bucket, pacer->tokens_per_period,
-	      format_clib_us_time, diff, pacer->idle_timeout_us);
+	      format_clib_us_time, diff, pacer->max_burst);
   return s;
 }
 
@@ -644,26 +644,18 @@
   u64 n_periods = (time_now - pacer->last_update);
   u64 inc;
 
-  if (PREDICT_FALSE (n_periods > pacer->idle_timeout_us))
-    {
-      pacer->last_update = time_now;
-      pacer->bucket = TRANSPORT_PACER_MIN_BURST;
-      return TRANSPORT_PACER_MIN_BURST;
-    }
-
   if ((inc = (f32) n_periods * pacer->tokens_per_period) > 10)
     {
       pacer->last_update = time_now;
-      pacer->bucket = clib_min (pacer->bucket + inc, pacer->bytes_per_sec);
+      pacer->bucket = clib_min (pacer->bucket + inc, pacer->max_burst);
     }
 
-  return clib_min (pacer->bucket, TRANSPORT_PACER_MAX_BURST);
+  return pacer->bucket > 0 ? pacer->max_burst : 0;
 }
 
 static inline void
 spacer_update_bucket (spacer_t * pacer, u32 bytes)
 {
-  ASSERT (pacer->bucket >= bytes);
   pacer->bucket -= bytes;
 }
 
@@ -671,11 +663,26 @@
 spacer_set_pace_rate (spacer_t * pacer, u64 rate_bytes_per_sec,
 		      clib_us_time_t rtt)
 {
+  clib_us_time_t max_time;
+
   ASSERT (rate_bytes_per_sec != 0);
   pacer->bytes_per_sec = rate_bytes_per_sec;
   pacer->tokens_per_period = rate_bytes_per_sec * CLIB_US_TIME_PERIOD;
-  pacer->idle_timeout_us = clib_max (rtt * TRANSPORT_PACER_IDLE_FACTOR,
-				     TRANSPORT_PACER_MIN_IDLE);
+
+  /* Allow a min number of bursts per rtt, if their size is acceptable. Goal
+   * is to spread the sending of data over the rtt but to also allow for some
+   * coalescing that can potentially
+   * 1) reduce load on session layer by reducing scheduling frequency for a
+   *    session and
+   * 2) optimize sending when tso if available
+   *
+   * Max "time-length" of a burst cannot be less than 1us or more than 1ms.
+   */
+  max_time = rtt / TRANSPORT_PACER_BURSTS_PER_RTT;
+  max_time = clib_clamp (max_time, 1 /* 1us */ , 1000 /* 1ms */ );
+  pacer->max_burst = (rate_bytes_per_sec * max_time) * CLIB_US_TIME_PERIOD;
+  pacer->max_burst = clib_clamp (pacer->max_burst, TRANSPORT_PACER_MIN_BURST,
+				 TRANSPORT_PACER_MAX_BURST);
 }
 
 static inline u64
diff --git a/src/vnet/session/transport.h b/src/vnet/session/transport.h
index c8d4e27..9a9b89f 100644
--- a/src/vnet/session/transport.h
+++ b/src/vnet/session/transport.h
@@ -23,6 +23,7 @@
 #define TRANSPORT_PACER_MIN_BURST 	TRANSPORT_PACER_MIN_MSS
 #define TRANSPORT_PACER_MAX_BURST	(43 * TRANSPORT_PACER_MIN_MSS)
 #define TRANSPORT_PACER_MAX_BURST_PKTS	43
+#define TRANSPORT_PACER_BURSTS_PER_RTT	20
 #define TRANSPORT_PACER_MIN_IDLE	100
 #define TRANSPORT_PACER_IDLE_FACTOR	0.05
 
diff --git a/src/vnet/session/transport_types.h b/src/vnet/session/transport_types.h
index ab34d9f..2caafea 100644
--- a/src/vnet/session/transport_types.h
+++ b/src/vnet/session/transport_types.h
@@ -65,10 +65,10 @@
 typedef struct _spacer
 {
   u64 bytes_per_sec;
-  u64 bucket;
+  i64 bucket;
   clib_us_time_t last_update;
   f32 tokens_per_period;
-  u32 idle_timeout_us;
+  u32 max_burst;
 } spacer_t;
 
 #define TRANSPORT_CONN_ID_LEN	44
@@ -146,8 +146,8 @@
 #define c_stats connection.stats
 #define c_pacer connection.pacer
 #define c_flags connection.flags
-#define s_ho_handle pacer.bucket
-#define c_s_ho_handle connection.pacer.bucket
+#define s_ho_handle pacer.bytes_per_sec
+#define c_s_ho_handle connection.pacer.bytes_per_sec
 } transport_connection_t;
 
 STATIC_ASSERT (STRUCT_OFFSET_OF (transport_connection_t, s_index)