#include "titanium.h" #include "needs!T11PAPICounter4lang2ti.c.h" #include "T11PAPICounter4lang2ti.h" #include "T11NativeUtils4lang2ti.h" #include "T5Class4lang4java.h" #include "layout!ti5cdescmT11PAPICounter4lang2ti.h" #include "java_string.h" #include #ifdef USE_PAPI #include #ifndef PAPI_VERSION /* PAPI 2 support goes here */ #ifndef PAPI_VERSION_NUMBER #define PAPI_VERSION_NUMBER(maj,min,rev) (((maj)<<16) | ((min)<<8) | (rev)) #endif #define PAPI_VERSION PAPI_VERSION_NUMBER(2,0,0) #ifndef PAPI_VERSION_MAJOR #define PAPI_VERSION_MAJOR(x) (((x)>>16) & 0xffff) #endif #ifndef PAPI_VERSION_MINOR #define PAPI_VERSION_MINOR(x) (((x)>>8) & 0xff) #endif #ifndef PAPI_VERSION_REVISION #define PAPI_VERSION_REVISION(x) ((x) & 0xff) #endif #define PAPI_EVENTSET_PARAM(pint) (pint) #define PAPI_remove_event PAPI_rem_event #define PAPI_remove_events PAPI_rem_events #elif (PAPI_VERSION_MAJOR(PAPI_VERSION) == 3) /* PAPI 3 support goes here */ #define PAPI_EVENTSET_PARAM(pint) (*(pint)) #else /* PAPI future support goes here */ #error Compiling against an untested PAPI version #endif extern int _ti_papi_eventmap[]; extern int _ti_papi_event_cnt; #define TI_PAPI_EVENT_BASE (0xF0000000) #define EVENT_TI2PAPI(event) ( \ assert((int)(juint)(event) >= TI_PAPI_EVENT_BASE), \ assert((int)(juint)(event) < TI_PAPI_EVENT_BASE+_ti_papi_event_cnt), \ _ti_papi_eventmap[(int)(juint)(event) & ~TI_PAPI_EVENT_BASE]) #define throwTooManyCounterException() \ m28throwTooManyCounterExceptionmT11PAPICounter4lang2ti() #define throwPAPIException(context, papierr) \ m18throwPAPIExceptionLT6String4lang4javaLT6String4lang4javamT11PAPICounter4lang2ti( \ java_string_build_8(context), java_string_build_8(papierr)) #define PAPI_SAFE(fn, okval, context, cleanup) do { \ int retval = (fn); \ if (retval != (okval)) { \ char *papierr = PAPI_strerror(retval); \ { cleanup; } \ if (retval == PAPI_ECNFLCT) throwTooManyCounterException(); \ else throwPAPIException(context, papierr); \ } \ } while(0) #ifndef TI_MAX_PAPI_EVENTS #define TI_MAX_PAPI_EVENTS 128 /* max simultaneously running events */ #endif #ifndef TI_MAX_PAPI_EVENTWIDTH #define TI_MAX_PAPI_EVENTWIDTH 4 /* max simultaneously running counters on the same event */ #endif typedef struct { int eventset; /* PAPI handle to event set */ int numevents; /* number of events in the PAPI event set */ jlong nextid; /* next unique counter id */ int event[TI_MAX_PAPI_EVENTS]; /* PAPI event codes for events in event set */ int numcounters[TI_MAX_PAPI_EVENTS]; /* number of overloaded counters on each event */ jlong counterid[TI_MAX_PAPI_EVENTWIDTH][TI_MAX_PAPI_EVENTS]; /* counter ids for each event */ long long accum[TI_MAX_PAPI_EVENTWIDTH][TI_MAX_PAPI_EVENTS]; /* accumulators for each counter */ } ti_papi_threadinfo_t; ti_papi_threadinfo_t *ti_papi_threadinfo[MAX_BOX_PROCS]; #endif static ti_lock_t TI_PAPI_lock = ti_lock_decl_initializer; static int threadInits = 0; /* ------------------------------------------------------------------------------------ */ jint m10PAPI_availmT11PAPICounter4lang2ti(){ #ifdef USE_PAPI return (jint) 1; #else return (jint) 0; #endif } jint m15PAPI_checkEventImT11PAPICounter4lang2ti(jint event){ #ifdef USE_PAPI int papievt = EVENT_TI2PAPI(event); if (!papievt) return 0; return PAPI_query_event(papievt) == PAPI_OK; #else return (jint) -1; #endif } /* ------------------------------------------------------------------------------------ */ void m9PAPI_initmT11PAPICounter4lang2ti(){ #ifdef USE_PAPI ti_lock(&TI_PAPI_lock); if (threadInits == 0) { /* PAPI per-box init */ PAPI_SAFE(PAPI_library_init(PAPI_VER_CURRENT), PAPI_VER_CURRENT, "PAPI library init", ti_unlock(&TI_PAPI_lock)); #ifdef HAVE_PAPI_MULTIPLEX_INIT /* DOB: older versions of PAPI lack this fn (eg. 1.1.5) */ PAPI_SAFE(PAPI_multiplex_init(), PAPI_OK, "PAPI multiplex init", ti_unlock(&TI_PAPI_lock)); #endif PAPI_SAFE(PAPI_set_debug(PAPI_VERB_ECONT), PAPI_OK, "PAPI set debug", ti_unlock(&TI_PAPI_lock)); #ifdef MEMORY_SHARED #if PAPI_VERSION_MAJOR(PAPI_VERSION) == 2 PAPI_SAFE(PAPI_thread_init((unsigned long (*)(void))(pthread_self), 0), PAPI_OK, "PAPI thread init", ti_unlock(&TI_PAPI_lock)); #else PAPI_SAFE(PAPI_thread_init((unsigned long (*)(void))(pthread_self)), PAPI_OK, "PAPI thread init", ti_unlock(&TI_PAPI_lock)); #endif #endif } { /* PAPI per-thread init */ ti_papi_threadinfo_t *info = ti_papi_threadinfo[MYBOXPROC]; if (info == NULL) { info = ti_malloc(sizeof(ti_papi_threadinfo_t)); info->numevents = 0; info->nextid = 0; info->eventset = PAPI_NULL; /* required init */ PAPI_SAFE(PAPI_create_eventset(&(info->eventset)), PAPI_OK, "PAPI create event set", ti_unlock(&TI_PAPI_lock)); #if USE_PAPI_MULTIPLEX /* currently disabled by default because it fails stability tests, at least on Power4 */ PAPI_SAFE(PAPI_set_multiplex(PAPI_EVENTSET_PARAM(&(info->eventset))), PAPI_OK, "PAPI PAPI_set_multiplex", ti_unlock(&TI_PAPI_lock)); #endif ti_papi_threadinfo[MYBOXPROC] = info; threadInits++; } } ti_unlock(&TI_PAPI_lock); #else abort(); /* should never reach here when PAPI is not available */ #endif } void m13PAPI_shutdownmT11PAPICounter4lang2ti(){ /* currently never called */ #ifdef USE_PAPI ti_papi_threadinfo_t *info = ti_papi_threadinfo[MYBOXPROC]; if (!info) return; /* this thread already shutdown */ if (info->numevents > 0) throwPAPIException("Internal error in PAPI_shutdown - counter is running", "N/A"); ti_lock(&TI_PAPI_lock); ti_papi_threadinfo[MYBOXPROC] = NULL; threadInits--; PAPI_SAFE(PAPI_cleanup_eventset(PAPI_EVENTSET_PARAM(&(info->eventset))), PAPI_OK, "PAPI clean up", ti_unlock(&TI_PAPI_lock)); PAPI_SAFE(PAPI_destroy_eventset(&(info->eventset)), PAPI_OK, "PAPI destroy event set", ti_unlock(&TI_PAPI_lock)); if (threadInits == 0) PAPI_shutdown(); /* no err return */ ti_unlock(&TI_PAPI_lock); #else abort(); /* should never reach here when PAPI is not available */ #endif } /* ------------------------------------------------------------------------------------ */ jlong m10PAPI_startImT11PAPICounter4lang2ti(jint event){ jlong mycounterid = -1; #ifdef USE_PAPI int papievent = EVENT_TI2PAPI(event); int myeventidx = -1; ti_papi_threadinfo_t *info = ti_papi_threadinfo[MYBOXPROC]; assert(info); assert(PAPI_query_event(papievent) == PAPI_OK); /* should have been caught in constructor */ if (info->numevents > 0) { long long stopval[TI_MAX_PAPI_EVENTS]; int i,j; for (i=0; i < info->numevents; i++) { if (papievent == info->event[i]) { myeventidx = i; if (info->numcounters[i] >= TI_MAX_PAPI_EVENTWIDTH) /* too many of same event */ throwTooManyCounterException(); break; } } if (myeventidx == -1 && info->numevents >= TI_MAX_PAPI_EVENTS) throwTooManyCounterException(); PAPI_SAFE(PAPI_stop(info->eventset, stopval), PAPI_OK, "PAPI stop before adding event", {}); PAPI_SAFE(PAPI_accum(info->eventset, info->accum[0]), PAPI_OK, "PAPI accum before adding event", {}); /* update overloaded counters */ for (i=0; i < info->numevents; i++) { for (j=1; j < info->numcounters[i]; j++) { info->accum[j][i] += stopval[i]; } } } mycounterid = info->nextid; info->nextid++; if (myeventidx >= 0) { /* adding a counter overload */ int mypos = info->numcounters[myeventidx]; assert(mypos > 0); assert(info->numcounters[myeventidx] < TI_MAX_PAPI_EVENTWIDTH); info->numcounters[myeventidx]++; info->counterid[mypos][myeventidx] = mycounterid; info->accum[mypos][myeventidx] = 0; } else { /* This code *assumes* PAPI is adding new events to the END of the event set (and compacting the list as they are removed), which does not appear to be documented, but seems to be true based on source-code inspection (and it's difficult to imagine how else the eventset interface could work and still provide sane results to the user) */ PAPI_SAFE(PAPI_add_event(PAPI_EVENTSET_PARAM(&(info->eventset)), papievent), PAPI_OK, "PAPI add event", { /* may get a PAPI conflict failure here */ if (info->numevents > 0) PAPI_SAFE(PAPI_start(info->eventset), PAPI_OK, "PAPI start after recovering from failed add event", {}); }); myeventidx = info->numevents; info->numevents++; info->event[myeventidx] = papievent; /* assign a new event */ info->counterid[0][myeventidx] = mycounterid; info->accum[0][myeventidx] = 0; info->numcounters[myeventidx] = 1; } PAPI_SAFE(PAPI_start(info->eventset), PAPI_OK, "PAPI start after adding event", {}); #else abort(); /* should never reach here when PAPI is not available */ #endif return mycounterid; } jlong m9PAPI_stopIJmT11PAPICounter4lang2ti(jint event, jlong counterid) { #ifdef USE_PAPI int papievent = EVENT_TI2PAPI(event); ti_papi_threadinfo_t *info = ti_papi_threadinfo[MYBOXPROC]; long long myvalue; int myeventidx = -1; int mypos = -1; int i,j; assert(info->numevents > 0); { long long stopval[TI_MAX_PAPI_EVENTS]; PAPI_SAFE(PAPI_stop(info->eventset, stopval), PAPI_OK, "PAPI stop", {}); PAPI_SAFE(PAPI_accum(info->eventset, info->accum[0]), PAPI_OK, "PAPI accum in PAPI stop", {}); /* update overloaded counters */ for (i=0; i < info->numevents; i++) { assert(info->numcounters[i] > 0 && info->numcounters[i] <= TI_MAX_PAPI_EVENTWIDTH); for (j=1; j < info->numcounters[i]; j++) { info->accum[j][i] += stopval[i]; } if (papievent == info->event[i]) myeventidx = i; } if (myeventidx == -1) throwPAPIException("Internal error in PAPI_stop - counter not running", "N/A"); } for (j=0; j < info->numcounters[myeventidx]; j++) { if (counterid == info->counterid[j][myeventidx]) { myvalue = info->accum[j][myeventidx]; mypos = j; break; } } if (info->numcounters[myeventidx] == 1) { /* removing last overload */ assert(mypos == 0); PAPI_SAFE(PAPI_remove_event(PAPI_EVENTSET_PARAM(&(info->eventset)), papievent), PAPI_OK, "PAPI remove event", { /* should never fail here... */ PAPI_SAFE(PAPI_start(info->eventset), PAPI_OK, "PAPI start after recovering from failed remove event", {}); }); { /* remove succeeded, now compact our metadata to match */ int i; for (i=myeventidx; i < info->numevents-1; i++) { info->event[i] = info->event[i+1]; info->numcounters[i] = info->numcounters[i+1]; for (j=0; j < info->numcounters[i]; j++) { info->accum[j][i] = info->accum[j][i+1]; info->counterid[j][i] = info->counterid[j][i+1]; } } info->numevents--; } } else { /* removing an overload */ assert(mypos != -1); /* compact overloads */ for (j=mypos; j < info->numcounters[myeventidx]-1; j++) { info->accum[j][myeventidx] = info->accum[j+1][myeventidx]; info->counterid[j][myeventidx] = info->counterid[j+1][myeventidx]; } info->numcounters[myeventidx]--; } if (info->numevents > 0) PAPI_SAFE(PAPI_start(info->eventset), PAPI_OK, "PAPI start after removing counter", {}); return (jlong) myvalue; #else abort(); /* should never reach here when PAPI is not available */ return -1; #endif } /* ------------------------------------------------------------------------------------ */ #ifdef USE_PAPI int _ti_papi_eventmap[] = { PAPI_L1_DCM, PAPI_L1_ICM, PAPI_L2_DCM, PAPI_L2_ICM, PAPI_L3_DCM, PAPI_L3_ICM, PAPI_L1_TCM, PAPI_L2_TCM, PAPI_L3_TCM, PAPI_CA_SNP, PAPI_CA_SHR, PAPI_CA_CLN, PAPI_CA_INV, PAPI_CA_ITV, PAPI_L3_LDM, PAPI_L3_STM, PAPI_BRU_IDL, PAPI_FXU_IDL, PAPI_FPU_IDL, PAPI_LSU_IDL, PAPI_TLB_DM, PAPI_TLB_IM, PAPI_TLB_TL, PAPI_L1_LDM, PAPI_L1_STM, PAPI_L2_LDM, PAPI_L2_STM, PAPI_BTAC_M, PAPI_PRF_DM, PAPI_L3_DCH, PAPI_TLB_SD, PAPI_CSR_FAL, PAPI_CSR_SUC, PAPI_CSR_TOT, PAPI_MEM_SCY, PAPI_MEM_RCY, PAPI_MEM_WCY, PAPI_STL_ICY, PAPI_FUL_ICY, PAPI_STL_CCY, PAPI_FUL_CCY, PAPI_HW_INT, PAPI_BR_UCN, PAPI_BR_CN, PAPI_BR_TKN, PAPI_BR_NTK, PAPI_BR_MSP, PAPI_BR_PRC, PAPI_FMA_INS, PAPI_TOT_IIS, PAPI_TOT_INS, PAPI_INT_INS, PAPI_FP_INS, PAPI_LD_INS, PAPI_SR_INS, PAPI_BR_INS, PAPI_VEC_INS, PAPI_RES_STL, PAPI_FP_STAL, PAPI_TOT_CYC, PAPI_LST_INS, PAPI_SYC_INS, PAPI_L1_DCH, PAPI_L2_DCH, PAPI_L1_DCA, PAPI_L2_DCA, PAPI_L3_DCA, PAPI_L1_DCR, PAPI_L2_DCR, PAPI_L3_DCR, PAPI_L1_DCW, PAPI_L2_DCW, PAPI_L3_DCW, PAPI_L1_ICH, PAPI_L2_ICH, PAPI_L3_ICH, PAPI_L1_ICA, PAPI_L2_ICA, PAPI_L3_ICA, PAPI_L1_ICR, PAPI_L2_ICR, PAPI_L3_ICR, PAPI_L1_ICW, PAPI_L2_ICW, PAPI_L3_ICW, PAPI_L1_TCH, PAPI_L2_TCH, PAPI_L3_TCH, PAPI_L1_TCA, PAPI_L2_TCA, PAPI_L3_TCA, PAPI_L1_TCR, PAPI_L2_TCR, PAPI_L3_TCR, PAPI_L1_TCW, PAPI_L2_TCW, PAPI_L3_TCW, PAPI_FML_INS, PAPI_FAD_INS, PAPI_FDV_INS, PAPI_FSQ_INS, PAPI_FNV_INS, #if (PAPI_VERSION_MAJOR(PAPI_VERSION) >= 3) PAPI_FP_OPS #else 0 #endif /* PAPI_IPS, -- removed in 2.745 */ /* PAPI_FLOPS, -- removed in 2.745 */ }; int _ti_papi_event_cnt = sizeof(_ti_papi_eventmap)/sizeof(int); #endif