LCOV - code coverage report
Current view: top level - plugins/bufmon - bufmon.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 3 134 2.2 %
Date: 2023-07-05 22:20:52 Functions: 6 17 35.3 %

          Line data    Source code
       1             : #include <vlib/vlib.h>
       2             : #include <vnet/plugin/plugin.h>
       3             : #include <vpp/app/version.h>
       4             : 
       5             : typedef struct
       6             : {
       7             :   u64 in;
       8             :   u64 out;
       9             :   u64 alloc;
      10             :   u64 free;
      11             : } bufmon_per_node_data_t;
      12             : 
      13             : typedef struct
      14             : {
      15             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
      16             :   bufmon_per_node_data_t *pnd;
      17             :   u32 cur_node;
      18             : } bufmon_per_thread_data_t;
      19             : 
      20             : typedef struct
      21             : {
      22             :   bufmon_per_thread_data_t *ptd;
      23             :   int enabled;
      24             : } bufmon_main_t;
      25             : 
      26             : static bufmon_main_t bufmon_main;
      27             : 
      28             : static u32
      29           0 : bufmon_alloc_free_callback (vlib_main_t *vm, u32 n_buffers, const int is_free)
      30             : {
      31           0 :   bufmon_main_t *bm = &bufmon_main;
      32             :   bufmon_per_thread_data_t *ptd;
      33             :   bufmon_per_node_data_t *pnd;
      34             :   u32 cur_node;
      35             : 
      36           0 :   if (PREDICT_FALSE (vm->thread_index >= vec_len (bm->ptd)))
      37             :     {
      38           0 :       clib_warning ("bufmon: thread index %d unknown for buffer %s (%d)",
      39             :                     vm->thread_index, is_free ? "free" : "alloc", n_buffers);
      40           0 :       return n_buffers;
      41             :     }
      42             : 
      43           0 :   ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
      44             : 
      45           0 :   cur_node = ptd->cur_node;
      46           0 :   if (cur_node >= vec_len (ptd->pnd))
      47             :     {
      48           0 :       cur_node = vlib_get_current_process_node_index (vm);
      49           0 :       vec_validate_aligned (ptd->pnd, cur_node, CLIB_CACHE_LINE_BYTES);
      50             :     }
      51             : 
      52           0 :   pnd = vec_elt_at_index (ptd->pnd, cur_node);
      53             : 
      54           0 :   if (is_free)
      55           0 :     pnd->free += n_buffers;
      56             :   else
      57           0 :     pnd->alloc += n_buffers;
      58             : 
      59           0 :   return n_buffers;
      60             : }
      61             : 
      62             : static u32
      63           0 : bufmon_alloc_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
      64             :                        u32 n_buffers)
      65             : {
      66           0 :   return bufmon_alloc_free_callback (vm, n_buffers, 0 /* is_free */);
      67             : }
      68             : 
      69             : static u32
      70           0 : bufmon_free_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
      71             :                       u32 n_buffers)
      72             : {
      73           0 :   return bufmon_alloc_free_callback (vm, n_buffers, 1 /* is_free */);
      74             : }
      75             : 
      76             : static u32
      77           0 : bufmon_count_buffers (vlib_main_t *vm, vlib_frame_t *frame)
      78             : {
      79             :   vlib_buffer_t *b[VLIB_FRAME_SIZE];
      80           0 :   u32 *from = vlib_frame_vector_args (frame);
      81           0 :   const u32 n = frame->n_vectors;
      82           0 :   u32 nc = 0;
      83             :   u32 i;
      84             : 
      85           0 :   vlib_get_buffers (vm, from, b, n);
      86             : 
      87           0 :   for (i = 0; i < n; i++)
      88             :     {
      89           0 :       const vlib_buffer_t *cb = b[i];
      90           0 :       while (cb->flags & VLIB_BUFFER_NEXT_PRESENT)
      91             :         {
      92           0 :           nc++;
      93           0 :           cb = vlib_get_buffer (vm, cb->next_buffer);
      94             :         }
      95             :     }
      96             : 
      97           0 :   return n + nc;
      98             : }
      99             : 
     100             : static uword
     101           0 : bufmon_dispatch_wrapper (vlib_main_t *vm, vlib_node_runtime_t *node,
     102             :                          vlib_frame_t *frame)
     103             : {
     104           0 :   vlib_node_main_t *nm = &vm->node_main;
     105           0 :   bufmon_main_t *bm = &bufmon_main;
     106             :   bufmon_per_thread_data_t *ptd;
     107             :   bufmon_per_node_data_t *pnd;
     108             :   int pending_frames;
     109             :   uword rv;
     110             : 
     111           0 :   ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
     112           0 :   vec_validate_aligned (ptd->pnd, node->node_index, CLIB_CACHE_LINE_BYTES);
     113           0 :   pnd = vec_elt_at_index (ptd->pnd, node->node_index);
     114             : 
     115           0 :   if (frame)
     116           0 :     pnd->in += bufmon_count_buffers (vm, frame);
     117             : 
     118           0 :   pending_frames = vec_len (nm->pending_frames);
     119           0 :   ptd->cur_node = node->node_index;
     120             : 
     121           0 :   rv = node->function (vm, node, frame);
     122             : 
     123           0 :   ptd->cur_node = ~0;
     124           0 :   for (; pending_frames < vec_len (nm->pending_frames); pending_frames++)
     125             :     {
     126           0 :       vlib_pending_frame_t *p =
     127           0 :         vec_elt_at_index (nm->pending_frames, pending_frames);
     128           0 :       pnd->out += bufmon_count_buffers (vm, vlib_get_frame (vm, p->frame));
     129             :     }
     130             : 
     131           0 :   return rv;
     132             : }
     133             : 
     134             : static void
     135           0 : bufmon_unregister_callbacks (vlib_main_t *vm)
     136             : {
     137           0 :   vlib_buffer_set_alloc_free_callback (vm, 0, 0);
     138           0 :   foreach_vlib_main ()
     139           0 :     vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
     140           0 : }
     141             : 
     142             : static clib_error_t *
     143           0 : bufmon_register_callbacks (vlib_main_t *vm)
     144             : {
     145           0 :   if (vlib_buffer_set_alloc_free_callback (vm, bufmon_alloc_callback,
     146             :                                            bufmon_free_callback))
     147           0 :     goto err0;
     148             : 
     149           0 :   foreach_vlib_main ()
     150           0 :     if (vlib_node_set_dispatch_wrapper (this_vlib_main,
     151             :                                         bufmon_dispatch_wrapper))
     152           0 :       goto err1;
     153             : 
     154           0 :   vec_validate_aligned (bufmon_main.ptd, vlib_thread_main.n_vlib_mains - 1,
     155             :                         CLIB_CACHE_LINE_BYTES);
     156           0 :   return 0;
     157             : 
     158           0 : err1:
     159           0 :   foreach_vlib_main ()
     160           0 :     vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
     161           0 : err0:
     162           0 :   vlib_buffer_set_alloc_free_callback (vm, 0, 0);
     163           0 :   return clib_error_return (0, "failed to register callback");
     164             : }
     165             : 
     166             : static clib_error_t *
     167           0 : bufmon_enable_disable (vlib_main_t *vm, int enable)
     168             : {
     169           0 :   bufmon_main_t *bm = &bufmon_main;
     170             : 
     171           0 :   if (enable)
     172             :     {
     173           0 :       if (bm->enabled)
     174           0 :         return 0;
     175           0 :       clib_error_t *error = bufmon_register_callbacks (vm);
     176           0 :       if (error)
     177           0 :         return error;
     178           0 :       bm->enabled = 1;
     179             :     }
     180             :   else
     181             :     {
     182           0 :       if (!bm->enabled)
     183           0 :         return 0;
     184           0 :       bufmon_unregister_callbacks (vm);
     185           0 :       bm->enabled = 0;
     186             :     }
     187             : 
     188           0 :   return 0;
     189             : }
     190             : 
     191             : static clib_error_t *
     192           0 : set_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
     193             :                    vlib_cli_command_t *cmd)
     194             : {
     195           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     196           0 :   int on = 1;
     197             : 
     198           0 :   if (unformat_user (input, unformat_line_input, line_input))
     199             :     {
     200           0 :       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     201             :         {
     202           0 :           if (unformat (line_input, "on"))
     203           0 :             on = 1;
     204           0 :           else if (unformat (line_input, "off"))
     205           0 :             on = 0;
     206             :           else
     207             :             {
     208           0 :               unformat_free (line_input);
     209           0 :               return clib_error_return (0, "unknown input `%U'",
     210             :                                         format_unformat_error, line_input);
     211             :             }
     212             :         }
     213           0 :       unformat_free (line_input);
     214             :     }
     215             : 
     216           0 :   return bufmon_enable_disable (vm, on);
     217             : }
     218             : 
     219      253847 : VLIB_CLI_COMMAND (set_buffer_traces_command, static) = {
     220             :   .path = "set buffer traces",
     221             :   .short_help = "set buffer traces [on|off]",
     222             :   .function = set_buffer_traces,
     223             : };
     224             : 
     225             : static clib_error_t *
     226           0 : show_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
     227             :                     vlib_cli_command_t *cmd)
     228             : {
     229           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     230           0 :   const bufmon_main_t *bm = &bufmon_main;
     231             :   const bufmon_per_thread_data_t *ptd;
     232             :   const bufmon_per_node_data_t *pnd;
     233           0 :   int verbose = 0;
     234           0 :   int status = 0;
     235             : 
     236           0 :   if (unformat_user (input, unformat_line_input, line_input))
     237             :     {
     238           0 :       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     239             :         {
     240           0 :           if (unformat (line_input, "verbose"))
     241           0 :             verbose = 1;
     242           0 :           else if (unformat (line_input, "status"))
     243           0 :             status = 1;
     244             :           else
     245             :             {
     246           0 :               unformat_free (line_input);
     247           0 :               return clib_error_return (0, "unknown input `%U'",
     248             :                                         format_unformat_error, line_input);
     249             :             }
     250             :         }
     251           0 :       unformat_free (line_input);
     252             :     }
     253             : 
     254           0 :   if (status)
     255             :     {
     256           0 :       vlib_cli_output (vm, "buffers tracing is %s",
     257           0 :                        bm->enabled ? "on" : "off");
     258           0 :       return 0;
     259             :     }
     260             : 
     261           0 :   vlib_cli_output (vm, "%U\n\n", format_vlib_buffer_pool_all, vm);
     262           0 :   vlib_cli_output (vm, "%30s%20s%20s%20s%20s%20s", "Node", "Allocated",
     263             :                    "Freed", "In", "Out", "Buffered");
     264           0 :   vec_foreach (ptd, bm->ptd)
     265             :     {
     266           0 :       vec_foreach (pnd, ptd->pnd)
     267             :         {
     268           0 :           const u64 in = pnd->alloc + pnd->in;
     269           0 :           const u64 out = pnd->free + pnd->out;
     270           0 :           const i64 buffered = in - out;
     271           0 :           if (0 == in && 0 == out)
     272           0 :             continue; /* skip nodes w/o activity */
     273           0 :           if (0 == buffered && !verbose)
     274           0 :             continue; /* if not verbose, skip nodes w/o buffered buffers */
     275           0 :           vlib_cli_output (vm, "%30U%20lu%20lu%20lu%20lu%20ld",
     276           0 :                            format_vlib_node_name, vm, pnd - ptd->pnd,
     277             :                            pnd->alloc, pnd->free, pnd->in, pnd->out, buffered);
     278             :         }
     279             :     }
     280             : 
     281           0 :   return 0;
     282             : }
     283             : 
     284      253847 : VLIB_CLI_COMMAND (show_buffer_traces_command, static) = {
     285             :   .path = "show buffer traces",
     286             :   .short_help = "show buffer traces [status|verbose]",
     287             :   .function = show_buffer_traces,
     288             : };
     289             : 
     290             : static clib_error_t *
     291           0 : clear_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
     292             :                      vlib_cli_command_t *cmd)
     293             : {
     294           0 :   const bufmon_main_t *bm = &bufmon_main;
     295             :   const bufmon_per_thread_data_t *ptd;
     296             :   const bufmon_per_node_data_t *pnd;
     297             : 
     298           0 :   vec_foreach (ptd, bm->ptd)
     299           0 :     vec_foreach (pnd, ptd->pnd)
     300           0 :       vec_reset_length (pnd);
     301             : 
     302           0 :   return 0;
     303             : }
     304             : 
     305      253847 : VLIB_CLI_COMMAND (clear_buffers_trace_command, static) = {
     306             :   .path = "clear buffer traces",
     307             :   .short_help = "clear buffer traces",
     308             :   .function = clear_buffer_traces,
     309             : };
     310             : 
     311             : VLIB_PLUGIN_REGISTER () = {
     312             :   .version = VPP_BUILD_VER,
     313             :   .description = "Buffers monitoring plugin",
     314             : };

Generated by: LCOV version 1.14