sw_multiplex.h File Reference

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MPX_EventSet
struct  EventSetMultiplexInfo_t

Defines

#define PAPI_MAX_SW_MPX_EVENTS   32

Enumerations

enum  MPX_status { MPX_STOPPED, MPX_RUNNING }

Functions

int mpx_check (int EventSet)
int mpx_init (int)
int mpx_add_event (MPX_EventSet **, int EventCode, int domain, int granularity)
int mpx_remove_event (MPX_EventSet **, int EventCode)
int MPX_add_events (MPX_EventSet **mpx_events, int *event_list, int num_events, int domain, int granularity)
int MPX_stop (MPX_EventSet *mpx_events, long long *values)
int MPX_cleanup (MPX_EventSet **mpx_events)
void MPX_shutdown (void)
int MPX_reset (MPX_EventSet *mpx_events)
int MPX_read (MPX_EventSet *mpx_events, long long *values, int called_by_stop)
int MPX_start (MPX_EventSet *mpx_events)

Define Documentation

#define PAPI_MAX_SW_MPX_EVENTS   32

Definition at line 4 of file sw_multiplex.h.


Enumeration Type Documentation

enum MPX_status
Enumerator:
MPX_STOPPED 
MPX_RUNNING 

Definition at line 9 of file sw_multiplex.h.


Function Documentation

int mpx_add_event ( MPX_EventSet **  ,
int  EventCode,
int  domain,
int  granularity 
)

Definition at line 305 of file sw_multiplex.c.

00307 {
00308     MPX_EventSet *newset = *mpx_events;
00309     int retval, alloced_newset = 0;
00310     Threadlist *t;
00311 
00312     /* Get the global list of threads */
00313 
00314     MPXDBG("Adding %p %#x\n",newset,EventCode);
00315 
00316     _papi_hwi_lock( MULTIPLEX_LOCK );
00317     t = tlist;
00318 
00319     /* If there are no threads in the list at all, then allocate the new Threadlist */
00320 
00321     if ( t == NULL ) {
00322       new_thread:
00323         t = ( Threadlist * ) papi_malloc( sizeof ( Threadlist ) );
00324         if ( t == NULL ) {
00325             _papi_hwi_unlock( MULTIPLEX_LOCK );
00326             return ( PAPI_ENOMEM );
00327         }
00328 
00329         /* If we're actually threaded, fill the 
00330          * field with the thread_id otherwise
00331          * use getpid() as a placeholder. */
00332 
00333         if ( _papi_hwi_thread_id_fn ) {
00334             MPXDBG( "New thread at %p\n", t );
00335             t->tid = _papi_hwi_thread_id_fn(  );
00336         } else {
00337             MPXDBG( "New process at %p\n", t );
00338             t->tid = ( unsigned long ) getpid(  );
00339         }
00340 
00341         /* Fill in the fields */
00342 
00343         t->head = NULL;
00344         t->cur_event = NULL;
00345         t->next = tlist;
00346         tlist = t;
00347         MPXDBG( "New head is at %p(%lu).\n", tlist,
00348                 ( long unsigned ) tlist->tid );
00349         /* alloced_thread = 1; */
00350     } else if ( _papi_hwi_thread_id_fn ) {
00351 
00352         /* If we are threaded, AND there exists threads in the list, 
00353          *  then try to find our thread in the list. */
00354 
00355         unsigned long tid = _papi_hwi_thread_id_fn(  );
00356 
00357         while ( t ) {
00358             if ( t->tid == tid ) {
00359                 MPXDBG( "Found thread %#lx\n", t->tid );
00360                 break;
00361             }
00362             t = t->next;
00363         }
00364 
00365         /* Our thread is not in the list, so make a new
00366          * thread entry. */
00367 
00368         if ( t == NULL ) {
00369             MPXDBG( "New thread %lx\n", tid );
00370             goto new_thread;
00371         }
00372     }
00373 
00374     /* Now t & tlist points to our thread, also at the head of the list */
00375 
00376     /* Allocate a the MPX_EventSet if necessary */
00377 
00378     if ( newset == NULL ) {
00379         newset = mpx_malloc( t );
00380         if ( newset == NULL ) {
00381             _papi_hwi_unlock( MULTIPLEX_LOCK );
00382             return ( PAPI_ENOMEM );
00383         }
00384         alloced_newset = 1;
00385     }
00386 
00387     /* Now we're finished playing with the thread list */
00388 
00389     _papi_hwi_unlock( MULTIPLEX_LOCK );
00390 
00391     /* Removed newset->num_events++, moved to mpx_insert_events() */
00392 
00393     mpx_hold(  );
00394 
00395     /* Create PAPI events (if they don't already exist) and link
00396      * the new event set to them, add them to the master list for
00397      the thread, reset master event list for this thread */
00398 
00399     retval = mpx_insert_events( newset, &EventCode, 1, 
00400                     domain, granularity );
00401     if ( retval != PAPI_OK ) {
00402         if ( alloced_newset ) {
00403             papi_free( newset );
00404             newset = NULL;
00405         }
00406     }
00407 
00408     mpx_release(  );
00409 
00410     /* Output the new or existing EventSet */
00411 
00412     *mpx_events = newset;
00413 
00414     return retval;
00415 }

