diff options
Diffstat (limited to 'kern/perfmon.c')
-rw-r--r-- | kern/perfmon.c | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/kern/perfmon.c b/kern/perfmon.c index 5627726..d5d6589 100644 --- a/kern/perfmon.c +++ b/kern/perfmon.c @@ -54,6 +54,7 @@ struct perfmon_event { uint64_t count; uint64_t prev; + uint64_t overflow_id; struct list node; int flags; unsigned int type; @@ -167,6 +168,8 @@ struct perfmon_pmu { */ struct perfmon_cpu_pmc { unsigned int nr_refs; + uint64_t prev_value; + uint64_t overflow_id; }; /* @@ -379,14 +382,15 @@ perfmon_cpu_pmu_init(struct perfmon_cpu_pmu *cpu_pmu) unsigned int i; for (i = 0; i < ARRAY_SIZE(cpu_pmu->pmcs); i++) { - cpu_pmu->pmcs[i].nr_refs = 0; - } -} + struct perfmon_cpu_pmu *cpu_pmc; -static inline struct perfmon_cpu_pmc * -perfmon_cpu_pmu_get_pmc(struct perfmon_cpu_pmu *cpu_pmu, unsigned int index) -{ - return &cpu_pmu->pmcs[index]; + cpu_pmu = &cpu_pmu->pmcs[i]; + + pmc.nr_refs = 0; + pmc->prev_value = pmu_driver.read(perfmon_pmu.pmcs[i].id); + pmc->overflow_id = 0; + + } } static void @@ -394,7 +398,7 @@ perfmon_cpu_pmu_load(struct perfmon_cpu_pmu *cpu_pmu, unsigned int pmc_index) { struct perfmon_cpu_pmc *cpu_pmc; - cpu_pmc = perfmon_cpu_pmu_get_pmc(cpu_pmu, pmc_index); + cpu_pmc = cpu_pmu->pmcs[pmc_index]; if (cpu_pmc->nr_refs == 0) { pmu_driver.start(perfmon_pmu.pmcs[pmc_index].id, @@ -422,7 +426,8 @@ int perfmon_pmu_register(struct perfmon_pmu_ops *driver) { assert(driver->info && driver->translate && driver->alloc - && driver->free && driver->start && driver->stop); + && driver->free && driver->start && driver->stop + && driver->get_pmc_width); if (pmu_driver.info) { /* Already initialized */ @@ -551,16 +556,36 @@ perfmon_event_reset(struct perfmon_event *event) } static void -perfmon_event_sync(struct perfmon_event *event) +perfmon_event_sync(struct perfmon_cpu_pmu *cpu_pmu, + struct perfmon_event *event) { struct perfmon_pmc *pmc; + struct perfmon_cpu_pmc *cpu_pmc; uint64_t count; pmc = perfmon_pmc_from_index(event->pmc_index); + cpu_pmc = cpu_pmu->pmcs[event->pmc_index]; count = pmu_driver.read(pmc->id); - /* TODO: overflow managment. */ - event->count += (count - event->prev); + + if (unlikely(event->overflow_id != cpu_pmc->overflow_id)) { + int diff; + + assert(cpu_pmc->overflow_id > event->overflow_id); + + diff = cpu_pmc->overflow_id > event->overflow_id; + /* diff is very likely 1. */ + event->count += (1UL << pmu_driver.get_pmc_width()) * diff + - event->prev + count; + event->overflow_id = cpu_pmc->overflow_id; + } else { + 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 @@ -830,6 +855,11 @@ perfmon_group_load(struct perfmon_group *group) list_for_each_entry(&group->events, event, node) { 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(); @@ -865,7 +895,7 @@ perfmon_group_unload(struct perfmon_group *group) list_for_each_entry(&group->events, event, node) { perfmon_cpu_pmu_unload(cpu_pmu, event->pmc_index); - perfmon_event_sync(event); + perfmon_event_sync(cpu_pmu, event); } group->flags &= ~PERFMON_GF_LOADED; @@ -993,7 +1023,7 @@ perfmon_group_sync_local(struct perfmon_group *group) * limited amount of *different* events. */ list_for_each_entry(&group->events, event, node) { - perfmon_event_sync(event); + perfmon_event_sync(cpu_pmu, event); } } |