LCOV - code coverage report
Current view: top level - vlib - time.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 17 18 94.4 %
Date: 2023-07-05 22:20:52 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: Apache-2.0
       3             :  * Copyright(c) 2021 Cisco Systems, Inc.
       4             :  */
       5             : 
       6             : /* Virtual time allows to adjust VPP clock by arbitrary amount of time.
       7             :  * It is done such that the order of timer expirations is maintained,
       8             :  * and if a timer expiration callback reschedule another timer, this
       9             :  * timer will also properly expire in the right order. IOW, the order
      10             :  * of events is preserved.
      11             :  *
      12             :  * When moving time forward, each VPP thread (main and workers) runs an
      13             :  * instance of the input node 'virtual-time-input' below. This node is
      14             :  * responsible of advancing its own VPP thread clock to the next timer
      15             :  * expiration.  IOW each thread will move its clock independently one
      16             :  * timer at a time. This also means that while moving time forward, each
      17             :  * thread might not have the exact same view of what 'now' means. Once
      18             :  * the main thread has finished moving its time forward, the worker thread
      19             :  * barrier will ensure the timer between main and workers is synchronized.
      20             :  *
      21             :  * Using an input node in poll-mode has several advantages, including
      22             :  * preventing 'unix-epoll-input' to sleep (as it will not sleep if at
      23             :  * least one polling node is active). */
      24             : 
      25             : #include <vlib/vlib.h>
      26             : #include <vlib/time.h>
      27             : 
      28             : static f64 vlib_time_virtual_stop;
      29             : 
      30             : static uword
      31       31037 : vlib_time_virtual_input (vlib_main_t *vm, vlib_node_runtime_t *node,
      32             :                          vlib_frame_t *frame)
      33             : {
      34       31037 :   const f64 next = vlib_time_get_next_timer (vm);
      35             :   /* each thread will advance its own time. In case a thread is much faster
      36             :    * than another, we must make sure it does not run away... */
      37       31040 :   if (vlib_time_now (vm) + next > vlib_time_virtual_stop)
      38         125 :     vlib_node_set_state (vm, node->node_index, VLIB_NODE_STATE_DISABLED);
      39             :   else
      40       30920 :     vlib_time_adjust (vm, next);
      41       31045 :   return 0;
      42             : }
      43             : 
      44      178120 : VLIB_REGISTER_NODE (vlib_time_virtual_input_node) = {
      45             :   .function = vlib_time_virtual_input,
      46             :   .type = VLIB_NODE_TYPE_INPUT,
      47             :   .name = "virtual-time-input",
      48             :   .state = VLIB_NODE_STATE_DISABLED,
      49             : };
      50             : 
      51             : static clib_error_t *
      52          82 : vlib_time_virtual_adjust_command_fn (vlib_main_t *vm, unformat_input_t *input,
      53             :                                      vlib_cli_command_t *cmd)
      54             : {
      55             :   f64 val;
      56             : 
      57          82 :   if (!unformat (input, "%f", &val))
      58           0 :     return clib_error_create ("unknown input `%U'", format_unformat_error,
      59             :                               input);
      60             : 
      61          82 :   vlib_time_virtual_stop = vlib_time_now (vm) + val;
      62             : 
      63         222 :   foreach_vlib_main ()
      64         140 :     vlib_node_set_state (this_vlib_main, vlib_time_virtual_input_node.index,
      65             :                          VLIB_NODE_STATE_POLLING);
      66             : 
      67          82 :   vlib_worker_thread_barrier_release (vm);
      68          82 :   while ((val = vlib_process_wait_for_event_or_clock (vm, val)) >= 0.001)
      69             :     ;
      70             :   /* this barrier sync will resynchronize all the clocks, so even if the main
      71             :    * thread was faster than some workers, this will make sure the workers will
      72             :    * disable their virtual-time-input node on their next iteration (as stop
      73             :    * time is reached). If a worker is too slow, there is a slight chance
      74             :    * several of its timers expire at the same time at this point. Time will
      75             :    * tell... */
      76          82 :   vlib_worker_thread_barrier_sync (vm);
      77          82 :   return 0;
      78             : }
      79             : 
      80      272887 : VLIB_CLI_COMMAND (vlib_time_virtual_command) = {
      81             :   .path = "set clock adjust",
      82             :   .short_help = "set clock adjust <nn>",
      83             :   .function = vlib_time_virtual_adjust_command_fn,
      84             : };

Generated by: LCOV version 1.14