|
PAPI
5.0.1.0
|

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 PAPI_MAX_SW_MPX_EVENTS 32 |
Definition at line 4 of file sw_multiplex.h.
| enum MPX_status |
Definition at line 9 of file sw_multiplex.h.
{ MPX_STOPPED, MPX_RUNNING } MPX_status;
| int mpx_add_event | ( | MPX_EventSet ** | , |
| int | EventCode, | ||
| int | domain, | ||
| int | granularity | ||
| ) |
< Used with setting up array
< Used with setting up array
< Insufficient memory
< Used with setting up array
< Insufficient memory
< Used with setting up array
< No error
Definition at line 305 of file sw_multiplex.c.
{
MPX_EventSet *newset = *mpx_events;
int retval, alloced_newset = 0;
Threadlist *t;
/* Get the global list of threads */
MPXDBG("Adding %p %x\n",newset,EventCode);
_papi_hwi_lock( MULTIPLEX_LOCK );
t = tlist;
/* If there are no threads in the list at all, then allocate the new Threadlist */
if ( t == NULL ) {
new_thread:
t = ( Threadlist * ) papi_malloc( sizeof ( Threadlist ) );
if ( t == NULL ) {
_papi_hwi_unlock( MULTIPLEX_LOCK );
return ( PAPI_ENOMEM );
}
/* If we're actually threaded, fill the
* field with the thread_id otherwise
* use getpid() as a placeholder. */
if ( _papi_hwi_thread_id_fn ) {
MPXDBG( "New thread at %p\n", t );
t->tid = _papi_hwi_thread_id_fn( );
} else {
MPXDBG( "New process at %p\n", t );
t->tid = ( unsigned long ) getpid( );
}
/* Fill in the fields */
t->head = NULL;
t->cur_event = NULL;
t->next = tlist;
tlist = t;
MPXDBG( "New head is at %p(%lu).\n", tlist,
( long unsigned ) tlist->tid );
/* alloced_thread = 1; */
} else if ( _papi_hwi_thread_id_fn ) {
/* If we are threaded, AND there exists threads in the list,
* then try to find our thread in the list. */
unsigned long tid = _papi_hwi_thread_id_fn( );
while ( t ) {
if ( t->tid == tid ) {
MPXDBG( "Found thread 0x%lx\n", t->tid );
break;
}
t = t->next;
}
/* Our thread is not in the list, so make a new
* thread entry. */
if ( t == NULL ) {
MPXDBG( "New thread %lx\n", tid );
goto new_thread;
}
}
/* Now t & tlist points to our thread, also at the head of the list */
/* Allocate a the MPX_EventSet if necessary */
if ( newset == NULL ) {
newset = mpx_malloc( t );
if ( newset == NULL ) {
_papi_hwi_unlock( MULTIPLEX_LOCK );
return ( PAPI_ENOMEM );
}
alloced_newset = 1;
}
/* Now we're finished playing with the thread list */
_papi_hwi_unlock( MULTIPLEX_LOCK );
/* Removed newset->num_events++, moved to mpx_insert_events() */
mpx_hold( );
/* Create PAPI events (if they don't already exist) and link
* the new event set to them, add them to the master list for
the thread, reset master event list for this thread */
retval = mpx_insert_events( newset, &EventCode, 1,
domain, granularity );
if ( retval != PAPI_OK ) {
if ( alloced_newset ) {
papi_free( newset );
newset = NULL;
}
}
mpx_release( );
/* Output the new or existing EventSet */
*mpx_events = newset;
return retval;
}


| int MPX_add_events | ( | MPX_EventSet ** | mpx_events, |
| int * | event_list, | ||
| int | num_events, | ||
| int | domain, | ||
| int | granularity | ||
| ) |
< No error
< No error
Definition at line 676 of file sw_multiplex.c.
{
int i, retval = PAPI_OK;
for ( i = 0; i < num_events; i++ ) {
retval =
mpx_add_event( mpx_events, event_list[i], domain, granularity );
if ( retval != PAPI_OK )
return ( retval );
}
return ( retval );
}


| int mpx_check | ( | int | EventSet | ) |
< Internal error, please send mail to the developers
< No error
< User context counted
< Kernel/OS context counted
< Supervisor/hypervisor context counted
< No such EventSet Available
< EventSet domain is not supported for the operation
< No error
Definition at line 1121 of file sw_multiplex.c.
{
/* Currently, there is only the need for one mpx check: if
* running on POWER6/perfctr platform, the domain must
* include user, kernel, and supervisor, since the scale
* event uses the dedicated counter #6, PM_RUN_CYC, which
* cannot be controlled on a domain level.
*/
EventSetInfo_t *ESI = _papi_hwi_lookup_EventSet( EventSet );
if (ESI==NULL) return PAPI_EBUG;
if ( strstr( _papi_hwd[ESI->CmpIdx]->cmp_info.name, "perfctr.c" ) == NULL )
return PAPI_OK;
if ( strcmp( _papi_hwi_system_info.hw_info.model_string, "POWER6" ) == 0 ) {
unsigned int chk_domain =
PAPI_DOM_USER + PAPI_DOM_KERNEL + PAPI_DOM_SUPERVISOR;
if ( ESI == NULL )
return ( PAPI_ENOEVST );
if ( ( ESI->domain.domain & chk_domain ) != chk_domain ) {
PAPIERROR
( "This platform requires PAPI_DOM_USER+PAPI_DOM_KERNEL+PAPI_DOM_SUPERVISOR\n"
"to be set in the domain when using multiplexing. Instead, found 0X%x\n",
ESI->domain.domain );
return ( PAPI_EINVAL_DOM );
}
}
return PAPI_OK;
}


| int MPX_cleanup | ( | MPX_EventSet ** | mpx_events | ) |
< Invalid argument
< No error
< Invalid argument
< No error
Definition at line 1069 of file sw_multiplex.c.
{
#ifdef PTHREADS
int retval;
#endif
if ( mpx_events == NULL )
return PAPI_EINVAL;
if ( *mpx_events == NULL )
return PAPI_OK;
if (( *mpx_events )->status == MPX_RUNNING )
return PAPI_EINVAL;
mpx_hold( );
/* Remove master events from this event set and from
* the master list, if necessary.
*/
mpx_delete_events( *mpx_events );
mpx_release( );
/* Free all the memory */
papi_free( *mpx_events );
*mpx_events = NULL;
return PAPI_OK;
}


| int mpx_init | ( | int | ) |
< No error
Definition at line 1154 of file sw_multiplex.c.
{
#if defined(PTHREADS) || defined(_POWER6)
int retval;
#endif
#ifdef _POWER6
retval = PAPI_event_name_to_code( "PM_RUN_CYC", &_PNE_PM_RUN_CYC );
if ( retval != PAPI_OK )
return ( retval );
#endif
tlist = NULL;
mpx_hold( );
mpx_shutdown_itimer( );
mpx_init_timers( interval_ns / 1000 );
return ( PAPI_OK );
}


| int MPX_read | ( | MPX_EventSet * | mpx_events, |
| long long * | values, | ||
| int | called_by_stop | ||
| ) |
< No error
< No error
Definition at line 823 of file sw_multiplex.c.
{
int i;
int retval;
long long last_value[2];
long long cycles_this_slice = 0;
MasterEvent *cur_event;
Threadlist *thread_data;
if ( mpx_events->status == MPX_RUNNING ) {
/* Hold timer interrupts while we read values */
mpx_hold( );
thread_data = mpx_events->mythr;
cur_event = thread_data->cur_event;
retval = PAPI_read( cur_event->papi_event, last_value );
if ( retval != PAPI_OK )
return retval;
cycles_this_slice = ( cur_event->pi.event_type == SCALE_EVENT )
? last_value[0] : last_value[1];
/* Save the current counter values and get
* the lastest data for the current event
*/
for ( i = 0; i < mpx_events->num_events; i++ ) {
MasterEvent *mev = mpx_events->mev[i];
if ( !( mev->is_a_rate ) ) {
mpx_events->stop_values[i] = mev->count_estimate;
}
else {
mpx_events->stop_values[i] = mev->count;
}
#ifdef MPX_NONDECR_HYBRID
/* If we are called from MPX_stop() then */
/* adjust the final values based on the */
/* cycles elapsed since the last read */
/* otherwise, don't do this as it can cause */
/* decreasing values if read is called again */
/* before another sample happens. */
if (called_by_stop) {
/* Extrapolate data up to the current time
* only if it's not a rate measurement
*/
if ( !( mev->is_a_rate ) ) {
if ( mev != thread_data->cur_event ) {
mpx_events->stop_values[i] +=
( long long ) ( mev->rate_estimate *
( cycles_this_slice +
thread_data->total_c -
mev->prev_total_c ) );
MPXDBG
( "%s:%d:: Inactive %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
__FILE__, __LINE__, i, mpx_events->stop_values[i],
mev->count_estimate, mev->rate_estimate,
cycles_this_slice + thread_data->total_c -
mev->prev_total_c );
} else {
mpx_events->stop_values[i] += last_value[0] +
( long long ) ( mev->rate_estimate *
( thread_data->total_c -
mev->prev_total_c ) );
MPXDBG
( "%s:%d:: -Active- %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
__FILE__, __LINE__, i, mpx_events->stop_values[i],
mev->count_estimate, mev->rate_estimate,
thread_data->total_c - mev->prev_total_c );
}
}
}
#endif
}
mpx_events->stop_c = thread_data->total_c + cycles_this_slice;
/* Restore the interrupt */
mpx_release( );
}
/* Store the values in user array. */
for ( i = 0; i < mpx_events->num_events; i++ ) {
MasterEvent *mev = mpx_events->mev[i];
long long elapsed_slices = 0;
long long elapsed_values = mpx_events->stop_values[i]
- mpx_events->start_values[i];
/* For rates, cycles contains the number of measurements,
* not the number of cycles, so just divide to compute
* an average value. This assumes that the rate was
* constant over the whole measurement period.
*/
values[i] = elapsed_values;
if ( mev->is_a_rate ) {
/* Handler counts */
elapsed_slices = mev->cycles - mpx_events->start_hc[i];
values[i] =
elapsed_slices ? ( elapsed_values / elapsed_slices ) : 0;
}
MPXDBG( "%s:%d:: event %d, values=%lld ( %lld - %lld), cycles %lld\n",
__FILE__, __LINE__, i,
elapsed_values,
mpx_events->stop_values[i], mpx_events->start_values[i],
mev->is_a_rate ? elapsed_slices : 0 );
}
return PAPI_OK;
}


| int mpx_remove_event | ( | MPX_EventSet ** | , |
| int | EventCode | ||
| ) |
< No error
Definition at line 418 of file sw_multiplex.c.
{
mpx_hold( );
if ( *mpx_events )
mpx_delete_one_event( *mpx_events, EventCode );
mpx_release( );
return ( PAPI_OK );
}


| int MPX_reset | ( | MPX_EventSet * | mpx_events | ) |
< No error
< No error
Definition at line 937 of file sw_multiplex.c.
{
int i, retval;
long long values[PAPI_MAX_SW_MPX_EVENTS];
/* Get the current values from MPX_read */
retval = MPX_read( mpx_events, values, 0 );
if ( retval != PAPI_OK )
return retval;
/* Disable timer interrupt */
mpx_hold( );
/* Make counters read zero by setting the start values
* to the current counter values.
*/
for ( i = 0; i < mpx_events->num_events; i++ ) {
MasterEvent *mev = mpx_events->mev[i];
if ( mev->is_a_rate ) {
mpx_events->start_values[i] = mev->count;
} else {
mpx_events->start_values[i] += values[i];
}
mpx_events->start_hc[i] = mev->cycles;
}
/* Set the start time for this set to the current cycle count */
mpx_events->start_c = mpx_events->stop_c;
/* Restart the interrupt */
mpx_release( );
return PAPI_OK;
}


