From 75924457863e9dc90475b5cbd9bcabfff87cfc0d Mon Sep 17 00:00:00 2001 From: Remy Noel Date: Wed, 18 Apr 2018 19:21:42 +0200 Subject: perfmon: Add overflow handling. Only architectural version 1 handled so far. --- kern/perfmon.c | 36 +++++++++++++++++++++++++----------- kern/perfmon.h | 16 ++++++++++++++-- 2 files changed, 39 insertions(+), 13 deletions(-) (limited to 'kern') diff --git a/kern/perfmon.c b/kern/perfmon.c index ed848e3..e91f3cd 100644 --- a/kern/perfmon.c +++ b/kern/perfmon.c @@ -44,6 +44,7 @@ #include #include #include +#include /* * Performance monitoring event. @@ -424,6 +425,16 @@ perfmon_cpu_pmc_get_prev(unsigned int pmc_id) return cpu_pmc->prev_value; } +void +perfmon_cpu_pmc_set_prev(unsigned int pmc_id, uint64_t prev) +{ + struct perfmon_cpu_pmc *cpu_pmc; + + cpu_pmc = perfmon_cpu_pmu_get_pmc_from_id(pmc_id); + + cpu_pmc->prev_value = prev; +} + void perfmon_cpu_pmc_inc_of(unsigned int pmc_id) { @@ -462,6 +473,12 @@ perfmon_cpu_pmu_unload(struct perfmon_cpu_pmu *cpu_pmu, unsigned int pmc_index) } } +void +perfmon_handle_of_intr(struct trap_frame *frame) +{ + pmu_driver.handle_of_intr(frame); +} + int perfmon_pmu_register(struct perfmon_pmu_ops *driver) { @@ -527,6 +544,11 @@ perfmon_setup(void) return ENODEV; } pmu_driver.info(); + if (pmu_driver.handle_of_intr) { + trap_register(TRAP_LAPIC_PMC_OF, lapic_pmc_of_intr); + } else { + log_warning("registered pmu does not handle overflow\n"); + } return 0; } @@ -540,7 +562,8 @@ INIT_OP_DEFINE(perfmon_setup, INIT_OP_DEP(pmu_intel_setup, false), INIT_OP_DEP(pmu_amd_setup, false), INIT_OP_DEP(spinlock_setup, true), - INIT_OP_DEP(thread_setup, true)); + INIT_OP_DEP(thread_setup, true), + INIT_OP_DEP(trap_setup, true)); static void perfmon_check_event_args(unsigned int type, unsigned int id, int flags) @@ -618,14 +641,9 @@ perfmon_event_sync(struct perfmon_cpu_pmu *cpu_pmu, - event->prev + count; event->overflow_id = cpu_pmc->overflow_id; } else { - event->count += (count - event->prev); + event->count += count - event->prev; } event->prev = count; - - /* Update per cpu prev value. we should use a callback "on_sync" or so - * instead as it is only necessary for certain archtectural overflow - * management.*/ - cpu_pmc->prev_value = count; } static inline int @@ -896,10 +914,6 @@ perfmon_group_load(struct perfmon_group *group) perfmon_cpu_pmu_load(cpu_pmu, event->pmc_index); event->prev = pmu_driver.read(perfmon_pmu.pmcs[event->pmc_index].id); event->overflow_id = cpu_pmu->pmcs[event->pmc_index].overflow_id; - /* Update per cpu prev value. we should use a callback "on_sync" or so - * instead as it is only necessary for certain archtectural overflow - * management.*/ - cpu_pmu->pmcs[event->pmc_index].prev_value = event->prev; } group->cpu = cpu_id(); diff --git a/kern/perfmon.h b/kern/perfmon.h index 0e5cd19..60e40e0 100644 --- a/kern/perfmon.h +++ b/kern/perfmon.h @@ -65,6 +65,7 @@ struct perfmon_pmu_ops { void (*stop)(unsigned int pmc_id); uint64_t (*read)(unsigned int pmc_id); uint8_t (*get_pmc_width)(void); + void (*handle_of_intr)(struct trap_frame *frame); }; /* @@ -216,17 +217,28 @@ INIT_OP_DECLARE(perfmon_bootstrap); */ INIT_OP_DECLARE(perfmon_setup); +/* + * Handle overflow interrupt. + */ +void perfmon_handle_of_intr(struct trap_frame *frame); + +int perfmon_on_overflow(struct perfmon_pmu_ops *driver); + /* * Register an architecture-specific driver. */ -int -perfmon_pmu_register(struct perfmon_pmu_ops *driver); +int perfmon_pmu_register(struct perfmon_pmu_ops *driver); /* * Get the last value of given pmc. */ uint64_t perfmon_cpu_pmc_get_prev(unsigned int pmc_id); +/* + * Set the last value of given pmc. + */ +void perfmon_cpu_pmc_set_prev(unsigned int pmc_id, uint64_t prev); + /* * Increment overflow counter for given pmc. */ -- cgit v1.2.3