|About||Articles||How to contact me||Projects||Site Map|
Please see http://wiki.FreeBSD.org/PmcTools.
This document is a short tutorial on using the pmc(3) library.
The hwpmc(4) driver virtualizes the available PMC hardware on your CPU, allowing multiple processes to use the hardware at the same time. The OS (i.e., the hwpmc(4) driver) takes care of multiplexing the hardware as needed.
The process of using a PMC involves informing the hwpmc(4) driver about the kind of event (e.g., cache misses, instructions retired) desired to be counted. If an appropriate PMC counter could be allocated to the count this event, the driver returns a 'handle' of type pmcid_t — see the manual entry for pmc_allocate() in pmc(3).
The hwpmc(4) kernel module needs to be loaded in the kernel before stuff will work. This needs to be done using kldload(8) or by compiling the driver into the base kernel image.
Normally, application programs will access the hwpmc(4) driver using the pmc(3) library. Application programs will initialize the pmc(3) library with a call to pmc_init() .
... if (pmc_init() < 0) err(EX_OSERR, "Cannot initialize pmc(3)"); ...
PMCs can be allocated in 4 modes:
This tutorial only covers the first three modes of operation.
PMCs are allocated by invoking the pmc_allocate function.
int pmc_allocate(char *_ctrspec, enum pmc_mode _mode, uint32_t _flags, int _cpu, pmc_id_t *_pmcid);
Here _ctrspec is an ascii string describing the event desired to be counted with additional qualifiers. Parameter _mode specifies one of the 4 PMC modes described above. Parameter _cpu is normally PMC_CPU_ANY , but for the system-wide modes can be set to the number of the CPU this counter should be allocated on. Return value _pmcid is the handle to the allocated PMC. Function pmc_allocate() will return a zero value if successful.
... char mycounterspec; enum pmc_mode mode; pmcid_t pmcid; ... mode = PMC_MODE_TS; /* thread virtual counter */ ... if (pmc_allocate(mycounterspec, mode, 0 PMC_CPU_ANY, &pmcid) < 0) err(EX_OSERR, "Cannot allocate counter \"%s\"", mycounterspec); ...
The format of a ctrspec string comprises an event name, followed by a comma-separated set of modifiers. For example, with specification ctrspec = "k7-dc-refills-from-l2,unitmask=mes,os,usr" on an AMD Athlon CPU, we are requesting the PMC system to:
The allowed list of PMC events is CPU specific. The full list is documented in the manual page for pmc(3). I have tried to be as consistent with the relevant processor architecture manuals as possible.
You can allocate multiple PMCs per process (subject to available hardware resources), and you can have multiple processes allocating PMCs at the same time. The hwpmc(4) driver ensures that the actual PMC hardware gets appropriately managed.
Once successfully allocated, a PMC counter may be associated with a target process. This is done using the pmc_attach function.
... if (pmc_attach(pmcid, targetpid) < 0) err(EX_OSERR, "Cannot attached to target %d", targetpid); ...
Attaching to a process is optional. By default, the owner process (the one that allocated the PMC) is the one attached to the allocated PMC. The usual security restrictions apply to this operation.
Counters are started using the pmc_start() API.
... if (pmc_start(pmcid) < 0) err(EX_OSERR, "Cannot start pmc"); ...
Once a PMC is started, it may be read using pmc_read() .
... pmc_value_t v; if (pmc_read(pmcid, &v) < 0) err(EX_OSERR, "Cannot read pmc"); ...
Allocated PMCs may be stopped using pmc_stop() , and the current values may be written to using pmc_write() .
Allocated PMCs are released using pmc_release() .
The source code for pmccontrol(8) and pmcstat(8) show the usage of the PMC library.