| void MPX_shutdown | ( | void | ) |
Definition at line 1102 of file sw_multiplex.c.
{
MPXDBG( "%d\n", getpid( ) );
mpx_shutdown_itimer( );
mpx_restore_signal( );
if ( tlist ) {
Threadlist *next,*t=tlist;
while(t!=NULL) {
next=t->next;
papi_free( t );
t = next;
}
tlist = NULL;
}
}


| int MPX_start | ( | MPX_EventSet * | mpx_events | ) |
< No error
< No error
< No error
< No error
Definition at line 692 of file sw_multiplex.c.
{
int retval = PAPI_OK;
int i;
long long values[2];
long long cycles_this_slice, current_thread_mpx_c = 0;
Threadlist *t;
t = mpx_events->mythr;
mpx_hold( );
if ( t->cur_event && t->cur_event->active ) {
current_thread_mpx_c += t->total_c;
retval = PAPI_read( t->cur_event->papi_event, values );
assert( retval == PAPI_OK );
if ( retval == PAPI_OK ) {
cycles_this_slice = ( t->cur_event->pi.event_type == SCALE_EVENT )
? values[0] : values[1];
} else {
values[0] = values[1] = 0;
cycles_this_slice = 0;
}
} else {
values[0] = values[1] = 0;
cycles_this_slice = 0;
}
/* Make all events in this set active, and for those
* already active, get the current count and cycles.
*/
for ( i = 0; i < mpx_events->num_events; i++ ) {
MasterEvent *mev = mpx_events->mev[i];
if ( mev->active++ ) {
mpx_events->start_values[i] = mev->count_estimate;
mpx_events->start_hc[i] = mev->cycles;
/* If this happens to be the currently-running
* event, add in the current amounts from this
* time slice. If it's a rate, though, don't
* bother since the event might not have been
* running long enough to get an accurate count.
*/
if ( t->cur_event && !( t->cur_event->is_a_rate ) ) {
#ifdef MPX_NONDECR_HYBRID
if ( mev != t->cur_event ) { /* This event is not running this slice */
mpx_events->start_values[i] +=
( long long ) ( mev->rate_estimate *
( cycles_this_slice + t->total_c -
mev->prev_total_c ) );
} else { /* The event is running, use current value + estimate */
if ( cycles_this_slice >= MPX_MINCYC )
mpx_events->start_values[i] += values[0] + ( long long )
( ( values[0] / ( double ) cycles_this_slice ) *
( t->total_c - mev->prev_total_c ) );
else /* Use previous rate if the event has run too short time */
mpx_events->start_values[i] += values[0] + ( long long )
( mev->rate_estimate *
( t->total_c - mev->prev_total_c ) );
}
#endif
} else {
mpx_events->start_values[i] = mev->count;
}
} else {
/* The = 0 isn't actually necessary; we only need
* to sync up the mpx event to the master event,
* but it seems safe to set the mev to 0 here, and
* that gives us a change to avoid (very unlikely)
* rollover problems for events used repeatedly over
* a long time.
*/
mpx_events->start_values[i] = 0;
mpx_events->stop_values[i] = 0;
mpx_events->start_hc[i] = mev->cycles = 0;
mev->count_estimate = 0;
mev->rate_estimate = 0.0;
mev->prev_total_c = current_thread_mpx_c;
mev->count = 0;
}
/* Adjust start value to include events and cycles
* counted previously for this event set.
*/
}
mpx_events->status = MPX_RUNNING;
/* Start first counter if one isn't already running */
if ( t->cur_event == NULL ) {
/* Pick an events at random to start. */
int index = ( rand_r( &randomseed ) % mpx_events->num_events );
t->cur_event = mpx_events->mev[index];
t->total_c = 0;
t->cur_event->prev_total_c = 0;
mpx_events->start_c = 0;
retval = PAPI_start( mpx_events->mev[index]->papi_event );
assert( retval == PAPI_OK );
} else {
/* If an event is already running, record the starting cycle
* count for mpx_events, which is the accumlated cycle count
* for the master event set plus the cycles for this time
* slice.
*/
mpx_events->start_c = t->total_c + cycles_this_slice;
}
#if defined(DEBUG)
if ( ISLEVEL( DEBUG_MULTIPLEX ) ) {
MPXDBG( "%s:%d:: start_c=%lld thread->total_c=%lld\n", __FILE__,
__LINE__, mpx_events->start_c, t->total_c );
for ( i = 0; i < mpx_events->num_events; i++ ) {
MPXDBG
( "%s:%d:: start_values[%d]=%lld estimate=%lld rate=%g last active=%lld\n",
__FILE__, __LINE__, i, mpx_events->start_values[i],
mpx_events->mev[i]->count_estimate,
mpx_events->mev[i]->rate_estimate,
mpx_events->mev[i]->prev_total_c );
}
}
#endif
mpx_release( );
retval = mpx_startup_itimer( );
return retval;
}


| int MPX_stop | ( | MPX_EventSet * | mpx_events, |
| long long * | values | ||
| ) |
< No error
< Invalid argument
< EventSet is currently not running
< Internal error, please send mail to the developers
< No error
Definition at line 974 of file sw_multiplex.c.
{
int i, cur_mpx_event;
int retval = PAPI_OK;
long long dummy_value[2];
long long dummy_mpx_values[PAPI_MAX_SW_MPX_EVENTS];
/* long long cycles_this_slice, total_cycles; */
MasterEvent *cur_event = NULL, *head;
Threadlist *thr = NULL;
if ( mpx_events == NULL )
return PAPI_EINVAL;
if ( mpx_events->status != MPX_RUNNING )
return PAPI_ENOTRUN;
/* Read the counter values, this updates mpx_events->stop_values[] */
MPXDBG( "Start\n" );
if ( values == NULL )
retval = MPX_read( mpx_events, dummy_mpx_values, 1 );
else
retval = MPX_read( mpx_events, values, 1 );
/* Block timer interrupts while modifying active events */
mpx_hold( );
/* Get the master event list for this thread. */
head = get_my_threads_master_event_list( );
if (!head) {
retval=PAPI_EBUG;
goto exit_mpx_stop;
}
/* Get this threads data structure */
thr = head->mythr;
cur_event = thr->cur_event;
/* This would be a good spot to "hold" the counter and then restart
* it at the end, but PAPI_start resets counters so it is not possible
*/
/* Run through all the events decrement their activity counters. */
cur_mpx_event = -1;
for ( i = 0; i < mpx_events->num_events; i++ ) {
--mpx_events->mev[i]->active;
if ( mpx_events->mev[i] == cur_event )
cur_mpx_event = i;
}
/* One event in this set is currently running, if this was the
* last active event set using this event, we need to start the next
* event if there still is one left in the queue
*/
if ( cur_mpx_event > -1 ) {
MasterEvent *tmp, *mev = mpx_events->mev[cur_mpx_event];
if ( mev->active == 0 ) {
/* Event is now inactive; stop it
* There is no need to update master event set
* counters as this is the last active user
*/
retval = PAPI_stop( mev->papi_event, dummy_value );
mev->rate_estimate = 0.0;
/* Fall-back value if none is found */
thr->cur_event = NULL;
/* Now find a new cur_event */
for ( tmp = ( cur_event->next == NULL ) ? head : cur_event->next;
tmp != cur_event;
tmp = ( tmp->next == NULL ) ? head : tmp->next ) {
if ( tmp->active ) { /* Found the next one to start */
thr->cur_event = tmp;
break;
}
}
if ( thr->cur_event != NULL ) {
retval = PAPI_start( thr->cur_event->papi_event );
assert( retval == PAPI_OK );
} else {
mpx_shutdown_itimer( );
}
}
}
mpx_events->status = MPX_STOPPED;
exit_mpx_stop:
MPXDBG( "End\n" );
/* Restore the timer (for other event sets that may be running) */
mpx_release( );
return retval;
}

