Here we present some simple examples of how to use the libpfm library. There is
also more complete set of examples included with the library
source code. The example on this page use version 3.0 of the library which is not
compatible with version 2.0. For version 2.0 examples, click here.
Example of a self-monitoring process using the opcode matcher PMC8 on Itanium 2
/*
* we must include the perfmon, pfmlib, and Itanium2 specific header files
*/
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <perfmon/pfmlib.h>
#include <perfmon/perfmon.h>
#include <perfmon/pfmlib_itanium2.h>
#define MAX_EVT_NAME_LEN 256
#define NUM_PMCS PFMLIB_MAX_PMCS
#define NUM_PMDS PFMLIB_MAX_PMDS
int
main(int argc, char **argv)
{
int i, ret, fd;
pfmlib_input_param_t inp;
pfmlib_output_param_t outp;
pfmlib_ita2_input_param_t ita2_inp;
pfarg_reg_t pc[NUM_PMCS];
pfarg_reg_t pd[NUM_PMDS];
pfarg_context_t ctx[1];
pfarg_load_t load_args;
char name[MAX_EVT_NAME_LEN];
/*
* Initialize libpfm (required before we use it)
*/
if (pfm_initialize() != PFMLIB_SUCCESS) {
fprintf(stderr, "cannot initialize libpfm\n");
exit(1);
}
/*
* initialize local variables
*/
memset(pd, 0, sizeof(pd));
memset(pc, 0, sizeof(pc));
memset(ctx, 0, sizeof(ctx));
memset(&inp,0, sizeof(inp));
memset(&outp,0, sizeof(outp));
memset(&load_args,0, sizeof(load_args));
memset(&ita2_inp,0, sizeof(ita2_inp));
/*
* find event descriptor for our event
*/
ret = pfm_find_event("IA64_TAGGED_INST_RETIRED_IBRP0_PMC8",
&inp.pfp_events[0].event);
if (ret != PFMLIB_SUCCESS) {
fprintf(stderr,"ia64_tagged_inst_retired not found\n");
exit(1);
}
/*
* indicate that we are using the PMC8 opcode matcher
*/
ita2_inp.pfp_ita2_pmc8.opcm_used = 1;
/*
* load value to install in PMC8 (some control fields may be
* modified by library). Here it is the pattern for the
* br.cloop instruction.
*/
ita2_inp.pfp_ita2_pmc8.pmc_val = 0x1400028003fff1fa;
/*
* set the default privilege mode for all counters:
* PFM_PLM3 : user level only
*/
inp.pfp_dfl_plm = PFM_PLM3;
/*
* how many events we are interested in
*/
inp.pfp_event_count = 1;
/*
* let the library figure out the values for the PMCS
*/
ret = pfm_dispatch_events(&inp, &ita2_inp, &outp, NULL);
if (ret != PFMLIB_SUCCESS) {
fprintf(stderr, "cannot configure events: %s\n",
pfm_strerror(ret));
exit(1);
}
/*
* copy the library parameters to the OS-specific structures.
* Here we propagate the PMC indexes and values.
*/
for (i=0; i < outp.pfp_pmc_count; i++) {
pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
}
/*
* propagate the PMC indexes to the PMD arguments to the
* kernel. This is required for counting monitors.
*/
for (i=0; i < inp.pfp_event_count; i++) {
pd[i].reg_num = pc[i].reg_num;
}
/*
* now create the context
*/
ret = perfmonctl(0, PFM_CREATE_CONTEXT, ctx, 1);
if (ret == -1) {
fprintf(stderr, "PFM_CREATE_CONTEXT errno %d\n", errno);
exit(1);
}
/*
* extract the file descriptor identifying the context
*/
fd = ctx[0].ctx_fd;
/*
* Now program the PMC registers.
* In this case, we write two PMC registers
*/
ret = perfmonctl(fd, PFM_WRITE_PMCS, pc, outp.pfp_pmc_count);
if (ret == -1) {
fprintf(stderr, "PFM_WRITE_PMCS errno %d\n",errno);
exit(1);
}
/*
* We reset the PMDs that go with the PMCs
*/
ret = perfmonctl(fd, PFM_WRITE_PMDS, pd, inp.pfp_event_count);
if (ret == -1) {
fprintf(stderr, "PFM_WRITE_PMDS errno %d\n",errno);
exit(1);
}
/*
* attach the perfmon context to ourself
*/
load_args.load_pid = getpid();
ret = perfmonctl(fd, PFM_LOAD_CONTEXT, &load_args, 1);
if (ret == -1) {
fprintf(stderr, "PFM_LOAD_CONTEXT errno %d\n",errno);
exit(1);
}
/*
* start monitoring. For self-monitoring tasks, it is possible to
* use the lightweight library call instead of PFM_START
*/
pfm_self_start(fd);
/*
*
* code to monitor goes here
*
*/
/*
* stop monitoring. For self-monitoring tasks, it is possible to
* use the lightweight library call instead of PFM_STOP
*/
pfm_self_stop(fd);
/*
* now read the results
*/
ret = perfmonctl(fd, PFM_READ_PMDS, pd, inp.pfp_event_count);
if (ret == -1) {
fprintf(stderr, "PFM_READ_PMDS errno %d\n",errno);
exit(1);
}
/*
* and finally, print the results
*/
for (i=0; i < inp.pfp_event_count; i++) {
pfm_get_event_name(inp.pfp_events[i].event, name, MAX_EVT_NAME_LEN);
printf("PMD%u %20lu %s\n",
pd[i].reg_num,
pd[i].reg_value,
name);
}
/*
* destroy the perfmon context
*/
close(fd);
return 0;
}