Here is the call graph for this function:

Here is the caller graph for this function:

int MPX_add_events ( MPX_EventSet **  mpx_events,
int *  event_list,
int  num_events,
int  domain,
int  granularity 
)

Definition at line 676 of file sw_multiplex.c.

00678 {
00679     int i, retval = PAPI_OK;
00680 
00681     for ( i = 0; i < num_events; i++ ) {
00682         retval =
00683             mpx_add_event( mpx_events, event_list[i], domain, granularity );
00684 
00685         if ( retval != PAPI_OK )
00686             return ( retval );
00687     }
00688     return ( retval );
00689 }

Here is the call graph for this function:

Here is the caller graph for this function:

int mpx_check ( int  EventSet  ) 

Definition at line 1121 of file sw_multiplex.c.

01122 {
01123     /* Currently, there is only the need for one mpx check: if
01124      * running on POWER6/perfctr platform, the domain must
01125      * include user, kernel, and supervisor, since the scale
01126      * event uses the dedicated counter #6, PM_RUN_CYC, which
01127      * cannot be controlled on a domain level.
01128      */
01129     EventSetInfo_t *ESI = _papi_hwi_lookup_EventSet( EventSet );
01130 
01131     if (ESI==NULL) return PAPI_EBUG;
01132 
01133     if ( strstr( _papi_hwd[ESI->CmpIdx]->cmp_info.name, "perfctr.c" ) == NULL )
01134         return PAPI_OK;
01135 
01136     if ( strcmp( _papi_hwi_system_info.hw_info.model_string, "POWER6" ) == 0 ) {
01137         unsigned int chk_domain =
01138             PAPI_DOM_USER + PAPI_DOM_KERNEL + PAPI_DOM_SUPERVISOR;
01139 
01140         if ( ( ESI->domain.domain & chk_domain ) != chk_domain ) {
01141             PAPIERROR
01142                 ( "This platform requires PAPI_DOM_USER+PAPI_DOM_KERNEL+PAPI_DOM_SUPERVISOR\n"
01143                   "to be set in the domain when using multiplexing.  Instead, found %#x\n",
01144                   ESI->domain.domain );
01145             return ( PAPI_EINVAL_DOM );
01146         }
01147     }
01148     return PAPI_OK;
01149 }

Here is the call graph for this function:

Here is the caller graph for this function:

int MPX_cleanup ( MPX_EventSet **  mpx_events  ) 

Definition at line 1069 of file sw_multiplex.c.

01070 {
01071 #ifdef PTHREADS
01072     int retval;
01073 #endif
01074 
01075     if ( mpx_events == NULL )
01076        return PAPI_EINVAL;
01077 
01078     if ( *mpx_events == NULL )
01079        return PAPI_OK;
01080 
01081     if (( *mpx_events )->status == MPX_RUNNING )
01082        return PAPI_EINVAL;
01083 
01084     mpx_hold(  );
01085 
01086     /* Remove master events from this event set and from
01087      * the master list, if necessary.
01088      */
01089     mpx_delete_events( *mpx_events );
01090 
01091     mpx_release(  );
01092 
01093     /* Free all the memory */
01094 
01095     papi_free( *mpx_events );
01096 
01097     *mpx_events = NULL;
01098     return PAPI_OK;
01099 }

Here is the call graph for this function:

Here is the caller graph for this function:

int mpx_init ( int   ) 

Definition at line 1152 of file sw_multiplex.c.

01153 {
01154 #if defined(PTHREADS) || defined(_POWER6)
01155     int retval;
01156 #endif
01157 
01158 #ifdef _POWER6
01159     retval = PAPI_event_name_to_code( "PM_RUN_CYC", &_PNE_PM_RUN_CYC );
01160     if ( retval != PAPI_OK )
01161         return ( retval );
01162 #endif
01163     tlist = NULL;
01164     mpx_hold(  );
01165     mpx_shutdown_itimer(  );
01166     mpx_init_timers( interval_ns / 1000 );
01167 
01168     return ( PAPI_OK );
01169 }

Here is the call graph for this function:

Here is the caller graph for this function:

int MPX_read ( MPX_EventSet mpx_events,
long long *  values,
int  called_by_stop 
)

Definition at line 823 of file sw_multiplex.c.

00824 {
00825     int i;
00826     int retval;
00827     long long last_value[2];
00828     long long cycles_this_slice = 0;
00829     MasterEvent *cur_event;
00830     Threadlist *thread_data;
00831 
00832     if ( mpx_events->status == MPX_RUNNING ) {
00833 
00834         /* Hold timer interrupts while we read values */
00835         mpx_hold(  );
00836 
00837         thread_data = mpx_events->mythr;
00838         cur_event = thread_data->cur_event;
00839 
00840         retval = PAPI_read( cur_event->papi_event, last_value );
00841         if ( retval != PAPI_OK )
00842             return retval;
00843 
00844         cycles_this_slice = ( cur_event->pi.event_type == SCALE_EVENT )
00845             ? last_value[0] : last_value[1];
00846 
00847         /* Save the current counter values and get
00848          * the lastest data for the current event
00849          */
00850         for ( i = 0; i < mpx_events->num_events; i++ ) {
00851             MasterEvent *mev = mpx_events->mev[i];
00852 
00853             if ( !( mev->is_a_rate ) ) {
00854                 mpx_events->stop_values[i] = mev->count_estimate;
00855             }
00856             else {
00857                 mpx_events->stop_values[i] = mev->count;
00858             }
00859 #ifdef MPX_NONDECR_HYBRID
00860             /* If we are called from MPX_stop() then      */
00861                         /* adjust the final values based on the       */
00862                         /* cycles elapsed since the last read         */
00863                         /* otherwise, don't do this as it can cause   */
00864                         /* decreasing values if read is called again  */
00865                         /* before another sample happens.             */
00866 
00867                         if (called_by_stop) {
00868 
00869                /* Extrapolate data up to the current time 
00870                 * only if it's not a rate measurement 
00871                 */
00872                if ( !( mev->is_a_rate ) ) {
00873                   if ( mev != thread_data->cur_event ) {
00874                  mpx_events->stop_values[i] +=
00875                         ( long long ) ( mev->rate_estimate *
00876                                         ( cycles_this_slice +
00877                                           thread_data->total_c -
00878                                           mev->prev_total_c ) );
00879                  MPXDBG
00880                         ( "%s:%d:: Inactive %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
00881                           __FILE__, __LINE__, i, mpx_events->stop_values[i],
00882                           mev->count_estimate, mev->rate_estimate,
00883                           cycles_this_slice + thread_data->total_c -
00884                           mev->prev_total_c );
00885                   } else {
00886                  mpx_events->stop_values[i] += last_value[0] +
00887                         ( long long ) ( mev->rate_estimate *
00888                                         ( thread_data->total_c -
00889                                           mev->prev_total_c ) );
00890                  MPXDBG
00891                         ( "%s:%d:: -Active- %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
00892                           __FILE__, __LINE__, i, mpx_events->stop_values[i],
00893                           mev->count_estimate, mev->rate_estimate,
00894                           thread_data->total_c - mev->prev_total_c );
00895                   }
00896                }
00897             }
00898 #endif
00899         }
00900 
00901         mpx_events->stop_c = thread_data->total_c + cycles_this_slice;
00902 
00903         /* Restore the interrupt */
00904         mpx_release(  );
00905     }
00906 
00907     /* Store the values in user array. */
00908     for ( i = 0; i < mpx_events->num_events; i++ ) {
00909         MasterEvent *mev = mpx_events->mev[i];
00910         long long elapsed_slices = 0;
00911         long long elapsed_values = mpx_events->stop_values[i]
00912             - mpx_events->start_values[i];
00913 
00914         /* For rates, cycles contains the number of measurements,
00915          * not the number of cycles, so just divide to compute
00916          * an average value.  This assumes that the rate was
00917          * constant over the whole measurement period.
00918          */
00919         values[i] = elapsed_values;
00920         if ( mev->is_a_rate ) {
00921             /* Handler counts */
00922             elapsed_slices = mev->cycles - mpx_events->start_hc[i];
00923             values[i] =
00924                 elapsed_slices ? ( elapsed_values / elapsed_slices ) : 0;
00925         }
00926         MPXDBG( "%s:%d:: event %d, values=%lld ( %lld - %lld), cycles %lld\n",
00927                 __FILE__, __LINE__, i,
00928                 elapsed_values,
00929                 mpx_events->stop_values[i], mpx_events->start_values[i],
00930                 mev->is_a_rate ? elapsed_slices : 0 );
00931     }
00932 
00933     return PAPI_OK;
00934 }

