perfmon: prune bundles by available pmu counters 94/34594/10
authorRay Kinsella <mdr@ashroe.eu>
Fri, 26 Nov 2021 14:57:35 +0000 (14:57 +0000)
committerDamjan Marion <dmarion@me.com>
Thu, 27 Jan 2022 20:01:45 +0000 (20:01 +0000)
Prune perfmon bundles that exceed the number of available pmu counters.

Type: improvement

Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
Change-Id: I70fec26bb8ca915f4b980963e06c2e43dfde5a23

src/plugins/perfmon/intel/core.c
src/plugins/perfmon/perfmon.c
src/plugins/perfmon/perfmon.h
src/vppinfra/cpu.h

index c59fce8..d985d04 100644 (file)
@@ -77,11 +77,21 @@ intel_core_init (vlib_main_t *vm, perfmon_source_t *src)
   return 0;
 }
 
+u8
+intel_core_is_fixed (u32 event)
+{
+  u64 config = events[event].config;
+  u8 eventcode = (config & 0xFF);
+
+  return !eventcode ? 1 : 0;
+}
+
 PERFMON_REGISTER_SOURCE (intel_core) = {
   .name = "intel-core",
   .description = "intel arch core events",
   .events = events,
   .n_events = ARRAY_LEN (events),
   .init_fn = intel_core_init,
+  .is_fixed = intel_core_is_fixed,
   .format_config = format_intel_core_config,
 };
index 411a07d..1569036 100644 (file)
@@ -324,11 +324,37 @@ perfmon_stop (vlib_main_t *vm)
   return 0;
 }
 
+static_always_inline u8
+is_enough_counters (perfmon_bundle_t *b)
+{
+  struct
+  {
+    u8 general;
+    u8 fixed;
+  } bl = { 0, 0 }, cpu = { 0, 0 };
+
+  /* how many does this uarch support */
+  if (!clib_get_pmu_counter_count (&cpu.fixed, &cpu.general))
+    return 0;
+
+  /* how many does the bundle require */
+  for (u16 i = 0; i < b->n_events; i++)
+    if (b->src->is_fixed && b->src->is_fixed (b->events[i]))
+      bl.fixed++;
+    else
+      bl.general++;
+
+  return cpu.general >= bl.general && cpu.fixed >= bl.fixed;
+}
+
 static_always_inline u8
 is_bundle_supported (perfmon_bundle_t *b)
 {
   perfmon_cpu_supports_t *supports = b->cpu_supports;
 
+  if (!is_enough_counters (b))
+    return 0;
+
   if (!b->cpu_supports)
     return 1;
 
@@ -372,13 +398,6 @@ perfmon_init (vlib_main_t *vm)
       clib_error_t *err;
       uword *p;
 
-      if (!is_bundle_supported (b))
-       {
-         log_debug ("skipping bundle '%s' - not supported", b->name);
-         b = b->next;
-         continue;
-       }
-
       if (hash_get_mem (pm->bundle_by_name, b->name) != 0)
        clib_panic ("duplicate bundle name '%s'", b->name);
 
@@ -391,6 +410,13 @@ perfmon_init (vlib_main_t *vm)
        }
 
       b->src = (perfmon_source_t *) p[0];
+      if (!is_bundle_supported (b))
+       {
+         log_debug ("skipping bundle '%s' - not supported", b->name);
+         b = b->next;
+         continue;
+       }
+
       if (b->init_fn && ((err = (b->init_fn) (vm, b))))
        {
          log_warn ("skipping bundle '%s' - %U", b->name, format_clib_error,
index 58d971f..c7f4314 100644 (file)
@@ -82,6 +82,8 @@ extern vlib_node_function_t *perfmon_dispatch_wrappers[PERF_MAX_EVENTS + 1];
 
 typedef clib_error_t *(perfmon_source_init_fn_t) (vlib_main_t *vm,
                                                  struct perfmon_source *);
+typedef u8 (perfmon_source_is_fixed) (u32 event);
+
 typedef struct perfmon_source
 {
   char *name;
@@ -91,6 +93,7 @@ typedef struct perfmon_source
   u32 n_events;
   perfmon_instance_type_t *instances_by_type;
   format_function_t *format_config;
+  perfmon_source_is_fixed *is_fixed;
   perfmon_source_init_fn_t *init_fn;
 } perfmon_source_t;
 
index 50d8b61..329e5cc 100644 (file)
@@ -266,6 +266,24 @@ clib_cpu_march_priority_hsw ()
   return -1;
 }
 
+#define X86_CPU_ARCH_PERF_FUNC 0xA
+
+static inline int
+clib_get_pmu_counter_count (u8 *fixed, u8 *general)
+{
+#if defined(__x86_64__)
+  u32 __clib_unused eax = 0, ebx = 0, ecx = 0, edx = 0;
+  clib_get_cpuid (X86_CPU_ARCH_PERF_FUNC, &eax, &ebx, &ecx, &edx);
+
+  *general = (eax & 0xFF00) >> 8;
+  *fixed = (edx & 0xF);
+
+  return 1;
+#else
+  return 0;
+#endif
+}
+
 static inline u32
 clib_cpu_implementer ()
 {