diff options
-rw-r--r-- | src/plugins/perfmon/intel/core.c | 10 | ||||
-rw-r--r-- | src/plugins/perfmon/perfmon.c | 40 | ||||
-rw-r--r-- | src/plugins/perfmon/perfmon.h | 3 | ||||
-rw-r--r-- | src/vppinfra/cpu.h | 18 |
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 () { |