Here is the call graph for this function:

Here is the caller graph for this function:

int mpx_remove_event ( MPX_EventSet **  ,
int  EventCode 
)

Definition at line 418 of file sw_multiplex.c.

00419 {
00420     mpx_hold(  );
00421     if ( *mpx_events )
00422         mpx_delete_one_event( *mpx_events, EventCode );
00423     mpx_release(  );
00424     return ( PAPI_OK );
00425 }

Here is the call graph for this function:

Here is the caller graph for this function:

int MPX_reset ( MPX_EventSet mpx_events  ) 

Definition at line 937 of file sw_multiplex.c.

00938 {
00939     int i, retval;
00940     long long values[PAPI_MAX_SW_MPX_EVENTS];
00941 
00942     /* Get the current values from MPX_read */
00943     retval = MPX_read( mpx_events, values, 0 );
00944     if ( retval != PAPI_OK )
00945         return retval;
00946 
00947     /* Disable timer interrupt */
00948     mpx_hold(  );
00949 
00950     /* Make counters read zero by setting the start values
00951      * to the current counter values.
00952      */
00953     for ( i = 0; i < mpx_events->num_events; i++ ) {
00954         MasterEvent *mev = mpx_events->mev[i];
00955 
00956         if ( mev->is_a_rate ) {
00957             mpx_events->start_values[i] = mev->count;
00958         } else {
00959             mpx_events->start_values[i] += values[i];
00960         }
00961         mpx_events->start_hc[i] = mev->cycles;
00962     }
00963 
00964     /* Set the start time for this set to the current cycle count */
00965     mpx_events->start_c = mpx_events->stop_c;
00966 
00967     /* Restart the interrupt */
00968     mpx_release(  );
00969 
00970     return PAPI_OK;
00971 }

Here is the call graph for this function:

Here is the caller graph for this function:

void MPX_shutdown ( void   ) 

Definition at line 1102 of file sw_multiplex.c.

01103 {
01104     MPXDBG( "%d\n", getpid(  ) );
01105     mpx_shutdown_itimer(  );
01106     mpx_restore_signal(  );
01107 
01108     if ( tlist ) {
01109            Threadlist *next,*t=tlist;
01110 
01111         while(t!=NULL) {
01112            next=t->next;
01113            papi_free( t );
01114            t = next;            
01115         }
01116         tlist = NULL;
01117     }
01118 }

Here is the call graph for this function:

Here is the caller graph for this function:

int MPX_start ( MPX_EventSet mpx_events  ) 

Definition at line 692 of file sw_multiplex.c.

