|
Packit |
577717 |
$Id: low-level-api.txt,v 1.1 2004/07/02 18:57:05 mikpe Exp $
|
|
Packit |
577717 |
|
|
Packit |
577717 |
PERFCTR LOW-LEVEL DRIVERS API
|
|
Packit |
577717 |
=============================
|
|
Packit |
577717 |
|
|
Packit |
577717 |
This document describes the common low-level API.
|
|
Packit |
577717 |
See low-level-$ARCH.txt for architecture-specific documentation.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
General Model
|
|
Packit |
577717 |
=============
|
|
Packit |
577717 |
The model is that of a processor with:
|
|
Packit |
577717 |
- A non-programmable clock-like counter, the "TSC".
|
|
Packit |
577717 |
The TSC frequency is assumed to be constant, but it is not
|
|
Packit |
577717 |
assumed to be identical to the core frequency.
|
|
Packit |
577717 |
The TSC may be absent.
|
|
Packit |
577717 |
- A set of programmable counters, the "perfctrs" or "pmcs".
|
|
Packit |
577717 |
Control data may be per-counter, global, or both.
|
|
Packit |
577717 |
The counters are not assumed to be interchangeable.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
A normal counter that simply counts events is referred to
|
|
Packit |
577717 |
as an "accumulation-mode" or "a-mode" counter. Its total
|
|
Packit |
577717 |
count is computed by adding the counts for the individual
|
|
Packit |
577717 |
periods during which the counter is active. Two per-counter
|
|
Packit |
577717 |
state variables are used for this: "sum", which is the
|
|
Packit |
577717 |
total count up to but not including the current period,
|
|
Packit |
577717 |
and "start", which records the value of the hardware counter
|
|
Packit |
577717 |
at the start of the current period. At the end of a period,
|
|
Packit |
577717 |
the hardware counter's value is read again, and the increment
|
|
Packit |
577717 |
relative the start value is added to the sum. This strategy
|
|
Packit |
577717 |
is used because it avoids a number of hardware problems.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
A counter that has been programmed to generate an interrupt
|
|
Packit |
577717 |
on overflow is referred to as an "interrupt-mode" or "i-mode"
|
|
Packit |
577717 |
counter. I-mode counters are initialised to specific values,
|
|
Packit |
577717 |
and after overflowing are reset to their (re)start values.
|
|
Packit |
577717 |
The total event count is available just as for a-mode counters.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
The set of counters may be empty, in which case only the
|
|
Packit |
577717 |
TSC (which must be present) can be sampled.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
Contents of <asm-$ARCH/perfctr.h>
|
|
Packit |
577717 |
=================================
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"struct perfctr_sum_ctrs"
|
|
Packit |
577717 |
-------------------------
|
|
Packit |
577717 |
struct perfctr_sum_ctrs {
|
|
Packit |
577717 |
unsigned long long tsc;
|
|
Packit |
577717 |
unsigned long long pmc[..]; /* one per counter */
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
Architecture-specific container for counter values.
|
|
Packit |
577717 |
Used in the kernel/user API, but not by the low-level drivers.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"struct perfctr_cpu_control"
|
|
Packit |
577717 |
----------------------------
|
|
Packit |
577717 |
This struct includes at least the following fields:
|
|
Packit |
577717 |
|
|
Packit |
577717 |
unsigned int tsc_on;
|
|
Packit |
577717 |
unsigned int nractrs; /* # of a-mode counters */
|
|
Packit |
577717 |
unsigned int nrictrs; /* # of i-mode counters */
|
|
Packit |
577717 |
unsigned int pmc_map[..]; /* one per counter: virt-to-phys mapping */
|
|
Packit |
577717 |
unsigned int evntsel[..]; /* one per counter: hw control data */
|
|
Packit |
577717 |
int ireset[..]; /* one per counter: i-mode (re)start value */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
Architecture-specific container for control data.
|
|
Packit |
577717 |
Used both in the kernel/user API and by the low-level drivers
|
|
Packit |
577717 |
(embedded in "struct perfctr_cpu_state").
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"tsc_on" is non-zero if the TSC should be sampled.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"nractrs" is the number of a-mode counters, corresponding to
|
|
Packit |
577717 |
elements 0..nractrs-1 in the per-counter arrays.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"nrictrs" is the number of i-mode counters, corresponding to
|
|
Packit |
577717 |
elements nractrs..nractrs+nrictrs-1 in the per-counter arrays.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"nractrs+nrictrs" is the total number of counters to program
|
|
Packit |
577717 |
and sample. A-mode and i-mode counters are separated in order
|
|
Packit |
577717 |
to allow quick enumeration of either set, which is needed in
|
|
Packit |
577717 |
some low-level driver operations.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"pmc_map[]" maps each counter to its corresponding hardware counter
|
|
Packit |
577717 |
identification. No two counters may map to the same hardware counter.
|
|
Packit |
577717 |
This mapping is present because the hardware may have asymmetric
|
|
Packit |
577717 |
counters or other addressing quirks, which means that a counter's index
|
|
Packit |
577717 |
may not suffice to address its hardware counter.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"evntsel[]" contains the per-counter control data. Architecture-specific
|
|
Packit |
577717 |
global control data, if any, is placed in architecture-specific fields.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"ireset[]" contains the (re)start values for the i-mode counters.
|
|
Packit |
577717 |
Only indices nractrs..nractrs+nrictrs-1 are used.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"struct perfctr_cpu_state"
|
|
Packit |
577717 |
--------------------------
|
|
Packit |
577717 |
This struct includes at least the following fields:
|
|
Packit |
577717 |
|
|
Packit |
577717 |
unsigned int cstatus;
|
|
Packit |
577717 |
unsigned int tsc_start;
|
|
Packit |
577717 |
unsigned long long tsc_sum;
|
|
Packit |
577717 |
struct {
|
|
Packit |
577717 |
unsigned int map;
|
|
Packit |
577717 |
unsigned int start;
|
|
Packit |
577717 |
unsigned long long sum;
|
|
Packit |
577717 |
} pmc[..]; /* one per counter; the size is not part of the user ABI */
|
|
Packit |
577717 |
#ifdef __KERNEL__
|
|
Packit |
577717 |
struct perfctr_cpu_control control;
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
This type records the state and control data for a collection
|
|
Packit |
577717 |
of counters. It is used by many low-level operations, and may
|
|
Packit |
577717 |
be exported to user-space via mmap().
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"cstatus" is a re-encoding of control.tsc_on/nractrs/nrictrs,
|
|
Packit |
577717 |
used because it reduces overheads in key low-level operations.
|
|
Packit |
577717 |
Operations on cstatus values include:
|
|
Packit |
577717 |
- unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs, unsigned int nrictrs);
|
|
Packit |
577717 |
Construct a cstatus value.
|
|
Packit |
577717 |
- unsigned int perfctr_cstatus_enabled(unsigned int cstatus);
|
|
Packit |
577717 |
Check if any part (tsc_on, nractrs, nrictrs) of the cstatus is non-zero.
|
|
Packit |
577717 |
- int perfctr_cstatus_has_tsc(unsigned int cstatus);
|
|
Packit |
577717 |
Check if the tsc_on part of the cstatus is non-zero.
|
|
Packit |
577717 |
- unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus);
|
|
Packit |
577717 |
Retrieve nractrs+nrictrs from the cstatus.
|
|
Packit |
577717 |
- unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus);
|
|
Packit |
577717 |
Check if the nrictrs part of cstatus is non-zero.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"tsc_start" and "tsc_sum" record the state of the TSC.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"pmc[]" contains the per-counter state, in the "start" and "sum"
|
|
Packit |
577717 |
fields. The "map" field contains the corresponding hardware counter
|
|
Packit |
577717 |
identification, from the counter's entry in "control.pmc_map[]";
|
|
Packit |
577717 |
it is copied into pmc[] to reduce overheads in key low-level operations.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
"control" contains the control data which determines the
|
|
Packit |
577717 |
behaviour of the counters.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
User-space overflow signal handler items
|
|
Packit |
577717 |
----------------------------------------
|
|
Packit |
577717 |
After a counter has overflowed, a user-space signal handler may
|
|
Packit |
577717 |
be invoked with a "struct siginfo" identifying the source of the
|
|
Packit |
577717 |
signal and the set of overflown counters.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define SI_PMC_OVF ..
|
|
Packit |
577717 |
|
|
Packit |
577717 |
Value to be stored in "si.si_code".
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define si_pmc_ovf_mask ..
|
|
Packit |
577717 |
|
|
Packit |
577717 |
Field in which to store a bit-mask of the overflown counters.
|
|
Packit |
577717 |
|
|
Packit |
577717 |
Kernel-internal API
|
|
Packit |
577717 |
-------------------
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Driver init/exit.
|
|
Packit |
577717 |
perfctr_cpu_init() performs hardware detection and may fail. */
|
|
Packit |
577717 |
extern int perfctr_cpu_init(void);
|
|
Packit |
577717 |
extern void perfctr_cpu_exit(void);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* CPU type name. Set if perfctr_cpu_init() was successful. */
|
|
Packit |
577717 |
extern char *perfctr_cpu_name;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Hardware reservation. A high-level driver must reserve the
|
|
Packit |
577717 |
hardware before it may use it, and release it afterwards.
|
|
Packit |
577717 |
"service" is a unique string identifying the high-level driver.
|
|
Packit |
577717 |
perfctr_cpu_reserve() returns NULL on success; if another
|
|
Packit |
577717 |
high-level driver has reserved the hardware, then that
|
|
Packit |
577717 |
driver's "service" string is returned. */
|
|
Packit |
577717 |
extern const char *perfctr_cpu_reserve(const char *service);
|
|
Packit |
577717 |
extern void perfctr_cpu_release(const char *service);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* PRE: state has no running interrupt-mode counters.
|
|
Packit |
577717 |
Check that the new control data is valid.
|
|
Packit |
577717 |
Update the low-level driver's private control data.
|
|
Packit |
577717 |
is_global should be zero for per-process counters and non-zero
|
|
Packit |
577717 |
for global-mode counters.
|
|
Packit |
577717 |
Returns a negative error code if the control data is invalid. */
|
|
Packit |
577717 |
extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Stop i-mode counters. Update sums and start values.
|
|
Packit |
577717 |
Read a-mode counters. Subtract from start and accumulate into sums.
|
|
Packit |
577717 |
Must be called with preemption disabled. */
|
|
Packit |
577717 |
extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Reset i-mode counters to their start values.
|
|
Packit |
577717 |
Write control registers.
|
|
Packit |
577717 |
Read a-mode counters and update their start values.
|
|
Packit |
577717 |
Must be called with preemption disabled. */
|
|
Packit |
577717 |
extern void perfctr_cpu_resume(struct perfctr_cpu_state *state);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Perform an efficient combined suspend/resume operation.
|
|
Packit |
577717 |
Must be called with preemption disabled. */
|
|
Packit |
577717 |
extern void perfctr_cpu_sample(struct perfctr_cpu_state *state);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* The type of a perfctr overflow interrupt handler.
|
|
Packit |
577717 |
It will be called in IRQ context, with preemption disabled. */
|
|
Packit |
577717 |
typedef void (*perfctr_ihandler_t)(unsigned long pc);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Install a perfctr overflow interrupt handler.
|
|
Packit |
577717 |
Should be called after perfctr_cpu_reserve() but before
|
|
Packit |
577717 |
any counter state has been activated. */
|
|
Packit |
577717 |
extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* PRE: The state has been suspended and sampled by perfctr_cpu_suspend().
|
|
Packit |
577717 |
Should be called from the high-level driver's perfctr_ihandler_t,
|
|
Packit |
577717 |
and preemption must not have been enabled.
|
|
Packit |
577717 |
Identify which counters have overflown, reset their start values
|
|
Packit |
577717 |
from ireset[], and perform any necessary hardware cleanup.
|
|
Packit |
577717 |
Returns a bit-mask of the overflown counters. */
|
|
Packit |
577717 |
extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
|
|
Packit |
577717 |
bypass internal caching and force a reload of the i-mode pmcs.
|
|
Packit |
577717 |
This ensures that perfctr_cpu_identify_overflow()'s state changes
|
|
Packit |
577717 |
are propagated to the hardware. */
|
|
Packit |
577717 |
extern void perfctr_cpu_ireload(struct perfctr_cpu_state*);
|