perfmon: fix init of bundles with pseudo events 36/35136/3
authorRay Kinsella <mdr@ashroe.eu>
Fri, 28 Jan 2022 05:01:52 +0000 (05:01 +0000)
committerDamjan Marion <dmarion@me.com>
Sun, 30 Jan 2022 15:08:18 +0000 (15:08 +0000)
Previously Linux pseudo events were being counted as multiple fixed
events, such that a bundle with pseudo events could exceed the number of
available fixed counters. Reworked to ignore pseudo events in the
accounting for the moment.

Type: fix
Fixes: 0024e53ad
Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
Change-Id: Ic938f8266fd04d7731afbd02e261c61ef22a8522

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

index d985d04..08a27b6 100644 (file)
@@ -77,13 +77,22 @@ intel_core_init (vlib_main_t *vm, perfmon_source_t *src)
   return 0;
 }
 
-u8
-intel_core_is_fixed (u32 event)
+perfmon_event_type_t
+intel_core_get_event_type (u32 event)
 {
   u64 config = events[event].config;
   u8 eventcode = (config & 0xFF);
-
-  return !eventcode ? 1 : 0;
+  u8 umask = ((config >> 8) & 0xFF);
+
+  if (!eventcode) /* is fixed or pseudo */
+    {
+      if (umask >= 0x80) /* is pseudo */
+       return PERFMON_EVENT_TYPE_PSEUDO;
+      else /* is fixed */
+       return PERFMON_EVENT_TYPE_FIXED;
+    }
+  else
+    return PERFMON_EVENT_TYPE_GENERAL;
 }
 
 PERFMON_REGISTER_SOURCE (intel_core) = {
@@ -92,6 +101,6 @@ PERFMON_REGISTER_SOURCE (intel_core) = {
   .events = events,
   .n_events = ARRAY_LEN (events),
   .init_fn = intel_core_init,
-  .is_fixed = intel_core_is_fixed,
+  .get_event_type = intel_core_get_event_type,
   .format_config = format_intel_core_config,
 };
index 594a987..b0c46b8 100644 (file)
@@ -327,24 +327,30 @@ perfmon_stop (vlib_main_t *vm)
 static_always_inline u8
 is_enough_counters (perfmon_bundle_t *b)
 {
-  struct
-  {
-    u8 general;
-    u8 fixed;
-  } bl = { 0, 0 }, cpu = { 0, 0 };
+  u8 bl[PERFMON_EVENT_TYPE_MAX];
+  u8 cpu[PERFMON_EVENT_TYPE_MAX];
+
+  clib_memset (&bl, 0, sizeof (bl));
+  clib_memset (&cpu, 0, sizeof (cpu));
 
   /* how many does this uarch support */
-  if (!clib_get_pmu_counter_count (&cpu.fixed, &cpu.general))
+  if (!clib_get_pmu_counter_count (&cpu[PERFMON_EVENT_TYPE_FIXED],
+                                  &cpu[PERFMON_EVENT_TYPE_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++;
+    {
+      /* if source allows us to identify events, otherwise assume general */
+      if (b->src->get_event_type)
+       bl[b->src->get_event_type (b->events[i])]++;
+      else
+       bl[PERFMON_EVENT_TYPE_GENERAL]++;
+    }
 
-  return cpu.general >= bl.general && cpu.fixed >= bl.fixed;
+  /* consciously ignoring pseudo events here */
+  return cpu[PERFMON_EVENT_TYPE_GENERAL] >= bl[PERFMON_EVENT_TYPE_GENERAL] &&
+        cpu[PERFMON_EVENT_TYPE_FIXED] >= bl[PERFMON_EVENT_TYPE_FIXED];
 }
 
 static_always_inline u8
index c7f4314..fa15ef6 100644 (file)
 
 #define PERF_MAX_EVENTS 12 /* 4 fixed and 8 programable on ICX */
 
+typedef enum
+{
+  PERFMON_EVENT_TYPE_GENERAL,
+  PERFMON_EVENT_TYPE_FIXED,
+  PERFMON_EVENT_TYPE_PSEUDO,
+  PERFMON_EVENT_TYPE_MAX,
+} perfmon_event_type_t;
+
 typedef enum
 {
   PERFMON_BUNDLE_TYPE_UNKNOWN,
@@ -82,7 +90,7 @@ 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 perfmon_event_type_t (perfmon_source_get_event_type) (u32 event);
 
 typedef struct perfmon_source
 {
@@ -93,7 +101,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_get_event_type *get_event_type;
   perfmon_source_init_fn_t *init_fn;
 } perfmon_source_t;