00693 {
00694     int retval = PAPI_OK;
00695     int i;
00696     long long values[2];
00697     long long cycles_this_slice, current_thread_mpx_c = 0;
00698     Threadlist *t;
00699 
00700     t = mpx_events->mythr;
00701 
00702     mpx_hold(  );
00703 
00704     if ( t->cur_event && t->cur_event->active ) {
00705         current_thread_mpx_c += t->total_c;
00706         retval = PAPI_read( t->cur_event->papi_event, values );
00707         assert( retval == PAPI_OK );
00708         if ( retval == PAPI_OK ) {
00709             cycles_this_slice = ( t->cur_event->pi.event_type == SCALE_EVENT )
00710                 ? values[0] : values[1];
00711         } else {
00712             values[0] = values[1] = 0;
00713             cycles_this_slice = 0;
00714         }
00715 
00716     } else {
00717         values[0] = values[1] = 0;
00718         cycles_this_slice = 0;
00719     }
00720 
00721     /* Make all events in this set active, and for those
00722      * already active, get the current count and cycles.
00723      */
00724     for ( i = 0; i < mpx_events->num_events; i++ ) {
00725         MasterEvent *mev = mpx_events->mev[i];
00726 
00727         if ( mev->active++ ) {
00728             mpx_events->start_values[i] = mev->count_estimate;
00729             mpx_events->start_hc[i] = mev->cycles;
00730 
00731             /* If this happens to be the currently-running
00732              * event, add in the current amounts from this
00733              * time slice.  If it's a rate, though, don't
00734              * bother since the event might not have been
00735              * running long enough to get an accurate count.
00736              */
00737             if ( t->cur_event && !( t->cur_event->is_a_rate ) ) {
00738 #ifdef MPX_NONDECR_HYBRID
00739                 if ( mev != t->cur_event ) {    /* This event is not running this slice */
00740                     mpx_events->start_values[i] +=
00741                         ( long long ) ( mev->rate_estimate *
00742                                         ( cycles_this_slice + t->total_c -
00743                                           mev->prev_total_c ) );
00744                 } else {     /* The event is running, use current value + estimate */
00745                     if ( cycles_this_slice >= MPX_MINCYC )
00746                         mpx_events->start_values[i] += values[0] + ( long long )
00747                             ( ( values[0] / ( double ) cycles_this_slice ) *
00748                               ( t->total_c - mev->prev_total_c ) );
00749                     else     /* Use previous rate if the event has run too short time */
00750                         mpx_events->start_values[i] += values[0] + ( long long )
00751                             ( mev->rate_estimate *
00752                               ( t->total_c - mev->prev_total_c ) );
00753                 }
00754 #endif
00755             } else {
00756                 mpx_events->start_values[i] = mev->count;
00757             }
00758         } else {
00759             /* The = 0 isn't actually necessary; we only need
00760              * to sync up the mpx event to the master event,
00761              * but it seems safe to set the mev to 0 here, and
00762              * that gives us a change to avoid (very unlikely)
00763              * rollover problems for events used repeatedly over
00764              * a long time.
00765              */
00766             mpx_events->start_values[i] = 0;
00767             mpx_events->stop_values[i] = 0;
00768             mpx_events->start_hc[i] = mev->cycles = 0;
00769             mev->count_estimate = 0;
00770             mev->rate_estimate = 0.0;
00771             mev->prev_total_c = current_thread_mpx_c;
00772             mev->count = 0;
00773         }
00774         /* Adjust start value to include events and cycles
00775          * counted previously for this event set.
00776          */
00777     }
00778 
00779     mpx_events->status = MPX_RUNNING;
00780 
00781     /* Start first counter if one isn't already running */
00782     if ( t->cur_event == NULL ) {
00783         /* Pick an events at random to start. */
00784         int index = ( rand_r( &randomseed ) % mpx_events->num_events );
00785         t->cur_event = mpx_events->mev[index];
00786         t->total_c = 0;
00787         t->cur_event->prev_total_c = 0;
00788         mpx_events->start_c = 0;
00789         retval = PAPI_start( mpx_events->mev[index]->papi_event );
00790         assert( retval == PAPI_OK );
00791     } else {
00792         /* If an event is already running, record the starting cycle
00793          * count for mpx_events, which is the accumlated cycle count
00794          * for the master event set plus the cycles for this time
00795          * slice.
00796          */
00797         mpx_events->start_c = t->total_c + cycles_this_slice;
00798     }
00799 
00800 #if defined(DEBUG)
00801     if ( ISLEVEL( DEBUG_MULTIPLEX ) ) {
00802         MPXDBG( "%s:%d:: start_c=%lld  thread->total_c=%lld\n", __FILE__,
00803                 __LINE__, mpx_events->start_c, t->total_c );
00804         for ( i = 0; i < mpx_events->num_events; i++ ) {
00805             MPXDBG
00806                 ( "%s:%d:: start_values[%d]=%lld  estimate=%lld rate=%g last active=%lld\n",
00807                   __FILE__, __LINE__, i, mpx_events->start_values[i],
00808                   mpx_events->mev[i]->count_estimate,
00809                   mpx_events->mev[i]->rate_estimate,
00810                   mpx_events->mev[i]->prev_total_c );
00811         }
00812     }
00813 #endif
00814 
00815     mpx_release(  );
00816 
00817     retval = mpx_startup_itimer(  );
00818 
00819     return retval;
00820 }

