Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP

hp.com home


kernel perfmon-1.x interface examples

» 

HP Labs

» Research
» News and events
» Technical reports
» About HP Labs
» Careers @ HP Labs
» People
» Worldwide sites
» Downloads
Content starts here

Here we present two simple examples of how to use the kernel perfmon-1.x interface (2.4-based kernels) and also the library (libpfm-2.0) for counting:

There are more examples, including on how to use the PMU specific features and sampling in the set of examples distributed with the libpfm library.

The following extra examples can also be downloaded:

  • A simple showing how to use perfmon to get fine grain timer interrupts can be found here. Thanks to Peter Chubb.

Example of a self-monitoring process

/*
 * main libpfm include file
 */
#include <perfmon/pfmlib.h>

int
main(int argc, char **argv)
{
  char *name;
  int i, ret;
  pid_t mypid = getpid();
  pfmlib_param_t evt;
  pfarg_reg_t pd[2];
  pfarg_context_t ctx[1];

  /*
   * 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(ctx, 0, sizeof(ctx));
  memset(&evt,0, sizeof(evt));

  /*
   * find event descriptors using their event names
   */
  ret = pfm_find_event("cpu_cycles", 
                       &evt.pfp_events[0].event);
  if (ret != PFMLIB_SUCCESS) {
     fprintf(stderr,"cpu_cycles not found\n");
     exit(1);
   }
  ret = pfm_find_event("ia64_inst_retired", 
                       &evt.pfp_events[1].event);
  if (ret != PFMLIB_SUCCESS) {
     fprintf(stderr,"ia64_inst_retired not found\n");
     exit(1);
   }

  /*
   * set the default privilege mode for all counters:
   *   PFM_PLM3 : user level only
   */
  evt.pfp_dfl_plm = PFM_PLM3; 

  /*
   * how many events we are interested in
   */
  evt.pfp_event_count = 2;

  /*
   * let the library figure out the values for the PMCS
   */
  ret = pfm_dispatch_events(&evt);
  if (ret != PFMLIB_SUCCESS) {
    fprintf(stderr, "cannot configure events: %s\n", 
            pfm_strerror(ret));
    exit(1);
  }
  /*
   * now create the context for self monitoring/per-task
   */
   ret = perfmonctl(mypid, PFM_CREATE_CONTEXT, ctx, 1);
  if (ret == -1) {
    fprintf(stderr, "PFM_CREATE_CONTEXT errno %d\n", errno);
    exit(1);
  }
  /*
   * Initialize the PMU with safe values. psr.up is cleared.
   */
   ret = perfmonctl(pid, PFM_ENABLE, NULL, 0);
  if (ret  == -1) {
    fprintf(stderr, "PFM_ENABLE errno %d\n",errno);
    exit(1);
  }

  /*
   * Now prepare the arguments to write the PMDs.
   * counters are pair of PMC/PMD and they use the same
   * index. We propagate the indexes used for the PMCs
   * back to their equivalent PMDs.
   */
  for (i=0; i < evt.pfp_event_count; i++) {
    pd[i].reg_num = evt.pfp_pc[i].reg_num;
  }
  /*
   * Now program the PMC registers.
   */
   ret = perfmonctl(mypid, PFM_WRITE_PMCS, evt.pfp_pc, evt.pfp_pc_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(mypid, PFM_WRITE_PMDS, pd, evt.pfp_event_count);
  if (ret == -1) {
    fprintf(stderr, "PFM_WRITE_PMDS 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_start();

  /* 
   *
   * 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_stop();

  /*
   * now read the results
   */
 ret = perfmonctl(mypid, PFM_READ_PMDS, pd, evt.pfp_event_count);
  if (ret == -1) {
    fprintf(stderr, "READ_PMDS errno %d\n",errno);
    exit(1);
  }
  /*
   * and finally, print the results
   */
  for (i=0; i < evt.pfp_event_count; i++) {
    pfm_get_event_name(evt.pfp_events[i].event, &name);
    printf("PMD%u %20lu %s\n", 
            pd[i].reg_num, 
            pd[i].reg_value, 
            name);
  }
  /*
   * destroy the perfmon context
   */
   ret = perfmonctl(pid, PFM_DESTROY_CONTEXT, NULL, 0);
  if (ret == -1) {
    fprintf(stderr, "PFM_DESTROY errno %d\n",errno);
    exit(1);
  }
  return 0;
}


Example of a single-cpu system wide session

/*
 * main libpfm include file
 */
#include <perfmon/pfmlib.h>

int
main(int argc, char **argv)
{
  char *name;
  int i, ret;
  pid_t mypid = getpid();
  pfmlib_param_t evt;
  pfarg_reg_t pd[2];
  pfarg_context_t ctx[1];

  /*
   * 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(ctx, 0, sizeof(ctx));
  memset(&evt,0, sizeof(evt));

  /*
   * find event descriptors using their event names
   */
  ret = pfm_find_event("cpu_cycles", 
                       &evt.pfp_events[0].event);
  if (ret != PFMLIB_SUCCESS) {
     fprintf(stderr,"cpu_cycles not found\n");
     exit(1);
   }
  ret = pfm_find_event("ia64_inst_retired", 
                       &evt.pfp_events[1].event);
  if (ret != PFMLIB_SUCCESS) {
     fprintf(stderr,"ia64_inst_retired not found\n");
     exit(1);
   }

  /*
   * set the default privilege mode for all counters:
   *   PFM_PLM3 : user level only
   */
  evt.pfp_dfl_plm = PFM_PLM3; 

  /*
   * how many events we are interested in
   */
  evt.pfp_event_count = 2;

  /*
   * we are using the counters for a system-wide session
   */
  evt.pfp_pm = 1;

  /*
   * let the library figure out the values for the PMCS
   */
  ret = pfm_dispatch_events(&evt);
  if (ret != PFMLIB_SUCCESS) {
    fprintf(stderr, "cannot configure events: %s\n", 
            pfm_strerror(ret));
    exit(1);
  }

  /*
   * indicate on which CPU the session must run,
   * here CPU0
   */
  ctx[0].ctx_cpu_mask = 1UL;

  /*
   * now create the context the system-wide session
   * upon return the process is running on the designated CPU
   */
   ret = perfmonctl(mypid, PFM_CREATE_CONTEXT, ctx, 1);
  if (ret == -1) {
    fprintf(stderr, "PFM_CREATE_CONTEXT errno %d\n", errno);
    exit(1);
  }
  /*
   * Initialize the PMU with safe values. psr.up is cleared.
   */
  ret = perfmonctl(pid, PFM_ENABLE, NULL, 0);
  if (ret  == -1) {
    fprintf(stderr, "PFM_ENABLE errno %d\n",errno);
    exit(1);
  }

  /*
   * Now prepare the arguments to write the PMDs.
   * counters are pair of PMC/PMD and they use the same
   * index. We propagate the indexes used for the PMCs
   * back to their equivalent PMDs.
   */
  for (i=0; i < evt.pfp_event_count; i++) {
    pd[i].reg_num = evt.pfp_pc[i].reg_num;
  }
  /*
   * Now program the PMC registers.
   */
   ret = perfmonctl(mypid, PFM_WRITE_PMCS, evt.pfp_pc, evt.pfp_pc_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(mypid, PFM_WRITE_PMDS, pd, evt.pfp_event_count);
  if (ret == -1) {
    fprintf(stderr, "PFM_WRITE_PMDS errno %d\n",errno);
    exit(1);
  }

  /*
   * start monitoring. For system-wide sessions,
   * we must call the kernel
   */
  ret = perfmonctl(mypid, PFM_START, NULL, 0);
  if (ret == -1) {
    fprintf(stderr, "PFM_START errno %d\n",errno);
    exit(1);
  }
  /* 
   * now monitoring
   */
   printf("<press a key to stop monitoring>\n"); getchar();

  /*
   * stop monitoring.  For system-wide sessions, 
   * we must call the kernel
   */
  ret = perfmonctl(mypid, PFM_STOP, NULL, 0);
  if (ret == -1) {
    fprintf(stderr, "PFM_STOP errno %d\n",errno);
    exit(1);
  }

  /*
   * now read the results
   */
   ret = perfmonctl(mypid, PFM_READ_PMDS, pd, evt.pfp_event_count);
  if (ret == -1) {
    fprintf(stderr, "READ_PMDS errno %d\n",errno);
    exit(1);
  }
  /*
   * and finally, print the results
   */
  for (i=0; i < evt.pfp_event_count; i++) {
    pfm_get_event_name(evt.pfp_events[i].event, &name);
    printf("PMD%u %20lu %s\n", 
            pd[i].reg_num, 
            pd[i].reg_value, 
            name);
  }
  /*
   * destroy the perfmon context
   */
   ret = perfmonctl(pid, PFM_DESTROY_CONTEXT, NULL, 0);
  if (ret == -1) {
    fprintf(stderr, "PFM_DESTROY errno %d\n",errno);
    exit(1);
  }
  return 0;
}


perfmon project links

» project home
» perfmon overview
» libpfm overview
» pfmon overview
» mailing list
» downloads
» bibliography
» presentations

kernel interface links

» FAQ
» examples
Printable version
Privacy statement Using this site means you accept its terms Feedback to HP Labs
© 2009 Hewlett-Packard Development Company, L.P.