From 1b86674fcbefb0c860c02ade0463db469f4df1bb Mon Sep 17 00:00:00 2001 From: Remy Noel Date: Wed, 18 Apr 2018 19:16:40 +0200 Subject: perfmon: Test overflow in cpu test. Adds perfmon_event_write as a test-only API. --- kern/perfmon.c | 38 ++++++++++++++++++++++++++++++++++++++ kern/perfmon.h | 3 +++ kern/perfmon_i.h | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 kern/perfmon_i.h (limited to 'kern') diff --git a/kern/perfmon.c b/kern/perfmon.c index e91f3cd..4da95fb 100644 --- a/kern/perfmon.c +++ b/kern/perfmon.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,10 @@ struct perfmon_event { unsigned int type; unsigned int id; unsigned int pmc_index; +#ifdef CONFIG_PERFMON_TEST + uint64_t value; + bool set_value; +#endif }; #define PERFMON_INVALID_CPU ((unsigned int)-1) @@ -612,6 +617,22 @@ perfmon_event_read(const struct perfmon_event *event) return event->count; } +#ifdef CONFIG_PERFMON_TEST + +int +perfmon_event_write(struct perfmon_event *event, uint64_t value) +{ + if (!pmu_driver.write) { + return ENODEV; + } + event->value = value; + event->set_value = true; + + return 0; +} + +#endif /* CONFIG_PERFMON_TEST */ + void perfmon_event_reset(struct perfmon_event *event) { @@ -903,6 +924,9 @@ perfmon_group_load(struct perfmon_group *group) { struct perfmon_cpu_pmu *cpu_pmu; struct perfmon_event *event; +#ifdef CONFIG_PERFMON_TEST + struct perfmon_pmc *pmc; +#endif assert(!thread_preempt_enabled()); assert(perfmon_group_enabled(group)); @@ -910,6 +934,20 @@ perfmon_group_load(struct perfmon_group *group) cpu_pmu = cpu_local_ptr(perfmon_cpu_pmu); +#ifdef CONFIG_PERFMON_TEST + /* XXX: could be done in the loading loop, but performance does not + * matters in the functional tests using this feature. + */ + list_for_each_entry(&group->events, event, node) { + if (!event->set_value) { + continue; + } + pmc = perfmon_pmc_from_index(event->pmc_index); + pmu_driver.write(pmc->id, event->value); + event->set_value = false; + } +#endif + 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); diff --git a/kern/perfmon.h b/kern/perfmon.h index 60e40e0..3b9a002 100644 --- a/kern/perfmon.h +++ b/kern/perfmon.h @@ -66,6 +66,9 @@ struct perfmon_pmu_ops { uint64_t (*read)(unsigned int pmc_id); uint8_t (*get_pmc_width)(void); void (*handle_of_intr)(struct trap_frame *frame); +#ifdef CONFIG_PERFMON_TEST + void (*write)(unsigned int pmc_id, uint64_t value); +#endif /* CONFIG_PERFMON_TEST */ }; /* diff --git a/kern/perfmon_i.h b/kern/perfmon_i.h new file mode 100644 index 0000000..5cb4d45 --- /dev/null +++ b/kern/perfmon_i.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Remy Noel. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * Performance monitoring based on performance counters internal functions. + * + */ +#ifndef _KERN_PERFMON_I_H +#define _KERN_PERFMON_I_H + +#include + +#ifdef CONFIG_PERFMON_TEST + +/* + * Set an running event hardware counter value for overflow tests purposes. + * + * Beware, this will affect all events associated to the same hardware counter. + */ +int perfmon_event_write(struct perfmon_event *event, uint64_t value); + +#endif /* CONFIG_PERFMON_TEST */ + +#endif /* _KERN_PERFMON_H */ + -- cgit v1.2.3