PAPI  5.3.0.0
papi_hl.c
Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines