1
0
Files
irix-657m-src/eoe/cmd/evctr/evctr_util.c
2022-09-29 17:59:04 +03:00

676 lines
20 KiB
C

/*
* Copyright 1995, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
*
* UNPUBLISHED -- Rights reserved under the copyright laws of the United
* States. Use of a copyright notice is precautionary only and does not
* imply publication or disclosure.
*
* U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
* in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
* in similar or successor clauses in the FAR, or the DOD or NASA FAR
* Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
* 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
*
* THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
* INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
* DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
* PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
* GRAPHICS, INC.
*/
#ident "$Id: evctr_util.c,v 1.7 1999/04/30 15:24:33 steiner Exp $"
#include <sys/types.h>
#include <sys/stat.h>
#include <procfs/procfs.h>
#include <sys/syssgi.h>
#include <sys/systeminfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "evctr_util.h"
EventDesc_t DescR10K[] = {
{ HWPERF_C0PRFCNT0_CYCLES, "CYCLES", "Cycles" },
{ HWPERF_C0PRFCNT0_IINSTR, "INSTRI", "Instructions issued" },
{ HWPERF_C0PRFCNT0_ILD, "LOADI", "Loads, etc. issued" },
{ HWPERF_C0PRFCNT0_IST, "STOREI", "Stores issued" },
{ HWPERF_C0PRFCNT0_ISC, "SCONDI", "Store conditionals issued" },
{ HWPERF_C0PRFCNT0_FAILSC, "SCONDF", "Store conditionals failed" },
{ HWPERF_C0PRFCNT0_DECBR, "BRD", "Branches decoded" },
{ HWPERF_C0PRFCNT0_QWWSC, "WB2$", "Quadwords written back from scache" },
{ HWPERF_C0PRFCNT0_SCDAECC, "ECC2$", "Single-bit ECC errors on scache data" },
{ HWPERF_C0PRFCNT0_PICMISS, "1$IMISS", "Pcache instruction misses" },
{ HWPERF_C0PRFCNT0_SICMISS, "2$IMISS", "Scache instruction misses" },
{ HWPERF_C0PRFCNT0_IMISPRED,"2$IWAYMP", "Scache instruction way misprediction" },
{ HWPERF_C0PRFCNT0_EXTINT, "INT", "External intervention requests" },
{ HWPERF_C0PRFCNT0_EXTINV, "INV", "External invalidate requests" },
{ HWPERF_C0PRFCNT0_VCOH, "FUCOMP", "ALU/FPU completion cycles" },
{ HWPERF_C0PRFCNT0_GINSTR, "INSTRG", "Instructions graduated" },
{ HWPERF_C0PRFCNT1_CYCLES, "CYCLES", "Cycles" },
{ HWPERF_C0PRFCNT1_GINSTR, "INSTRG", "Instructions graduated" },
{ HWPERF_C0PRFCNT1_GLD, "LOADG", "Loads graduated" },
{ HWPERF_C0PRFCNT1_GST, "STOREG", "Stores graduated" },
{ HWPERF_C0PRFCNT1_GSC, "SCONDG", "Store conditionals graduated" },
{ HWPERF_C0PRFCNT1_GFINSTR, "FPG", "Floating point instructions graduated" },
{ HWPERF_C0PRFCNT1_QWWPC, "WB1$", "Quadwords written back from pcache" },
{ HWPERF_C0PRFCNT1_TLBMISS, "TLBMISS", "TLB refill exceptions" },
{ HWPERF_C0PRFCNT1_BRMISS, "BRMP", "Branches mispredicted" },
{ HWPERF_C0PRFCNT1_PDCMISS, "1$DMISS", "Pcache data misses" },
{ HWPERF_C0PRFCNT1_SDCMISS, "2$DMISS", "Scache data misses" },
{ HWPERF_C0PRFCNT1_DMISPRED,"2$DWAYMP", "Scache data way misprediction" },
{ HWPERF_C0PRFCNT1_EXTINTHIT,"INTHIT", "External intervention hits in scache" },
{ HWPERF_C0PRFCNT1_EXTINVHIT,"INVHIT", "External invalidate hits in scache" },
{ HWPERF_C0PRFCNT1_SPEXCLEAN,"UPCLEAN", "Upgrade requests on clean scache lines" },
{ HWPERF_C0PRFCNT1_SPEXSHR, "UPSHARE", "Upgrade requests on shared scache lines" }
};
EventDesc_t DescR12K[HWPERF_EVENTMAX] = {
{ HWPERF_PRFCNT_CYCLES, "CYCLES", "Cycles" },
{ HWPERF_PRFCNT_DINSTR, "INSTRD", "Decoded instructions" },
{ HWPERF_PRFCNT_DLD, "LOADD", "Decoded loads" },
{ HWPERF_PRFCNT_DST, "STORED", "Decoded stores" },
{ HWPERF_PRFCNT_MTHO, "MHTO", "Miss Handling Table occupancy" },
{ HWPERF_PRFCNT_FAILSC, "SCONDF", "Failed store conditionals" },
{ HWPERF_PRFCNT_RESCB, "RESCBR", "Resolved conditional branches" },
{ HWPERF_PRFCNT_QWWSC, "WB2$", "Quadwords written back to scache" },
{ HWPERF_PRFCNT_SCDAECC, "ECC2$", "Correctable scache data array errors" },
{ HWPERF_PRFCNT_PICMISS, "1$IMISS", "Primary instruction cache misses" },
{ HWPERF_PRFCNT_SICMISS, "2$IMISS", "Secondary instruction cache misses" },
{ HWPERF_PRFCNT_IMISPRED, "2$IWAYMP", "Instruction misprediction from scache way predication table" },
{ HWPERF_PRFCNT_EXTINT, "INT", "External interventions" },
{ HWPERF_PRFCNT_EXTINV, "INV", "External invalidates" },
{ HWPERF_PRFCNT_ALUFPUFP, "ALUFPUP", "ALU/FPU forward progress" },
{ HWPERF_PRFCNT_GINSTR, "INSTRG", "Graduated instructions" },
{ HWPERF_PRFCNT_EXPREI, "INSTRPE", "Executed Prefetch Instructions" },
{ HWPERF_PRFCNT_PDCMISSPI, "1$DMPI", "Primary data cache misses by prefetch instructions" },
{ HWPERF_PRFCNT_GLD, "LOADG", "Graduated loads" },
{ HWPERF_PRFCNT_GST, "STOREG", "Graduated stores" },
{ HWPERF_PRFCNT_GSC, "SCONDG", "Graduated store conditionals" },
{ HWPERF_PRFCNT_GFINSTR, "FPG", "Graduated floating point instructions" },
{ HWPERF_PRFCNT_QWWPC, "WB1$", "Quadwords written back from primary data cache" },
{ HWPERF_PRFCNT_TLBMISS, "TLBMISS", "Translation lookaside buffer misses" },
{ HWPERF_PRFCNT_BRMISS, "BRMP", "Mispredicted branches" },
{ HWPERF_PRFCNT_PDCMISS, "1$DMISS", "Primary data cache misses" },
{ HWPERF_PRFCNT_SDCMISS, "2$DMISS", "Secondary data cache misses" },
{ HWPERF_PRFCNT_DMISPRED, "2$DWAYMP", "Data misprediction from scache way predication table" },
{ HWPERF_PRFCNT_EXTINTHIT, "INTHIT", "State of External intervention hits in scache" },
{ HWPERF_PRFCNT_EXTINVHIT, "INVHIT", "State of External invalidate hits in scache" },
{ HWPERF_PRFCNT_NHTAM, "NHTAM", "Miss Handling Table entries accessing memory" },
{ HWPERF_PRFCNT_SPEX, "2$SPEX", "Store/prefetch exclusive to block in secondary cache" }
};
EventDesc_t DescR10K_Rev2_Ev14 =
{ HWPERF_C0PRFCNT0_VCOH, "VCC", "Virtual coherency condition" };
EventDesc_t *EventDesc = DescR10K;
static hwperf_eventctrl_t evctr_set; /* counter control */
static hwperf_profevctrarg_t evctr_args_set; /* global counter control */
static hwperf_profevctrarg_t evctr_args_get; /* ditto */
static int gen; /* generation number */
static char *cmd; /* trimmed argv[0] */
static int trustme = 0;
cpucount_t cpucount;
int evctr_debug = 0;
int ActiveChanged;
int Active[HWPERF_EVENTMAX];
int Mux[HWPERF_EVENTMAX];
int Sem[HWPERF_EVENTMAX];
__uint64_t OldCount[HWPERF_EVENTMAX];
__uint64_t Count[HWPERF_EVENTMAX];
int Use[2]; /* mux count for each physical ctr */
static void
remap(hwperf_ctrl_t *cp)
{
int ctr;
/*
* try to remap if either counter is cycles(0,16) or
* graduated instructions(15,17)
* Warning ... this assumes we have only 2 physical registers, and is
* R10000-specific
*/
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
if (!cp[ctr].hwperf_spec)
continue;
if (ctr < HWPERF_CNT1BASE)
Use[0]++;
else
Use[1]++;
}
if (Use[0] > Use[1] + 1 && cp[0].hwperf_spec) {
cp[0].hwperf_spec = 0;
Use[0]--;
cp[16].hwperf_spec = 1;
Use[1]++;
}
if (Use[1] > Use[0] + 1 && cp[16].hwperf_spec) {
cp[16].hwperf_spec = 0;
Use[1]--;
cp[0].hwperf_spec = 1;
Use[0]++;
}
if (Use[0] > Use[1] + 1 && cp[15].hwperf_spec) {
cp[15].hwperf_spec = 0;
Use[0]--;
cp[17].hwperf_spec = 1;
Use[1]++;
}
if (Use[1] > Use[0] + 1 && cp[17].hwperf_spec) {
cp[17].hwperf_spec = 0;
Use[1]--;
cp[15].hwperf_spec = 1;
Use[0]++;
}
if (evctr_debug) {
fprintf(stderr, "After counter remap ...\n");
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++ ) {
if (!cp[ctr].hwperf_spec)
continue;
fprintf(stderr, "Enable [%2d] %s %s\n", ctr, EventDesc[ctr].name, EventDesc[ctr].text);
}
}
}
/*
* report control ...
* 0 no messages
* 1 messages to stderr
*/
static int
check_semantics(int ctr, int report)
{
int sts = EVCTR_SEM_OK;
if (cpucount.r10k_rev2 > 0 && cpucount.r10k_rev3 > 0) {
/* mixed rev R10Ks */
if (ctr == 14) { /* Virtual coherency condition */
if (report) {
fprintf(stderr, "%s: Warning: counter %d has conflicting meaning:\n", cmd, ctr);
fprintf(stderr, "\tR10000 Rev. 2: %s\n", DescR10K_Rev2_Ev14.text);
fprintf(stderr, "\tR10000 Rev. 3: %s\n", DescR10K[ctr].text);
}
if (!trustme) {
sts = EVCTR_SEM_BAD;
}
else {
sts = EVCTR_SEM_R10K_REV;
}
}
}
if (cpucount.r10k > 0 && cpucount.r12k > 0) {
if (ctr == 1 || /* Issued instructions */
ctr == 2 || /* Issued loads */
ctr == 3 || /* Issued stores */
ctr == 4 || /* Issued store conditionals */
ctr == 5 || /* Failed store conditionals */
ctr == 6 || /* Decoded branches */
( ctr == 14 && cpucount.r10k_rev3 == 0) || /* Virtual coherency conditon */
ctr == 16 || /* Cycles */
ctr == 17 || /* Graduated instructions */
ctr == 30 || /* Store/prefetch exclusive to clean block in secondary cache */
ctr == 31) { /* Store/prefetch exclusive to shared block in secondary cache */
if (report) {
fprintf(stderr, "%s: Warning: counter %d has conflicting meaning:\n", cmd, ctr);
fprintf(stderr, "\tR10000: %s\n", DescR10K[ctr].text);
fprintf(stderr, "\tR12000: %s\n", DescR12K[ctr].text);
}
if (!trustme) {
sts = EVCTR_SEM_BAD;
}
else if (sts == EVCTR_SEM_OK) {
sts = EVCTR_SEM_R10K_R12K;
}
}
}
return sts;
}
void
evctr_init(char *myname)
{
static char *buf;
static int buflen = 0;
static char *template="RXX000 x.x, xxx"; /* contains a few extra chars just in case */
char *p_type;
char *ver;
int need;
int i;
int ncpu;
cmd = strdup(basename(myname));
if (buflen == 0) {
/*
* enough for 32 processors, expand as required below
*/
buflen = 32 * strlen(template);
if ((buf = (char *)malloc(buflen)) == NULL) {
fprintf(stderr, "%s: Error: malloc(%d): %s\n",
cmd, buflen, strerror(errno));
exit(1);
}
}
if (sysinfo(_MIPS_SI_NUM_PROCESSORS, buf, buflen) < 0) {
fprintf(stderr, "%s: Error: sysinfo(_MIPS_SI_NUM_PROCESSORS, ...): %s\n",
cmd, strerror(errno));
exit(1);
}
ncpu = atoi(buf);
if (ncpu <= 0 || ncpu > 4096) {
/* not reasonable */
fprintf(stderr, "%s: Error: number of CPUs from sysinfo (%d) is not believable\n",
cmd, ncpu);
exit(1);
}
need = ncpu * strlen(template);
if (need > buflen) {
buflen = need;
if ((buf = (char *)realloc(buf, buflen)) == NULL) {
fprintf(stderr, "%s: Error: realloc(..., %d): %s\n",
cmd, buflen, strerror(errno));
exit(1);
}
}
if (sysinfo(_MIPS_SI_PROCESSORS, buf, buflen) < 0) {
fprintf(stderr, "%s: Error: sysinfo(_MIPS_SI_PROCESSORS, ...): %s\n",
cmd, strerror(errno));
exit(1);
}
for (i = 0; i < ncpu; i++) {
if (i == 0)
p_type = strtok(buf, " ,");
else
p_type = strtok(NULL, " ,");
if (p_type == NULL)
break;
ver = strtok(NULL, " ,");
if (evctr_debug)
fprintf(stderr, "CPU[%d]: %s Rev. %s\n", i, p_type, ver == NULL ? "?" : ver);
if (strcmp(p_type, "R10000") == 0) {
/* Hw counter change in R10K from rev 2.x to rev 3.x !!
*
**** 14 = Virtual coherency conditions
* In rev 2.x this counter is incremented on the cycle after a virtual
* address coherence condition is detected, provided that the
* access was not flagged as a miss. This condition can only be
* realized for virtual page sizes of 4KB.
*
**** 14 = Functional unit completion cycles
* In rev 3.x this counter's meaning is changed. It is incremented on
* the cycle after either ALU1, ALU2, FPU1, or FPU2 marks an
* instruction as "done."
****
*/
int major;
int minor;
cpucount.r10k++;
if (ver != NULL) {
if (sscanf(ver, "%d.%d", &major, &minor) == 2) {
if (major == 2) {
cpucount.r10k_rev2++;
continue;
}
else if (major == 3) {
cpucount.r10k_rev3++;
continue;
}
}
}
fprintf(stderr, "%s: Error: R10000 unknown Rev. %s\n",
cmd, ver == NULL ? "<NULL>" : ver);
exit(1);
}
else if (strcmp(p_type, "R12000") == 0) {
cpucount.r12k++;
}
else {
fprintf(stderr, "%s: Error: counters not supported on %s CPUs\n", cmd, buf);
exit(1);
}
}
if (cpucount.r10k_rev2 > 0 && cpucount.r10k_rev3 == 0) {
/* remap to R10000 rev 2 semantics */
if (evctr_debug) {
fprintf(stderr, "%s: Warning: using R10000 Rev. 2 interpretation for counter 14\n", cmd);
fprintf(stderr, "\tR10000 Rev. 2: %s\n", DescR10K_Rev2_Ev14.text);
}
DescR10K[14] = DescR10K_Rev2_Ev14;
}
if (cpucount.r10k == 0 && cpucount.r12k > 0)
/* pure R12000 system */
EventDesc = DescR12K;
}
void
evctr_opt(char *optarg, int enable)
{
int ctr;
char *op;
char *p;
if (strcmp(optarg, "?") == 0) {
fprintf(stderr, "Available counters ...\n");
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++ ) {
if (check_semantics(ctr, 0) == EVCTR_SEM_BAD)
continue;
fprintf(stderr, "[%2d] %-8s %s\n",
ctr, EventDesc[ctr].name, EventDesc[ctr].text);
}
exit(0);
}
if (strcmp(optarg, "*") == 0) {
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++ ) {
if (check_semantics(ctr, 0) == EVCTR_SEM_BAD)
continue;
if (cpucount.r12k == 0 && (ctr == 15 || ctr == 16))
continue;
evctr_set.hwp_evctrl[ctr].hwperf_spec = enable;
}
return;
}
/*
* process comma separated list of counter numbers and/or names
*/
for ( ; ; ) {
for (p = optarg; *p && *p != ','; p++)
;
if (*p == ',')
/* more */
*p++ = '\0';
else
p = (char *)0;
ctr = (int)strtol(optarg, &op, 10);
if (*op != '\0') {
/* not a number, try name */
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
if (strcasecmp(optarg, EventDesc[ctr].name) == 0)
break;
}
}
if (*optarg == '\0' || ctr < 0 || ctr >= HWPERF_EVENTMAX) {
fprintf(stderr, "%s: Error: illegal counter name or number (%s)\n",
cmd, optarg);
exit(1);
}
evctr_set.hwp_evctrl[ctr].hwperf_spec = enable;
if (p == (char *)0)
break;
optarg = p;
}
}
int
evctr_global_status(FILE *f)
{
int ctr;
if (syssgi(SGI_EVENTCTR, HWPERF_GET_SYSEVCTRL, &evctr_args_get) < 0) {
if (errno == EINVAL)
fprintf(stderr, "%s: Warning: global counters not enabled\n", cmd);
else
fprintf(stderr, "%s: Warning: cannot get config for global counters: %s\n",
cmd, strerror(errno));
return 0;
}
fprintf(f, "The following global counters are enabled:\n");
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
if (evctr_args_get.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec)
fprintf(f, "[%2d] %-8s %s\n",
ctr, EventDesc[ctr].name, EventDesc[ctr].text);
}
return 1;
}
int
evctr_global_release(void)
{
if ((gen = syssgi(SGI_EVENTCTR, HWPERF_RELSYSCNTRS)) < 0) {
if (errno == EINVAL)
fprintf(stderr, "%s: Warning: global counters already disabled\n", cmd);
else
fprintf(stderr, "%s: Warning: cannot release global counters: %s\n",
cmd, strerror(errno));
return 0;
}
return 1;
}
int
evctr_global_set(void)
{
int ctr;
int active;
int enable;
/* get current setup ... */
if ((gen = syssgi(SGI_EVENTCTR, HWPERF_GET_SYSEVCTRL, &evctr_args_set)) < 0) {
/*
* on error or if global ctrs inactive,
* assume everything is disabled
*/
active = 0;
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++)
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec = 0;
}
else {
active = 1;
/* mark active ones as "1" */
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++)
if (evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec)
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec = 1;
}
/* turn some explicitly on/off ... */
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
if (evctr_set.hwp_evctrl[ctr].hwperf_spec == 0)
continue;
if (evctr_set.hwp_evctrl[ctr].hwperf_spec == 1) {
/* turned on with -e */
if (check_semantics(ctr, 1) == EVCTR_SEM_BAD) {
fprintf(stderr, "... this counter will not be enabled\n");
evctr_set.hwp_evctrl[ctr].hwperf_spec = 0;
continue;
}
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec = 1;
}
if (evctr_set.hwp_evctrl[ctr].hwperf_spec == -1) {
/*
* turned off with -d
* ... a bit trickier as we have to manage the equivalences
* [0,16] and [15,17]
*/
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec = 0;
if (cpucount.r12k == 0) {
if (ctr == 0)
evctr_args_set.hwp_evctrargs.hwp_evctrl[16].hwperf_spec = 0;
else if (ctr == 16)
evctr_args_set.hwp_evctrargs.hwp_evctrl[0].hwperf_spec = 0;
else if (ctr == 15)
evctr_args_set.hwp_evctrargs.hwp_evctrl[17].hwperf_spec = 0;
else if (ctr == 17)
evctr_args_set.hwp_evctrargs.hwp_evctrl[15].hwperf_spec = 0;
}
}
}
if (cpucount.r12k == 0)
remap(evctr_args_set.hwp_evctrargs.hwp_evctrl);
/*
* set up the controls ...
* if enabled thru here, we want no overflow thresholds,
* no user signals, and all possible modes!
*/
enable = 0;
evctr_args_set.hwp_ovflw_sig = 0;
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++ ) {
evctr_args_set.hwp_ovflw_freq[ctr] = 0;
if (evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec == 1) {
enable++;
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_creg.hwp_mode =
HWPERF_CNTEN_U | HWPERF_CNTEN_K | HWPERF_CNTEN_E;
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_creg.hwp_ie = 1;
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_creg.hwp_ev =
ctr < HWPERF_CNT1BASE ? ctr : ctr - HWPERF_CNT1BASE;
}
else
evctr_args_set.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec = 0;
}
if (active) {
if (enable > 0) {
if ((gen = syssgi(SGI_EVENTCTR, HWPERF_SET_SYSEVCTRL, &evctr_args_set)) < 0) {
fprintf(stderr, "%s: Warning: cannot modify global counter state: %s\n",
cmd, strerror(errno));
return 0;
}
}
else
return evctr_global_release();
} else if (enable > 0) {
if ((gen = syssgi(SGI_EVENTCTR, HWPERF_ENSYSCNTRS, &evctr_args_set)) < 0) {
fprintf(stderr, "%s: Warning: cannot set global counters: %s\n",
cmd, strerror(errno));
return 0;
}
}
return 1;
}
#define S_INIT 0
#define S_ACTIVE 1
#define S_INACTIVE 2
static int state = S_INIT;
int
evctr_global_sample(int report)
{
int ctr;
int sts;
ActiveChanged = 0;
/* retrieve the counts */
if ((sts = syssgi(SGI_EVENTCTR, HWPERF_GET_SYSCNTRS, (void *)&Count)) < 0) {
if (state == S_INIT || state == S_ACTIVE) {
if (report) {
if (errno == EINVAL)
fprintf(stderr, "%s: Warning: global counters not enabled\n", cmd);
else
fprintf(stderr, "%s: Warning: cannot fetch global counters: %s\n",
cmd, strerror(errno));
}
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
Active[ctr] = 0;
Sem[ctr] = EVCTR_SEM_OK;
}
ActiveChanged = 1;
}
state = S_INACTIVE;
return 0;
}
if (state != S_ACTIVE || sts != gen) {
/*
* config changed, mark old results as invalid ...
* necessary because counters maybe re-set to zero
*/
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++)
OldCount[ctr] = -1;
state = S_ACTIVE; /* hope for the best */
/* get current setup ... */
if ((gen = syssgi(SGI_EVENTCTR, HWPERF_GET_SYSEVCTRL, &evctr_args_get)) < 0) {
if (report) {
if (errno == EINVAL)
fprintf(stderr, "%s: Warning: global counters not enabled\n", cmd);
else
fprintf(stderr, "%s: Warning: cannot get config for global counters: %s\n",
cmd, strerror(errno));
}
/* on error, assume everything is disabled */
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++)
evctr_args_get.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec = 0;
state = S_INACTIVE;
}
Use[0] = Use[1] = 0;
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
if (!evctr_args_get.hwp_evctrargs.hwp_evctrl[ctr].hwperf_spec) {
Active[ctr] = 0;
continue;
}
Sem[ctr] = check_semantics(ctr, report);
Active[ctr] = 1;
if (ctr < HWPERF_CNT1BASE)
Use[0]++;
else
Use[1]++;
}
for (ctr = 0; ctr < HWPERF_EVENTMAX; ctr++) {
if (Active[ctr]) {
if (ctr < HWPERF_CNT1BASE)
Mux[ctr] = Use[0];
else
Mux[ctr] = Use[1];
}
else
Mux[ctr] = 0;
}
ActiveChanged = 1;
if (state == S_INACTIVE)
return 0;
}
return 1;
}
void
evctr_trustme(void)
{
trustme = 1;
}