tcp: dynamic max timers per loop

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: If0a634c277d4f8e4d32321f52253721a990bdb1d
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index c4da23c..e243f5a 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -1392,7 +1392,7 @@
     return;
 
   thread_index = wrk->vm->thread_index;
-  for (i = 0; i < clib_min (n_timers, 32); i++)
+  for (i = 0; i < clib_min (n_timers, wrk->max_timers_per_loop); i++)
     {
       clib_fifo_sub1 (wrk->pending_timers, timer_handle);
       connection_index = timer_handle & 0x0FFFFFFF;
@@ -1412,6 +1412,10 @@
 
       (*timer_expiration_handlers[timer_id]) (tc);
     }
+
+  if (thread_index == 0 && clib_fifo_elts (wrk->pending_timers))
+    vlib_process_signal_event_mt (wrk->vm, session_queue_process_node.index,
+				  SESSION_Q_PROCESS_FLUSH_FRAMES, 0);
 }
 
 /**
@@ -1511,8 +1515,8 @@
 static void
 tcp_expired_timers_dispatch (u32 * expired_timers)
 {
-  u32 thread_index = vlib_get_thread_index ();
-  u32 connection_index, timer_id, n_expired;
+  u32 thread_index = vlib_get_thread_index (), n_left, max_per_loop;
+  u32 connection_index, timer_id, n_expired, max_loops;
   tcp_worker_ctx_t *wrk;
   tcp_connection_t *tc;
   int i;
@@ -1520,6 +1524,7 @@
   wrk = tcp_get_worker (thread_index);
   n_expired = vec_len (expired_timers);
   tcp_workerp_stats_inc (wrk, timer_expirations, n_expired);
+  n_left = clib_fifo_elts (wrk->pending_timers);
 
   /*
    * Invalidate all timer handles before dispatching. This avoids dangling
@@ -1541,6 +1546,16 @@
     }
 
   clib_fifo_add (wrk->pending_timers, expired_timers, n_expired);
+
+  max_loops = clib_max (1, 0.5 * TCP_TIMER_TICK * wrk->vm->loops_per_second);
+  max_per_loop = clib_max ((n_left + n_expired) / max_loops, 10);
+  max_per_loop = clib_min (max_per_loop, VLIB_FRAME_SIZE);
+  wrk->max_timers_per_loop = clib_max (n_left ? wrk->max_timers_per_loop : 0,
+				       max_per_loop);
+
+  if (thread_index == 0)
+    vlib_process_signal_event_mt (wrk->vm, session_queue_process_node.index,
+				  SESSION_Q_PROCESS_FLUSH_FRAMES, 0);
 }
 
 static void
@@ -1612,6 +1627,7 @@
       vec_reset_length (wrk->pending_disconnects);
       vec_reset_length (wrk->pending_resets);
       wrk->vm = vlib_mains[thread];
+      wrk->max_timers_per_loop = 10;
 
       /*
        * Preallocate connections. Assume that thread 0 won't
diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h
index e7b53b8..bef7edb 100644
--- a/src/vnet/tcp/tcp.h
+++ b/src/vnet/tcp/tcp.h
@@ -544,6 +544,9 @@
   /** worker time */
   u32 time_now;
 
+  /* Max timers to be handled per dispatch loop */
+  u32 max_timers_per_loop;
+
   /** tx frames for ip 4/6 lookup nodes */
   vlib_frame_t *ip_lookup_tx_frames[2];