/*
* Copyright (c) 2014-2018 Remy Noel.
* Copyright (c) 2014 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 .
*
* Performance monitoring based on hardware performance counters.
*/
#ifndef KERN_PERFMON_H
#define KERN_PERFMON_H
#include
#include
#include
/*
* Performance event types.
*/
#define PERFMON_ET_GENERIC 0
#define PERFMON_ET_RAW 1
/*
* IDs of generic performance 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_MASK (PERFMON_EF_KERN | PERFMON_EF_USER)
/*
* Pmu operations.
*
* Set by calling perfmon_register_pmu_ops.
*/
struct perfmon_pmu_ops {
void (*info)(void);
int (*translate)(unsigned int *raw_event_idp, unsigned int event_id);
int (*alloc)(unsigned int *pmc_idp, unsigned int raw_event_id);
void (*free)(unsigned int pmc_id);
void (*start)(unsigned int pmc_id, unsigned int raw_event_id);
void (*stop)(unsigned int pmc_id);
uint64_t (*read)(unsigned int pmc_id);
void (*write)(unsigned int pmc_id, uint64_t value);
/* If set, of_max_ticks should be set to 0. */
void (*handle_of_intr)(void);
};
/*
* Pmu device description.
*/
struct perfmon_pmu_driver {
uint8_t pmc_width; /* width in bits of a pmc */
/*
* Maximum number of clock ticks between two overflow ckecks.
* Should be set to 0 if handle_of_intr is set.
*/
uint64_t of_max_ticks;
struct perfmon_pmu_ops ops;
};
/*
* Performance monitoring event.
*
* An event describes a single, well-defined state and records its
* occurrences over a period of time. It must be added to exactly
* one group before being used.
*/
struct perfmon_event;
/*
* Group of performance monitoring events.
*
* A group must be attached to either a thread or a processor, and abstracts
* all operations on hardware counters.
*
* Until a group is actually attached, it is assumed there is only one
* reference on it, owned by the caller.
*
* For a thread-attached group, it is the user's responsability to make sure
* that perfmon_stop is always called before the monitored thread is deleted.
*/
struct perfmon_group;
/*
* Create an event.
*/
int perfmon_event_create(struct perfmon_event **eventp, unsigned int type,
unsigned int id, int flags);
/*
* Destroy an event.
*
* Once an event is added to a group, it can only be destroyed by destroying
* the group.
*/
void perfmon_event_destroy(struct perfmon_event *event);
/*
* Obtain the number of occurrences of an event.
*
* Events are updated at specific points in time, which means the value
* returned by this function can be outdated.
*
* See perfmon_group_update() and perfmon_group_stop().
*/
uint64_t perfmon_event_read(const struct perfmon_event *event);
/*
* Reset the number of occurrences of an event to 0.
*
* The group containing the given event should be stopped when calling
* this function.
*/
void perfmon_event_reset(struct perfmon_event *event);
/*
* Create an event group.
*
* Events must be added to the group, which must then be attached to a
* processor or a thread.
*/
int perfmon_group_create(struct perfmon_group **groupp);
/*
* Destroy a group and all its events.
*
* A group can only be destroyed once stopped and detached.
*
* Will return EINVAL if the group is not detached.
*/
int perfmon_group_destroy(struct perfmon_group *group);
/*
* Add an event into a group.
*
* Events can only be added when a group isn't attached.
*/
void perfmon_group_add(struct perfmon_group *group,
struct perfmon_event *event);
/*
* Attach a group to, respectively, a thread or a processor, reserving
* associated logical counter.
*
* A group can only be attached to one thread or processor at a time.
*/
int perfmon_group_attach(struct perfmon_group *group, struct thread *thread);
int perfmon_group_attach_cpu(struct perfmon_group *group, unsigned int cpu);
/*
* Detach a group from a thread or a processor.
*
* It frees associated logical counters..
*
* returns EINVAL if the group is still enabled (not stopped).
*/
int perfmon_group_detach(struct perfmon_group *group);
/*
* Start performance monitoring.
*
* A group must be attached before being started.
*/
int perfmon_group_start(struct perfmon_group *group);
/*
* Update all events in the given group.
*/
void perfmon_group_update(struct perfmon_group *group);
/*
* Stop performance monitoring.
*
* A group can't be detached before it's stopped. Events are implicitely
* updated when calling this function.
*/
int perfmon_group_stop(struct perfmon_group *group);
/*
* Initialize perfmon thread-specific data for the given thread.
*/
int perfmon_thread_init(struct thread *thread);
/*
* Destroy perfmon thread-specific data for the given thread.
*/
void perfmon_thread_destroy(struct thread *thread);
/*
* Load/unload the events associated to a thread on the current processor.
*
* These functions should only be used by the scheduler during context switch.
* Interrupts and preemption must be disabled when calling this function.
*/
void perfmon_thread_load(struct thread *thread);
void perfmon_thread_unload(struct thread *thread);
/*
* This init operation provides :
* - perfmon_thread_init()
*/
INIT_OP_DECLARE(perfmon_bootstrap);
/*
* This init operation provides :
* - module fully initialized
*/
INIT_OP_DECLARE(perfmon_setup);
/*
* Handle overflow interrupt.
*/
void perfmon_of_intr(void);
/*
* Register an architecture-specific driver.
*/
int perfmon_pmu_register(struct perfmon_pmu_driver *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.
*/
void perfmon_cpu_pmc_inc_of(unsigned int pmc_id);
#endif /* KERN_PERFMON_H */