Performance-Monitoring Counters Library, for Intel/AMD Processors and Linux
This example introduces
pmc_counter_t -- cycle and event accumulators, user interface
pmc_counter_init() -- initialize the event selectors
pmc_selector_t
pmc_cycles_t
pmc_events_t
pmc_cycles_bits
pmc_events_bits
pmc_sum_cycles() -- accumulated time intervals
pmc_sum_events() -- accumulated events over time
pmc_seconds()
Computing events per second
Previous example -- pmc_data_t
Download this example
Next example -- pmc_counter_t, details
Return to Main Menu
Compile with
gcc -o menu6 -O `pmc_options` menu6.c -lpmc
Try these examples (Pentium Pro/II/III):
menu6
menu6 --e 192,194
menu6 --e 0xc0,0xc2
menu6 --e 0x28,0x2a --mesi 3,4
menu6 --e 0xc0,0xc2 --mesi 3,4
Try these examples (AMD Athlon):
menu6
menu6 --e 192,193
menu6 --e 0xc0,0xc1
menu6 --e 0x40 --mesi 0,1,2,3
#include <pmc_lib.h>
int main(int argc, char * argv[])
{
pmc_control_t Ctl = pmc_control_null;
pmc_data_t t0, t1;
pmc_counter_t tot;
int k;
if (pmc_getargs(stderr, argv[0], &argc, &argv, &Ctl) == FALSE)
{ exit(1); }
printf("sizeof(pmc_counter_t) = %d\n", sizeof(pmc_counter_t));
printf("sizeof(pmc_selector_t) = %d\n", sizeof(pmc_selector_t));
printf("sizeof(pmc_cycles_t) = %d\n", sizeof(pmc_cycles_t));
printf("sizeof(pmc_events_t) = %d\n", sizeof(pmc_events_t));
printf("pmc_cycles_bits = %d\n", pmc_cycles_bits);
printf("pmc_events_bits = %d\n", pmc_events_bits);
pmc_counter_init(&tot, &Ctl); /* initialize the accumulator */
if (pmc_open(0) == FALSE) /* open /dev/pmc */
{ exit(1); }
pmc_read(&t0); /* read the counters */
/* do something */
pmc_read(&t1); /* read the counters */
pmc_close(); /* close /dev/pmc */
/* the selector field is almost never of direct interest */
printf("tot.selector =");
for (k = 0; k < pmc_event_counters; k++)
{ printf(" %08lx", tot.selector.c[k]); }
printf("\n");
printf("tot.pmc_sum_cycles() = %016llx\n", pmc_sum_cycles(&tot));
for (k = 0; k < pmc_event_counters; k++)
{
printf("tot.pmc_sum_events(%d) = %016llx\n", k, pmc_sum_events(&tot,k));
}
printf("tot.pmc_seconds() = %16.9f\n", pmc_seconds(pmc_sum_cycles(&tot)));
exit(0);
}
Synopsis
typedef struct { pmc_uint32_t c[pmc_event_counters]; } pmc_selector_t;
typedef unsigned long long int pmc_cycles_t;
typedef unsigned long long int pmc_events_t;
#define pmc_cycles_bits 64
#define pmc_events_bits 64
typedef struct
{
/* event codes */
pmc_selector_t selector;
/* housekeeping */
int clean; /* clean == 0,+ve -- remove pmc_read() overhead? */
int stats; /* stats == 0,1,2 -- level of statistical detail */
/* pmc_read() overhead estimate (clean > 0) */
pmc_cycles_t overhead_cycles;
pmc_events_t overhead_events[pmc_event_counters];
/* summation over all time intervals (stats == 0,1,2) */
pmc_cycles_t sum_cycles;
pmc_events_t sum_events[pmc_event_counters];
...
}
pmc_counter_t;
void pmc_counter_init(pmc_counter_t * counter, const pmc_control_t * ctl);
pmc_cycles_t pmc_sum_cycles(const pmc_counter_t * const a);
pmc_events_t pmc_sum_events(const pmc_counter_t * const a, const int i);
double pmc_seconds(const pmc_cycles_t c);
Naming convention
These values represent an interval of time, between two moments, so cycles
and events are plural. But, considering that pmc_accumulate() changes one
of the pmc_data_t values from a moment to an interval, the convention is
not consistent.
Notes
The pmc_counter_t type holds selector information for a pair of events,
and the results of measurements taken with those events. A pmc_counter_t
object is initialized from a pmc_control_t object by pmc_counter_init().
Two pmc_data_t values, obtained by pmc_read(), are subtracted and added
into a pmc_counter_t object by pmc_accumulate(). Further examples will
present more details.
The pmc_selector_t type holds exactly the information used by the processor's
model-specific control registers for the event counters. This value is
printed by pmc_control_print(), or can be inspected directly as shown above.
Because the processor's rules for setting the control bits may be obscure
(though to Intel's credit, they are now reasonably well documented), it is
best to leave the details to pmc_counter_init(). The following components
of *ctl are used by pmc_counter_init() to construct the selector field
of *counter:
event event selection
duration counter control
user user mode
os operating system mode
pc pin control
mesi unit mask for L2 cache
bus unit mask for external bus logic
mmx unit mask for MMX instructions
compare counter mask
invert counter mask, invert flag
apic local APIC enable
enable global enable
The pmc_counter_t acts as an accumulator for time and event measurements.
The most basic information, which is always retained, is the total number
of cycles expended and events recorded over the measured time intervals.
The stats component of *ctl, assigned to the stats component of *counter
by pmc_counter_init(), can be adjusted to affect the level of statistical
detail retained. Further examples will present more information.
The accumulator types, pmc_cycles_t and pmc_events_t, have at least as
many bits as the raw data types. That is,
pmc_cycle_bits <= pmc_cycles_bits
pmc_event_bits <= pmc_events_bits
and the type conversions from pmc_cycle_t to pmc_cycles_t or pmc_event_t
to pmc_events_t introduce no errors.
The accumulated cycles and events can be extracted by pmc_sum_cycles() and
pmc_sum_events(), and pmc_cycles_t converted to seconds by pmc_seconds().
The measured number of events per cycle, or events per second, or event 0
per event 1, can be reported by
pmc_sum_events(&tot,0) / pmc_sum_cycles(&tot)
pmc_sum_events(&tot,1) / pmc_sum_cycles(&tot)
pmc_sum_events(&tot,0) / pmc_seconds(pmc_sum_cycles(&tot))
pmc_sum_events(&tot,1) / pmc_seconds(pmc_sum_cycles(&tot))
pmc_sum_events(&tot,0) / pmc_sum_events(&tot,1).
These are also printed by pmc_print_results().
Further Notes
The programs menu6[ab].c contain more code than is given here in menu6.c.
You are invited to explain the addresses that are shown, and the importance
of the differences between menu6a.c and menu6b.c.
Forward References
pmc_select(), pmc_read(), pmc_accumulate()
pmc_print_results()
Performance-Monitoring Counters Library, for Intel/AMD Processors and Linux
Author: Don Heller, dheller@scl.ameslab.gov
Last revised: 2 August 2000