static int prepare_btb(pfmon_event_set_t *set) { pfmlib_ita_input_param_t *param = set->mod_inp; unsigned int i; int found_btb = -1; for(i=0; i < set->event_count; i++) { if (pfm_ita_is_btb(set->inp.pfp_events[i].event)) { found_btb = i; goto found; } } /* * check for no BTB event, but just BTB options. */ if (param->pfp_ita_btb.btb_used == 0) return 0; found: /* * in case of no BTB event found, we are in free running mode (no BTB sampling) * therefore we include the BTB PMD in all samples */ if (found_btb != -1 && (set->short_rates[i].flags & PFMON_RATE_VAL_SET)) { set->smpl_pmds[i][0] |= BTB_REGS_MASK; set->common_reset_pmds[0] |= M_PMD(16); } else { set->common_smpl_pmds[0] |= BTB_REGS_MASK; set->common_reset_pmds[0] |= BTB_REGS_MASK; } return 0; }
static int prepare_ears(pfmon_event_set_t *set) { unsigned int i; int ev, is_iear; /* * search for an EAR event */ for(i=0; i < set->event_count; i++) { ev = set->inp.pfp_events[i].event; /* look for EAR event */ if (pfm_ita_is_ear(ev) == 0) continue; is_iear = pfm_ita_is_iear(ev); /* * when used as sampling period, then just setup the bitmask * of PMDs to record in each sample */ if (set->short_rates[i].flags & PFMON_RATE_VAL_SET) { set->smpl_pmds[i][0] |= is_iear ? IEAR_REGS_MASK : DEAR_REGS_MASK; continue; } /* * for D-EAR, we must clear PMD3.stat and PMD17.vl to make * sure we do not interpret the register in the wrong manner. * * for I-EAR, we must clear PMD0.stat to avoid interpreting stale * entries * * This is ONLY necessary when the events are not used as sampling * periods. */ set->common_reset_pmds[0] |= is_iear ? M_PMD(0) : M_PMD(17) | M_PMD(3); } return 0; }
int main(void) { int ret; int type = 0; pid_t pid = getpid(); pfmlib_ita2_param_t ita_param; pfarg_reg_t pd[NUM_PMDS]; pfarg_context_t ctx[1]; pfmlib_options_t pfmlib_options; struct sigaction act; /* * Initialize pfm library (required before we can use it) */ if (pfm_initialize() != PFMLIB_SUCCESS) { fatal_error("Can't initialize library\n"); } /* * Let's make sure we run this on the right CPU */ pfm_get_pmu_type(&type); if (type != PFMLIB_ITANIUM2_PMU) { char *model; pfm_get_pmu_name(&model); fatal_error("this program does not work with %s PMU\n", model); } /* * Install the overflow handler (SIGPROF) */ memset(&act, 0, sizeof(act)); act.sa_handler = (sig_t)overflow_handler; sigaction (SIGPROF, &act, 0); /* * pass options to library (optional) */ memset(&pfmlib_options, 0, sizeof(pfmlib_options)); pfmlib_options.pfm_debug = 0; /* set to 1 for debug */ pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */ pfm_set_options(&pfmlib_options); memset(pd, 0, sizeof(pd)); memset(ctx, 0, sizeof(ctx)); /* * prepare parameters to library. we don't use any Itanium * specific features here. so the pfp_model is NULL. */ memset(&evt,0, sizeof(evt)); memset(&ita_param,0, sizeof(ita_param)); /* * because we use a model specific feature, we must initialize the * model specific pfmlib parameter structure and link it to the * common structure. * The magic number is a simple mechanism used by the library to check * that the model specific data structure is decent. You must set it manually * otherwise the model specific feature won't work. */ ita_param.pfp_magic = PFMLIB_ITA2_PARAM_MAGIC; evt.pfp_model = &ita_param; /* * Before calling pfm_find_dispatch(), we must specify what kind * of branches we want to capture. We are interesteed in all the mispredicted branches, * therefore we program we set the various fields of the BTB config to: */ ita_param.pfp_ita2_btb.btb_used = 1; ita_param.pfp_ita2_btb.btb_ds = 0; ita_param.pfp_ita2_btb.btb_tm = 0x3; ita_param.pfp_ita2_btb.btb_ptm = 0x3; ita_param.pfp_ita2_btb.btb_ppm = 0x3; ita_param.pfp_ita2_btb.btb_brt = 0x0; ita_param.pfp_ita2_btb.btb_plm = PFM_PLM3; /* * To count the number of occurence of this instruction, we must * program a counting monitor with the IA64_TAGGED_INST_RETIRED_PMC8 * event. */ if (pfm_find_event_byname("BRANCH_EVENT", &evt.pfp_events[0].event) != PFMLIB_SUCCESS) { fatal_error("cannot find event BRANCH_EVENT\n"); } /* * set the (global) privilege mode: * PFM_PLM3 : user level only */ evt.pfp_dfl_plm = PFM_PLM3; /* * how many counters we use */ evt.pfp_event_count = 1; /* * let the library figure out the values for the PMCS */ if ((ret=pfm_dispatch_events(&evt)) != PFMLIB_SUCCESS) { fatal_error("cannot configure events: %s\n", pfm_strerror(ret)); } /* * for this example, we will get notified ONLY when the sampling * buffer is full. The monitoring is not to be inherited * in derived tasks */ ctx[0].ctx_flags = PFM_FL_INHERIT_NONE; ctx[0].ctx_notify_pid = getpid(); ctx[0].ctx_smpl_entries = SMPL_BUF_NENTRIES; ctx[0].ctx_smpl_regs[0] = smpl_regs = BTB_REGS_MASK; /* * now create the context for self monitoring/per-task */ if (perfmonctl(pid, PFM_CREATE_CONTEXT, ctx, 1) == -1 ) { if (errno == ENOSYS) { fatal_error("Your kernel does not have performance monitoring support!\n"); } fatal_error("Can't create PFM context %s\n", strerror(errno)); } printf("Sampling buffer mapped at %p\n", ctx[0].ctx_smpl_vaddr); smpl_vaddr = ctx[0].ctx_smpl_vaddr; /* * Must be done before any PMD/PMD calls (unfreeze PMU). Initialize * PMC/PMD to safe values. psr.up is cleared. */ if (perfmonctl(pid, PFM_ENABLE, NULL, 0) == -1) { fatal_error("perfmonctl error PFM_ENABLE errno %d\n",errno); } /* * indicate we want notification when buffer is full */ evt.pfp_pc[0].reg_flags |= PFM_REGFL_OVFL_NOTIFY; /* * Now prepare the argument to initialize the PMD and the sampling period */ pd[0].reg_num = evt.pfp_pc[0].reg_num; pd[0].reg_value = (~0UL) - SMPL_PERIOD +1; pd[0].reg_long_reset = (~0UL) - SMPL_PERIOD +1; pd[0].reg_short_reset = (~0UL) - SMPL_PERIOD +1; /* * When our counter overflows, we want to BTB index to be reset, so that we keep * in sync. This is required to make it possible to interpret pmd16 on overflow * to avoid repeating the same branch several times. */ evt.pfp_pc[0].reg_reset_pmds[0] = M_PMD(16); /* * reset pmd16, short and long reset value are set to zero as well */ pd[1].reg_num = 16; pd[1].reg_value = 0UL; /* * Now program the registers * * We don't use the save variable to indicate the number of elements passed to * the kernel because, as we said earlier, pc may contain more elements than * the number of events we specified, i.e., contains more thann coutning monitors. */ if (perfmonctl(pid, PFM_WRITE_PMCS, evt.pfp_pc, evt.pfp_pc_count) == -1) { fatal_error("perfmonctl error PFM_WRITE_PMCS errno %d\n",errno); } if (perfmonctl(pid, PFM_WRITE_PMDS, pd, 2) == -1) { fatal_error("perfmonctl error PFM_WRITE_PMDS errno %d\n",errno); } /* * Let's roll now. */ do_test(100000); /* * We must call the processing routine to cover the last entries recorded * in the sampling buffer, i.e. which may not be full */ process_smpl_buffer(); /* * let's stop this now */ if (perfmonctl(pid, PFM_DESTROY_CONTEXT, NULL, 0) == -1) { fatal_error("perfmonctl error PFM_DESTROY errno %d\n",errno); } return 0; }