summaryrefslogtreecommitdiff
path: root/kern/perfmon.h
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2018-06-25 21:48:34 +0200
committerRichard Braun <rbraun@sceen.net>2018-06-25 21:52:26 +0200
commitbb91d0a376a71ef2c0d01a741400c367ac1a2ccf (patch)
treef7dd37b46d754bd9e3f7acb13957e2ace6a7b43e /kern/perfmon.h
parent64d74fe8d76c230e61b17482bb098d7f9729141d (diff)
kern/perfmon: new module
Diffstat (limited to 'kern/perfmon.h')
-rw-r--r--kern/perfmon.h221
1 files changed, 221 insertions, 0 deletions
diff --git a/kern/perfmon.h b/kern/perfmon.h
new file mode 100644
index 00000000..0c17752c
--- /dev/null
+++ b/kern/perfmon.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2014-2018 Remy Noel.
+ * Copyright (c) 2014-2018 Richard Braun.
+ *
+ * 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 hardware performance counters.
+ *
+ * The hardware layer is represented by a performance monitoring unit (PMU),
+ * which provides performance monitoring counters (PMCs).
+ */
+
+#ifndef KERN_PERFMON_H
+#define KERN_PERFMON_H
+
+#include <stdint.h>
+
+#include <kern/init.h>
+#include <kern/perfmon_types.h>
+#include <kern/thread.h>
+
+/*
+ * IDs of generic performance monitoring events.
+ */
+#define PERFMON_EV_CYCLE 0
+#define PERFMON_EV_REF_CYCLE 1
+#define PERFMON_EV_INSTRUCTION 2
+#define PERFMON_EV_CACHE_REF 3
+#define PERFMON_EV_CACHE_MISS 4
+#define PERFMON_EV_BRANCH 5
+#define PERFMON_EV_BRANCH_MISS 6
+#define PERFMON_NR_GENERIC_EVENTS 7
+
+/*
+ * Event flags.
+ */
+#define PERFMON_EF_KERN 0x1 /* Monitor events in kernel mode */
+#define PERFMON_EF_USER 0x2 /* Monitor events in user mode */
+#define PERFMON_EF_RAW 0x4 /* Raw event ID, generic if unset */
+
+/*
+ * Performance monitoring operations.
+ *
+ * This is a public structure.
+ *
+ * All operations are either global but serialized by the caller, or
+ * processor-local and called with interrupts and preemption disabled.
+ *
+ * If the hardware doesn't efficiently support overflow interrupts, the
+ * handler must be set to NULL, making the perfmon module perdiocally
+ * check the raw value of the hardware counters.
+ */
+struct perfmon_dev_ops {
+ /*
+ * Convert a generic event ID into a raw event ID.
+ *
+ * Global operation.
+ */
+ int (*translate)(unsigned int *raw_event_idp, unsigned int event_id);
+
+ /*
+ * Allocate a performance monitoring counter globally for the given
+ * raw event ID, and return the counter ID through the given pointer.
+ * The range of IDs must start from 0 and increase contiguously.
+ *
+ * The PMC index is to be used by the driver when reporting overflows,
+ * if a custom overflow interrupt handler.
+ *
+ * Global operation.
+ */
+ int (*alloc)(unsigned int *pmc_idp, unsigned int pmc_index,
+ unsigned int raw_event_id);
+
+ /*
+ * Free an allocated performance monitoring counter.
+ *
+ * Global operation.
+ */
+ void (*free)(unsigned int pmc_id);
+
+ /*
+ * Start a performance monitoring counter for the given raw event ID.
+ *
+ * Processor-local operation.
+ */
+ void (*start)(unsigned int pmc_id, unsigned int raw_event_id);
+
+ /*
+ * Stop a performance monitoring counter.
+ *
+ * Processor-local operation.
+ */
+ void (*stop)(unsigned int pmc_id);
+
+ /*
+ * Read the value of a performance monitoring counter.
+ *
+ * Processor-local operation.
+ */
+ uint64_t (*read)(unsigned int pmc_id);
+
+ /*
+ * Custom overflow interrupt handler.
+ *
+ * Processor-local operation.
+ */
+ void (*handle_overflow_intr)(void);
+};
+
+/*
+ * Performance monitoring device.
+ *
+ * This is a public structure.
+ *
+ * The PMC width is expressed in bits.
+ *
+ * If the driver doesn't provide an overflow interrupt handler, it may set
+ * the poll interval, in ticks, to a duration that safely allows the detection
+ * of a single overflow. A value of 0 lets the perfmon module compute a poll
+ * interval itself.
+ */
+struct perfmon_dev {
+ const struct perfmon_dev_ops *ops;
+ unsigned int pmc_width;
+ uint64_t poll_interval;
+};
+
+/*
+ * Performance monitoring thread data.
+ */
+struct perfmon_td;
+
+/*
+ * Performance monitoring event.
+ *
+ * An event describes a single, well-defined hardware condition and tracks
+ * its occurrences over a period of time.
+ */
+struct perfmon_event;
+
+/*
+ * Initialize thread-specific data.
+ */
+void perfmon_td_init(struct perfmon_td *td);
+
+/*
+ * Load/unload events attached to a thread on the current processor.
+ *
+ * These functions should only be used by the scheduler on a context switch.
+ * Interrupts and preemption must be disabled when calling these functions.
+ */
+void perfmon_td_load(struct perfmon_td *td);
+void perfmon_td_unload(struct perfmon_td *td);
+
+/*
+ * Initialize an event.
+ */
+int perfmon_event_init(struct perfmon_event *event, unsigned int id,
+ unsigned int flags);
+
+/*
+ * Attach/detach an event to/from a thread or a processor.
+ *
+ * Attaching an event allocates hardware resources and enables monitoring.
+ * The number of occurrences for the given event is reset.
+ *
+ * An event can only be attached to one thread or processor at a time.
+ */
+int perfmon_event_attach(struct perfmon_event *event, struct thread *thread);
+int perfmon_event_attach_cpu(struct perfmon_event *event, unsigned int cpu);
+int perfmon_event_detach(struct perfmon_event *event);
+
+/*
+ * Obtain the number of occurrences of an event.
+ */
+uint64_t perfmon_event_read(struct perfmon_event *event);
+
+/*
+ * Register a PMU device.
+ *
+ * Currently, there can only be a single system-wide PMU device, which
+ * assumes the driver is the same for all processors.
+ */
+void perfmon_register(struct perfmon_dev *dev);
+
+/*
+ * Handle an overflow interrupt.
+ *
+ * This function must be called in interrupt context.
+ */
+void perfmon_overflow_intr(void);
+
+/*
+ * Report a PMC overflow.
+ *
+ * This function is intended to be used by PMU drivers using a custom
+ * overflow interrupt handler.
+ *
+ * This function must be called in interrupt context.
+ */
+void perfmon_report_overflow(unsigned int pmc_index);
+
+/*
+ * This init operation provides :
+ * - PMU device registration
+ */
+INIT_OP_DECLARE(perfmon_bootstrap);
+
+#endif /* KERN_PERFMON_H */