Here is the call graph for this function:

Here is the caller graph for this function:

int MPX_stop ( MPX_EventSet mpx_events,
long long *  values 
)

Definition at line 974 of file sw_multiplex.c.

00975 {
00976     int i, cur_mpx_event;
00977     int retval = PAPI_OK;
00978     long long dummy_value[2];
00979     long long dummy_mpx_values[PAPI_MAX_SW_MPX_EVENTS];
00980     /* long long cycles_this_slice, total_cycles; */
00981     MasterEvent *cur_event = NULL, *head;
00982     Threadlist *thr = NULL;
00983 
00984     if ( mpx_events == NULL )
00985         return PAPI_EINVAL;
00986     if ( mpx_events->status != MPX_RUNNING )
00987         return PAPI_ENOTRUN;
00988 
00989     /* Read the counter values, this updates mpx_events->stop_values[] */
00990     MPXDBG( "Start\n" );
00991     if ( values == NULL )
00992       retval = MPX_read( mpx_events, dummy_mpx_values, 1 );
00993     else
00994       retval = MPX_read( mpx_events, values, 1 );
00995 
00996     /* Block timer interrupts while modifying active events */
00997     mpx_hold(  );
00998 
00999     /* Get the master event list for this thread. */
01000     head = get_my_threads_master_event_list(  );
01001     if (!head) {
01002       retval=PAPI_EBUG;
01003       goto exit_mpx_stop;
01004     }
01005 
01006     /* Get this threads data structure */
01007     thr = head->mythr;
01008     cur_event = thr->cur_event;
01009 
01010     /* This would be a good spot to "hold" the counter and then restart
01011      * it at the end, but PAPI_start resets counters so it is not possible
01012      */
01013 
01014     /* Run through all the events decrement their activity counters. */
01015     cur_mpx_event = -1;
01016     for ( i = 0; i < mpx_events->num_events; i++ ) {
01017         --mpx_events->mev[i]->active;
01018         if ( mpx_events->mev[i] == cur_event )
01019             cur_mpx_event = i;
01020     }
01021 
01022     /* One event in this set is currently running, if this was the
01023      * last active event set using this event, we need to start the next 
01024      * event if there still is one left in the queue
01025      */
01026     if ( cur_mpx_event > -1 ) {
01027         MasterEvent *tmp, *mev = mpx_events->mev[cur_mpx_event];
01028 
01029         if ( mev->active == 0 ) {
01030             /* Event is now inactive; stop it 
01031              * There is no need to update master event set 
01032              * counters as this is the last active user
01033              */
01034             retval = PAPI_stop( mev->papi_event, dummy_value );
01035             mev->rate_estimate = 0.0;
01036 
01037             /* Fall-back value if none is found */
01038             thr->cur_event = NULL;
01039             /* Now find a new cur_event */
01040             for ( tmp = ( cur_event->next == NULL ) ? head : cur_event->next;
01041                   tmp != cur_event;
01042                   tmp = ( tmp->next == NULL ) ? head : tmp->next ) {
01043                 if ( tmp->active ) {    /* Found the next one to start */
01044                     thr->cur_event = tmp;
01045                     break;
01046                 }
01047             }
01048 
01049             if ( thr->cur_event != NULL ) {
01050                 retval = PAPI_start( thr->cur_event->papi_event );
01051                 assert( retval == PAPI_OK );
01052             } else {
01053                 mpx_shutdown_itimer(  );
01054             }
01055         }
01056     }
01057     mpx_events->status = MPX_STOPPED;
01058 
01059 exit_mpx_stop:
01060     MPXDBG( "End\n" );
01061 
01062     /* Restore the timer (for other event sets that may be running) */
01063     mpx_release(  );
01064 
01065     return retval;
01066 }

Here is the call graph for this function:

Here is the caller graph for this function:


Generated on 17 Nov 2016 for PAPI by  doxygen 1.6.1