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/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