PAPI  5.0.1.0
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 
)

< 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;
}

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 
)

< 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 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 );
}

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 
)

< 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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

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.

{
    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;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

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 
)

< 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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines