summaryrefslogtreecommitdiff
path: root/kern
diff options
context:
space:
mode:
authorRemy Noel <mocramis@gmail.com>2018-04-18 19:16:40 +0200
committerRemy Noel <mocramis@gmail.com>2018-04-21 00:04:20 +0200
commit1b86674fcbefb0c860c02ade0463db469f4df1bb (patch)
treef2b741d60c7ae8996ca736378b28dc213a33b033 /kern
parent75924457863e9dc90475b5cbd9bcabfff87cfc0d (diff)
perfmon: Test overflow in cpu test.
Adds perfmon_event_write as a test-only API.
Diffstat (limited to 'kern')
-rw-r--r--kern/perfmon.c38
-rw-r--r--kern/perfmon.h3
-rw-r--r--kern/perfmon_i.h38
3 files changed, 79 insertions, 0 deletions
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 <kern/panic.h>
#include <kern/percpu.h>
#include <kern/perfmon.h>
+#include <kern/perfmon_i.h>
#include <kern/spinlock.h>
#include <kern/thread.h>
#include <kern/xcall.h>
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Performance monitoring based on performance counters internal functions.
+ *
+ */
+#ifndef _KERN_PERFMON_I_H
+#define _KERN_PERFMON_I_H
+
+#include <kern/perfmon.h>
+
+#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 */
+