summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/perfmon/intel/core.c10
-rw-r--r--src/plugins/perfmon/perfmon.c40
-rw-r--r--src/plugins/perfmon/perfmon.h3
-rw-r--r--src/vppinfra/cpu.h18
4 files changed, 64 insertions, 7 deletions
diff --git a/src/plugins/perfmon/intel/core.c b/src/plugins/perfmon/intel/core.c
index c59fce81735..d985d049712 100644
--- a/src/plugins/perfmon/intel/core.c
+++ b/src/plugins/perfmon/intel/core.c
@@ -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,
};
diff --git a/src/plugins/perfmon/perfmon.c b/src/plugins/perfmon/perfmon.c
index 411a07dea30..15690361a7f 100644
--- a/src/plugins/perfmon/perfmon.c
+++ b/src/plugins/perfmon/perfmon.c
@@ -325,10 +325,36 @@ 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 };
+
+ /* 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,
diff --git a/src/plugins/perfmon/perfmon.h b/src/plugins/perfmon/perfmon.h
index 58d971f559a..c7f43145943 100644
--- a/src/plugins/perfmon/perfmon.h
+++ b/src/plugins/perfmon/perfmon.h
@@ -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;
diff --git a/src/vppinfra/cpu.h b/src/vppinfra/cpu.h
index 50d8b61cab3..329e5cc298d 100644
--- a/src/vppinfra/cpu.h
+++ b/src/vppinfra/cpu.h
@@ -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 ()
{