|
PAPI
5.3.0.0
|
00001 /****************************/ 00002 /* THIS IS OPEN SOURCE CODE */ 00003 /****************************/ 00004 00016 #include "papi.h" 00017 #include "papi_internal.h" 00018 #include "papi_memory.h" 00019 #include <string.h> 00020 00021 /* high level papi functions*/ 00022 00023 /* 00024 * Which high-level interface are we using? 00025 */ 00026 #define HL_STOP 0 00027 #define HL_START 1 00028 #define HL_FLIP 2 00029 #define HL_FLOP 3 00030 #define HL_IPC 4 00031 #define HL_EPC 5 00032 #define HL_READ 6 00033 #define HL_ACCUM 7 00034 00038 typedef struct _HighLevelInfo 00039 { 00040 int EventSet; 00041 short int num_evts; 00042 short int running; 00043 long long initial_real_time; 00044 long long initial_proc_time; 00045 long long last_real_time; 00046 long long last_proc_time; 00047 long long total_ins; 00048 } HighLevelInfo; 00049 00050 int _hl_rate_calls( float *real_time, float *proc_time, int *events, 00051 long long *values, long long *ins, float *rate, int mode ); 00052 void _internal_cleanup_hl_info( HighLevelInfo * state ); 00053 int _internal_check_state( HighLevelInfo ** state ); 00054 int _internal_start_hl_counters( HighLevelInfo * state ); 00055 int _internal_hl_read_cnts( long long *values, int array_len, int flag ); 00056 00057 /* CHANGE LOG: 00058 - ksl 10/17/03 00059 Pretty much a complete rewrite of the high level interface. Now 00060 the interface is thread safe and you don't have to worry as much 00061 about mixing the various high level calls. 00062 00063 - dkt 11/19/01: 00064 After much discussion with users and developers, removed FMA and SLOPE 00065 fudge factors. SLOPE was not being used, and we decided the place to 00066 apply FMA was at a higher level where there could be a better understanding 00067 of platform discrepancies and code implications. 00068 ALL PAPI CALLS NOW RETURN EXACTLY WHAT THE HARDWARE REPORTS 00069 - dkt 08/14/01: 00070 Added reinitialization of values and proc_time to new reinit code. 00071 Added SLOPE and FMA constants to correct for systemic errors on a 00072 platform-by-platform basis. 00073 SLOPE is a factor subtracted from flpins on each call to compensate 00074 for platform overhead in the call. 00075 FMA is a shifter that doubles floating point counts on platforms that 00076 count FMA as one op instead of two. 00077 NOTE: We are making the FLAWED assumption that ALL flpins are FMA! 00078 This will result in counts that are TOO HIGH on the affected platforms 00079 in instances where the code is NOT mostly FMA. 00080 - dkt 08/01/01: 00081 NOTE: Calling semantics have changed! 00082 Now, if flpins < 0 (an invalid value) a PAPI_reset is issued to reset the 00083 counter values. The internal start time is also reset. This should be a 00084 benign change, exept in the rare case where a user passes an uninitialized 00085 (and possibly negative) value for flpins to the routine *AFTER* it has been 00086 called the first time. This is unlikely, since the first call clears and 00087 returns th is value. 00088 - dkt 08/01/01: 00089 Internal sequencing changes: 00090 -- initial PAPI_get_real_usec() call moved above PAPI_start to avoid unwanted flops. 00091 -- PAPI_accum() replaced with PAPI_start() / PAPI_stop pair for same reason. 00092 */ 00093 00099 int 00100 _internal_check_state( HighLevelInfo ** outgoing ) 00101 { 00102 int retval; 00103 HighLevelInfo *state = NULL; 00104 00105 /* Only allow one thread at a time in here */ 00106 if ( init_level == PAPI_NOT_INITED ) { 00107 retval = PAPI_library_init( PAPI_VER_CURRENT ); 00108 if ( retval != PAPI_VER_CURRENT ) { 00109 return ( retval ); 00110 } else { 00111 _papi_hwi_lock( HIGHLEVEL_LOCK ); 00112 init_level = PAPI_HIGH_LEVEL_INITED; 00113 _papi_hwi_unlock( HIGHLEVEL_LOCK ); 00114 } 00115 } 00116 00117 /* 00118 * Do we have the thread specific data setup yet? 00119 */ 00120 if ( ( retval = 00121 PAPI_get_thr_specific( PAPI_HIGH_LEVEL_TLS, ( void * ) &state ) ) 00122 != PAPI_OK || state == NULL ) { 00123 state = ( HighLevelInfo * ) papi_malloc( sizeof ( HighLevelInfo ) ); 00124 if ( state == NULL ) 00125 return ( PAPI_ENOMEM ); 00126 00127 memset( state, 0, sizeof ( HighLevelInfo ) ); 00128 state->EventSet = -1; 00129 00130 if ( ( retval = PAPI_create_eventset( &state->EventSet ) ) != PAPI_OK ) 00131 return ( retval ); 00132 00133 if ( ( retval = 00134 PAPI_set_thr_specific( PAPI_HIGH_LEVEL_TLS, 00135 state ) ) != PAPI_OK ) 00136 return ( retval ); 00137 } 00138 *outgoing = state; 00139 return ( PAPI_OK ); 00140 } 00141 00145 int 00146 _internal_start_hl_counters( HighLevelInfo * state ) 00147 { 00148 return ( PAPI_start( state->EventSet ) ); 00149 } 00150 00151 void 00152 _internal_cleanup_hl_info( HighLevelInfo * state ) 00153 { 00154 state->num_evts = 0; 00155 state->running = HL_STOP; 00156 state->initial_real_time = -1; 00157 state->initial_proc_time = -1; 00158 state->total_ins = 0; 00159 return; 00160 } 00161 00203 int 00204 PAPI_flips( float *rtime, float *ptime, long long *flpins, float *mflips ) 00205 { 00206 int retval; 00207 int events = PAPI_FP_INS; 00208 long long values = 0; 00209 00210 if ( rtime == NULL || ptime == NULL || flpins == NULL || mflips == NULL ) 00211 return PAPI_EINVAL; 00212 00213 retval = _hl_rate_calls( rtime, ptime, &events, &values, flpins, mflips, HL_FLIP ); 00214 return ( retval ); 00215 } 00216 00258 int 00259 PAPI_flops( float *rtime, float *ptime, long long *flpops, float *mflops ) 00260 { 00261 int retval; 00262 int events = PAPI_FP_OPS; 00263 long long values = 0; 00264 00265 if ( rtime == NULL || ptime == NULL || flpops == NULL || mflops == NULL ) 00266 return PAPI_EINVAL; 00267 00268 retval = _hl_rate_calls( rtime, ptime, &events, &values, flpops, mflops, HL_FLOP ); 00269 return ( retval ); 00270 } 00271 00315 int 00316 PAPI_ipc( float *rtime, float *ptime, long long *ins, float *ipc ) 00317 { 00318 long long values[2] = { 0, 0 }; 00319 int events[2] = {PAPI_TOT_INS, PAPI_TOT_CYC}; 00320 int retval = 0; 00321 00322 if ( rtime == NULL || ptime == NULL || ins == NULL || ipc == NULL ) 00323 return PAPI_EINVAL; 00324 00325 retval = _hl_rate_calls( rtime, ptime, events, values, ins, ipc, HL_IPC ); 00326 return ( retval ); 00327 } 00328 00382 int 00383 PAPI_epc( int event, float *rtime, float *ptime, long long *ref, long long *core, long long *evt, float *epc ) 00384 { 00385 long long values[3] = { 0, 0, 0 }; 00386 int events[3] = {PAPI_TOT_INS, PAPI_TOT_CYC, PAPI_REF_CYC}; 00387 int retval = 0; 00388 00389 if ( rtime == NULL || ptime == NULL || ref == NULL ||core == NULL || evt == NULL || epc == NULL ) 00390 return PAPI_EINVAL; 00391 00392 // if an event is provided, use it; otherwise use TOT_INS 00393 if (event != 0 ) events[0] = event; 00394 00395 if ( PAPI_query_event( ( int ) PAPI_REF_CYC ) != PAPI_OK ) 00396 events[2] = 0; 00397 00398 retval = _hl_rate_calls( rtime, ptime, events, values, evt, epc, HL_EPC ); 00399 *core = values[1]; 00400 *ref = values[2]; 00401 return ( retval ); 00402 } 00403 00404 int 00405 _hl_rate_calls( float *real_time, float *proc_time, int *events, 00406 long long *values, long long *ins, float *rate, int mode ) 00407 { 00408 long long rt, pt; // current elapsed real and process times in usec 00409 int num_events = 2; 00410 int retval = 0; 00411 HighLevelInfo *state = NULL; 00412 00413 if ( ( retval = _internal_check_state( &state ) ) != PAPI_OK ) { 00414 return ( retval ); 00415 } 00416 00417 if ( state->running != HL_STOP && state->running != mode ) { 00418 return PAPI_EINVAL; 00419 } 00420 00421 if ( state->running == HL_STOP ) { 00422 00423 switch (mode) { 00424 case HL_FLOP: 00425 case HL_FLIP: 00426 num_events = 1; 00427 break; 00428 case HL_IPC: 00429 break; 00430 case HL_EPC: 00431 if ( events[2] != 0 ) num_events = 3; 00432 break; 00433 default: 00434 return PAPI_EINVAL; 00435 } 00436 if (( retval = PAPI_add_events( state->EventSet, events, num_events )) != PAPI_OK ) { 00437 _internal_cleanup_hl_info( state ); 00438 PAPI_cleanup_eventset( state->EventSet ); 00439 return retval; 00440 } 00441 00442 state->total_ins = 0; 00443 state->initial_real_time = state->last_real_time = PAPI_get_real_usec( ); 00444 state->initial_proc_time = state->last_proc_time = PAPI_get_virt_usec( ); 00445 00446 if ( ( retval = PAPI_start( state->EventSet ) ) != PAPI_OK ) { 00447 return retval; 00448 } 00449 00450 /* Initialize the interface */ 00451 state->running = mode; 00452 *real_time = 0.0; 00453 *proc_time = 0.0; 00454 *rate = 0.0; 00455 00456 } else { 00457 if ( ( retval = PAPI_stop( state->EventSet, values ) ) != PAPI_OK ) { 00458 state->running = HL_STOP; 00459 return retval; 00460 } 00461 00462 /* Read elapsed real and process times */ 00463 rt = PAPI_get_real_usec(); 00464 pt = PAPI_get_virt_usec(); 00465 00466 /* Convert to seconds with multiplication because it is much faster */ 00467 *real_time = ((float)( rt - state->initial_real_time )) * .000001; 00468 *proc_time = ((float)( pt - state->initial_proc_time )) * .000001; 00469 00470 state->total_ins += values[0]; 00471 00472 switch (mode) { 00473 case HL_FLOP: 00474 case HL_FLIP: 00475 /* Calculate MFLOP and MFLIP rates */ 00476 if ( pt > 0 ) { 00477 *rate = (float)values[0] / (pt - state->last_proc_time); 00478 } else *rate = 0; 00479 break; 00480 case HL_IPC: 00481 case HL_EPC: 00482 /* Calculate IPC */ 00483 if (values[1]!=0) { 00484 *rate = (float) ((float)values[0] / (float) ( values[1])); 00485 } 00486 break; 00487 default: 00488 return PAPI_EINVAL; 00489 } 00490 state->last_real_time = rt; 00491 state->last_proc_time = pt; 00492 00493 if ( ( retval = PAPI_start( state->EventSet ) ) != PAPI_OK ) { 00494 state->running = HL_STOP; 00495 return retval; 00496 } 00497 } 00498 *ins = state->total_ins; 00499 return PAPI_OK; 00500 } 00501 00536 int 00537 PAPI_num_counters( void ) 00538 { 00539 int retval; 00540 HighLevelInfo *tmp = NULL; 00541 00542 /* Make sure the Library is initialized, etc... */ 00543 if ( ( retval = _internal_check_state( &tmp ) ) != PAPI_OK ) 00544 return ( retval ); 00545 00546 return ( PAPI_get_opt( PAPI_MAX_HWCTRS, NULL ) ); 00547 } 00548 00592 int 00593 PAPI_start_counters( int *events, int array_len ) 00594 { 00595 int i, retval; 00596 HighLevelInfo *state = NULL; 00597 00598 if ( events == NULL || array_len <= 0 ) 00599 return PAPI_EINVAL; 00600 00601 if ( ( retval = _internal_check_state( &state ) ) != PAPI_OK ) 00602 return ( retval ); 00603 00604 if ( state->running != 0 ) 00605 return ( PAPI_EINVAL ); 00606 00607 /* load events to the new EventSet */ 00608 for ( i = 0; i < array_len; i++ ) { 00609 retval = PAPI_add_event( state->EventSet, events[i] ); 00610 if ( retval == PAPI_EISRUN ) 00611 return ( retval ); 00612 00613 if ( retval ) { 00614 /* remove any prior events that may have been added 00615 * and cleanup the high level information 00616 */ 00617 _internal_cleanup_hl_info( state ); 00618 PAPI_cleanup_eventset( state->EventSet ); 00619 return ( retval ); 00620 } 00621 } 00622 /* start the EventSet */ 00623 if ( ( retval = _internal_start_hl_counters( state ) ) == PAPI_OK ) { 00624 state->running = HL_START; 00625 state->num_evts = ( short ) array_len; 00626 } 00627 return ( retval ); 00628 } 00629 00630 /*========================================================================*/ 00631 /* int PAPI_read_counters(long long *values, int array_len) */ 00632 /* */ 00633 /* Read the running counters into the values array. This call */ 00634 /* implicitly initializes the internal counters to zero and allows */ 00635 /* them continue to run upon return. */ 00636 /*========================================================================*/ 00637 00638 int 00639 _internal_hl_read_cnts( long long *values, int array_len, int flag ) 00640 { 00641 int retval; 00642 HighLevelInfo *state = NULL; 00643 00644 if ( ( retval = _internal_check_state( &state ) ) != PAPI_OK ) 00645 return ( retval ); 00646 00647 if ( state->running != HL_START || array_len < state->num_evts ) 00648 return ( PAPI_EINVAL ); 00649 00650 if ( flag == HL_ACCUM ) 00651 return ( PAPI_accum( state->EventSet, values ) ); 00652 else if ( flag == HL_READ ) { 00653 if ( ( retval = PAPI_read( state->EventSet, values ) ) != PAPI_OK ) 00654 return ( retval ); 00655 return ( PAPI_reset( state->EventSet ) ); 00656 } 00657 00658 /* Invalid flag passed in */ 00659 return ( PAPI_EINVAL ); 00660 } 00661 00705 int 00706 PAPI_read_counters( long long *values, int array_len ) 00707 { 00708 return ( _internal_hl_read_cnts( values, array_len, HL_READ ) ); 00709 } 00710 00711 00755 int 00756 PAPI_accum_counters( long long *values, int array_len ) 00757 { 00758 if ( values == NULL || array_len <= 0 ) 00759 return PAPI_EINVAL; 00760 00761 return ( _internal_hl_read_cnts( values, array_len, HL_ACCUM ) ); 00762 } 00763 00802 int 00803 PAPI_stop_counters( long long *values, int array_len ) 00804 { 00805 int retval; 00806 HighLevelInfo *state = NULL; 00807 00808 if ( ( retval = _internal_check_state( &state ) ) != PAPI_OK ) 00809 return ( retval ); 00810 00811 if ( state->running == 0 ) 00812 return ( PAPI_ENOTRUN ); 00813 00814 if ( state->running == HL_START ) { 00815 if ( array_len < state->num_evts || values == NULL) { 00816 return ( PAPI_EINVAL ); 00817 } else { 00818 retval = PAPI_stop( state->EventSet, values ); 00819 } 00820 } 00821 00822 if ( state->running > HL_START ) { 00823 long long tmp_values[3]; 00824 retval = PAPI_stop( state->EventSet, tmp_values ); 00825 } 00826 00827 if ( retval == PAPI_OK ) { 00828 _internal_cleanup_hl_info( state ); 00829 PAPI_cleanup_eventset( state->EventSet ); 00830 } 00831 APIDBG( "PAPI_stop_counters returns %d\n", retval ); 00832 return retval; 00833 } 00834 00835 void 00836 _papi_hwi_shutdown_highlevel( ) 00837 { 00838 HighLevelInfo *state = NULL; 00839 00840 if ( PAPI_get_thr_specific( PAPI_HIGH_LEVEL_TLS, ( void * ) &state ) == 00841 PAPI_OK ) { 00842 if ( state ) 00843 papi_free( state ); 00844 } 00845 }