policer: don't compute CPU clock frequency for each API call 17/43217/10
authorArthur de Kerhor <[email protected]>
Tue, 17 Jun 2025 14:30:51 +0000 (16:30 +0200)
committerBenoit Ganne <[email protected]>
Mon, 30 Jun 2025 06:47:49 +0000 (06:47 +0000)
In some virtualized environments, where we can't get TSC from
clib_get_cpuid, os_cpu_clock_frequency can take more than 1ms
to return. As the TSC value is invariant over time, it can be
cached in policer_init instead of being recalculated everytime
a policer is created/updated.

Type: improvement
Change-Id: Icfd00feac76f35d562546a17e4830efb91dba219
Signed-off-by: Arthur de Kerhor <[email protected]>
src/vnet/policer/policer.c
src/vnet/policer/policer.h
src/vnet/policer/xlate.c

index 00180d9..a24edb3 100644 (file)
@@ -1037,6 +1037,19 @@ VLIB_CLI_COMMAND (show_policer_pools_command, static) = {
     .function = show_policer_pools_command_fn,
 };
 
+/*
+ * Return the number of hardware TSC timer ticks per second for the dataplane.
+ * This is approximately, but not exactly, the clock speed.
+ */
+static u64
+get_tsc_hz (void)
+{
+  f64 cpu_freq;
+
+  cpu_freq = os_cpu_clock_frequency ();
+  return (u64) cpu_freq;
+}
+
 clib_error_t *
 policer_init (vlib_main_t * vm)
 {
@@ -1052,6 +1065,7 @@ policer_init (vlib_main_t * vm)
 
   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
   pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
+  pm->tsc_hz = get_tsc_hz ();
 
   vnet_classify_register_unformat_policer_next_index_fn
     (unformat_policer_classify_next_index);
index 7ce7fc7..9eef408 100644 (file)
@@ -50,6 +50,9 @@ typedef struct
   /* frame queue for thread handoff */
   u32 fq_index[VLIB_N_RX_TX];
 
+  /* cached TSC value. No need to re-compute for each new policer */
+  u64 tsc_hz;
+
   u16 msg_id_base;
 } vnet_policer_main_t;
 
index bffd208..26b0f59 100644 (file)
@@ -843,19 +843,6 @@ pol_compute_hw_params (qos_pol_cfg_params_st *cfg, qos_pol_hw_params_st *hw)
   return 0;
 }
 
-/*
- * Return the number of hardware TSC timer ticks per second for the dataplane.
- * This is approximately, but not exactly, the clock speed.
- */
-static u64
-get_tsc_hz (void)
-{
-  f64 cpu_freq;
-
-  cpu_freq = os_cpu_clock_frequency ();
-  return (u64) cpu_freq;
-}
-
 /*
  * Convert rates into bytes_per_period and scale.
  * Return 0 if ok or 1 if error.
@@ -948,8 +935,8 @@ compute_policer_params (u64 hz,           /* CPU speed in clocks per second */
 int
 x86_pol_compute_hw_params (qos_pol_cfg_params_st *cfg, policer_t *hw)
 {
+  vnet_policer_main_t *pm = &vnet_policer_main;
   const int BYTES_PER_KBIT = (1000 / 8);
-  u64 hz;
   u32 cap;
 
   if (!cfg || !hw)
@@ -958,7 +945,6 @@ x86_pol_compute_hw_params (qos_pol_cfg_params_st *cfg, policer_t *hw)
       return (-1);
     }
 
-  hz = get_tsc_hz ();
   hw->last_update_time = 0;
 
   /*
@@ -1001,10 +987,9 @@ x86_pol_compute_hw_params (qos_pol_cfg_params_st *cfg, policer_t *hw)
          return (-1);
        }
 
-      if (compute_policer_params (hz,
-                                 (u64) cfg->rb.kbps.cir_kbps *
-                                 BYTES_PER_KBIT, 0, &hw->current_limit,
-                                 &hw->extended_limit,
+      if (compute_policer_params (pm->tsc_hz,
+                                 (u64) cfg->rb.kbps.cir_kbps * BYTES_PER_KBIT,
+                                 0, &hw->current_limit, &hw->extended_limit,
                                  &hw->cir_tokens_per_period,
                                  &hw->pir_tokens_per_period, &hw->scale))
        {
@@ -1025,14 +1010,11 @@ x86_pol_compute_hw_params (qos_pol_cfg_params_st *cfg, policer_t *hw)
          return (-1);
        }
 
-      if (compute_policer_params (hz,
-                                 (u64) cfg->rb.kbps.cir_kbps *
-                                 BYTES_PER_KBIT,
-                                 (u64) cfg->rb.kbps.eir_kbps *
-                                 BYTES_PER_KBIT, &hw->current_limit,
-                                 &hw->extended_limit,
-                                 &hw->cir_tokens_per_period,
-                                 &hw->pir_tokens_per_period, &hw->scale))
+      if (compute_policer_params (
+           pm->tsc_hz, (u64) cfg->rb.kbps.cir_kbps * BYTES_PER_KBIT,
+           (u64) cfg->rb.kbps.eir_kbps * BYTES_PER_KBIT, &hw->current_limit,
+           &hw->extended_limit, &hw->cir_tokens_per_period,
+           &hw->pir_tokens_per_period, &hw->scale))
        {
          QOS_DEBUG_ERROR ("Policer parameter computation failed.");
          return (-1);