/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* bos720 src/bos/usr/sbin/perf/pmapi/pmtoolkit/cpi.c 1.7.1.3 */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* Restricted Materials of IBM */ /* */ /* COPYRIGHT International Business Machines Corp. 1999,2011 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ static char rcsid []="@(#)77 1.7.1.3 src/bos/usr/sbin/perf/pmapi/pmtoolkit/cpi.c, pmapi, bos720 7/14/11 18:35:18 "; /* * COMPONENT_NAME: PMAPI * * FUNCTIONS: main * search_cpi_group * search_cpi * * ORIGINS: 27, 83 * * -- ( when * combined with the aggregated modules for this product) * OBJECT CODE ONLY SOURCE MATERIALS * * (C) COPYRIGHT International Business Machines Corp. 1999, 2001. * All Rights Reserved * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ #include #include #include #include #include #include "pmapi.h" #define CYC_INDEX 0 #define INST_INDEX 1 #define MAX_EVENTS 2 char *Search_evs[MAX_EVENTS] = {"PM_CYC", "PM_INST_CMPL"}; /* ************************************************************************* * Name: search_cpi_group * * Function: searches for events PM_CYC and PM_INST_CMPL * within tables of event groups and events. * * Input: myginfo = list of event groups to search * myinfo = list of events used in myginfo * * Output: pmc[CYC_INDEX] = counter selected for PM_CYC * pmc[INST_INDEX] = counter selected for PM_INST_CMPL * evs[0] = selected group number * * Returns 0 if PM_CYC and PM_INST_CMPL were found * -1 if not found * ************************************************************************* */ int search_cpi_group(pm_info2_t *myinfo, pm_groups_info_t *myginfo, int evs[], int pmc[]) { int i, j, counter, event, s_index; pm_events2_t *evp; if (myginfo->event_groups == NULL) { return -1; } /* check each of the available groups */ for (i = 0; i < myginfo->maxgroups; i++) { pmc[CYC_INDEX] = -1; pmc[INST_INDEX] = -1; /* check each of the counter setting within the current group */ for (counter = 0; counter < myinfo->maxpmcs; counter++) { /* get the event id from the list */ event = myginfo->event_groups[i].events[counter]; if (!((event == COUNT_NOTHING) || (myinfo->maxevents[counter] == 0))) { /* retrieve pointer to the event */ evp = &(myinfo->list_events[counter][event]); for (s_index = 0; s_index < MAX_EVENTS; s_index++) { if (strcmp(Search_evs[s_index], evp->short_name)== 0) { if (s_index == CYC_INDEX) pmc[CYC_INDEX] = counter; else if (s_index == INST_INDEX) pmc[INST_INDEX] = counter; break; } } if (pmc[CYC_INDEX] != -1 && pmc[INST_INDEX] != -1) { evs[0] = i; return(0); } } /* if */ } /* for (counter = 0; ... */ } /* for groups */ return(-1); } /* ************************************************************************* * Name: search_cpi * * Function: searches for events PM_CYC and PM_INST_CMPL * within a table of events, while excluding * group_only events. * * Input: myinfo = list of events used in myginfo * * Output: pmc[CYC_INDEX] = counter selected for PM_CYC * pmc[INST_INDEX] = counter selected for PM_INST_CMPL * evs[0..myinfo->maxpmcs] = selected event numbers * * Returns 0 if PM_CYC and PM_INST_CMPL were found * -1 if not found * ************************************************************************* */ int search_cpi(pm_info2_t *myinfo, int evs[], int pmc[]) { int s_index, counter, ev; int i, j; int cyclfound, instfound; int evstmp[MAX_COUNTERS][MAX_EVENTS]; pm_events2_t *wevp; for (counter = 0; counter < myinfo->maxpmcs; counter++) { evstmp[counter][CYC_INDEX] = -1; evstmp[counter][INST_INDEX] = -1; evs[counter] = 0; } /* check each of the hardware counter */ for (counter = 0; counter < myinfo->maxpmcs; counter++) { wevp = myinfo->list_events[counter]; cyclfound = 0; instfound = 0; /* check all available events for current counter */ for (ev = 0; ev < myinfo->maxevents[counter]; ev++, wevp++) { /* skip group-only events */ if (!wevp->status.b.group_only) { /* if not yet found, compare current event to both events searched */ if (!cyclfound) { if (strcmp(Search_evs[CYC_INDEX], wevp->short_name) == 0) { cyclfound = 1; evstmp[counter][CYC_INDEX] = wevp->event_id; } } if (!instfound) { if (strcmp(Search_evs[INST_INDEX], wevp->short_name) == 0) { instfound = 1; evstmp[counter][INST_INDEX] = wevp->event_id; } } /* if both events found, stop the search */ if (cyclfound && instfound) break; } /* if either event searched still not found, continue with next pmc */ if (!cyclfound || !instfound) continue; } /* for ev */ /* search for a couple of pmcs containing the two events */ for (i = 0; i <= counter; i++) { /* check the first event */ if (evstmp[i][CYC_INDEX] == -1) continue; /* check the second event in any other pmc than the one containing the first event */ for (j = 0; j <= counter; j++) { if ((i != j) && (evstmp[j][INST_INDEX] != -1)) break; } /* couple found */ if (j <= counter) { pmc[CYC_INDEX] = i; pmc[INST_INDEX] = j; evs[i] = evstmp[i][CYC_INDEX]; evs[j] = evstmp[j][INST_INDEX]; return(0); } } } /* for counter */ return(-1); } void sigreconfig_handler(int sig) { dr_info_t dri; double new_cycles; if (dr_reconfig(DR_QUERY, &dri) != 0) { /* ignore signal if DR_QUERY fails */ perror("dr_reconfig"); (void)dr_reconfig(DR_RECONFIG_DONE, &dri); return; } if (!dri.migrate && !dri.hibernate) return; /* not a partition migration/hibernation, skip */ if (dri.pre || dri.check) { printf("Counting stopped by a partition migration/hibernation operation\n"); (void)dr_reconfig(DR_RECONFIG_DONE, &dri); exit(-1); } /*No need to handle POST* signals, they are received on a partition restore*/ } main(int argc, char *argv[]) { pm_info2_t myinfo; pm_prog_t myprog; pm_data_t mydata; pm_groups_info_t myginfo; struct sigaction sa; int i, rc, opt; int stime = 5; int maxiter = MAXINT; int verbose = 0; int pmc[MAX_EVENTS]; extern char *optarg; extern int optind; long long last_inst, last_cycles, delt_inst, delt_cycles; /* retrieve processor specific tables of events and groups */ if ((rc = pm_initialize(PM_VERIFIED|PM_UNVERIFIED|PM_CAVEAT|PM_GET_GROUPS, &myinfo, &myginfo, PM_CURRENT)) > 0) { pm_error("pm_initialize", rc); exit(-1); } /* register SIGRECONFIG signal */ bzero(&sa, sizeof (struct sigaction)); sa.sa_handler = sigreconfig_handler; sa.sa_flags = SA_RESTART; /* if interrupted during wait, restart wait */ if (sigaction(SIGRECONFIG, &sa, NULL) != 0) { perror("sigaction"); exit(-1); } while ((opt = getopt(argc, argv, "v")) != EOF) { switch(opt) { case 'v': verbose = 1; break; default: printf("usage: cpi [-v] [interval [count]]\n"); exit(1); } } /* skip arguments already processed */ argc -= optind; argv += optind; /* grab optional arguments */ if (argc > 0) { /* sample duration */ stime = atoi(argv[0]); if (argc > 1) { /* number of iterations */ maxiter = atoi(argv[1]); } } /* set to count in all modes */ myprog.mode.w = 0; myprog.mode.b.kernel = 1; myprog.mode.b.user = 1; /* also count in hypervisor mode if this processor supports it */ if (myinfo.proc_feature.b.hypervisor) { myprog.mode.b.hypervisor = 1; } /* initialize events to count */ for (i = 0; i < myinfo.maxpmcs; i++) { myprog.events[i] = 0; } /* search for events PM_CYC and PM_INST_CMPL first in the event table */ /* while skipping group-only events. If the pair of events cannot be */ /* found in the reduced event table, search for it in the group table */ if (search_cpi(&myinfo, myprog.events, pmc) < 0) { if (search_cpi_group(&myinfo, &myginfo, myprog.events, pmc) < 0) { printf("Could not find cpi events for this processor\n"); exit(-1); } myprog.mode.b.is_group = 1; } /* pmc[CYC_INDEX] (selected pmc number to count PM_CYC), */ /* pmc[INST_INDEX] (selected pmc number to count PM_INST_CMPL), */ /* and myprog.events have all been updated in either search_cpi */ /* or search_cpi_group */ if (verbose) { int ev1, ev2, grp, pmc1, pmc2; pmc1 = pmc[CYC_INDEX]; pmc2 = pmc[INST_INDEX]; if (myprog.mode.b.is_group) { grp = myprog.events[0]; ev1 = myginfo.event_groups[grp].events[pmc1]; ev2 = myginfo.event_groups[grp].events[pmc2]; printf("using group number %d : %s\n", grp, myginfo.event_groups[grp].short_name); } else { ev1 = myprog.events[pmc1]; ev2 = myprog.events[pmc2]; } printf("pmc%d is counting event number %d : %s\n", pmc1+1, ev1, myinfo.list_events[pmc1][ev1].short_name); printf("pmc%d is counting event number %d : %s\n", pmc2+1, ev2, myinfo.list_events[pmc2][ev2].short_name); printf("\n"); } printf(" Instructions Cycles CPI IPC\n"); printf("-------------- -------------- ----- -----\n"); /* set the PM programmation */ if ((rc = pm_set_program(&myprog)) > 0) { pm_error("pm_set_program", rc); exit(-1); } /* start the counters */ if ((rc = pm_start()) > 0) { pm_error("pm_start", rc); exit(-1); } last_inst = 0; last_cycles = 0; for (i = 0; i < maxiter; i++) { sleep(stime); /* get the data */ if ((rc = pm_get_data(&mydata)) > 0) { pm_error("pm_get_data", rc); exit(-1); } delt_inst = mydata.accu[pmc[INST_INDEX]] - last_inst; delt_cycles = mydata.accu[pmc[CYC_INDEX]] - last_cycles; printf("%-14lld %-14lld %5.2f %5.2f\n", delt_inst, delt_cycles, (double) delt_cycles / (double) delt_inst, (double) delt_inst / (double) delt_cycles); last_inst = mydata.accu[pmc[INST_INDEX]]; last_cycles = mydata.accu[pmc[CYC_INDEX]]; } }