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_sum_cycles()    -- accumulated time intervals
   pmc_sum_events()    -- accumulated events over time
   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,
Last revised: 2 August 2000