sw_multiplex.c File Reference

Include dependency graph for sw_multiplex.c:

Go to the source code of this file.

Defines

#define MPX_NONDECR_HYBRID
#define MPX_MINCYC   25000
#define SCALE_EVENT   PAPI_TOT_CYC

Functions

static void mpx_remove_unused (MasterEvent **head)
static void mpx_delete_events (MPX_EventSet *)
static void mpx_delete_one_event (MPX_EventSet *mpx_events, int Event)
static int mpx_insert_events (MPX_EventSet *, int *event_list, int num_events, int domain, int granularity)
static void mpx_handler (int signal)
inline_static void mpx_hold (void)
inline_static void mpx_release (void)
static void mpx_init_timers (int interval)
static int mpx_startup_itimer (void)
static void mpx_restore_signal (void)
static void mpx_shutdown_itimer (void)
static MasterEventget_my_threads_master_event_list (void)
static MPX_EventSetmpx_malloc (Threadlist *t)
int mpx_add_event (MPX_EventSet **mpx_events, int EventCode, int domain, int granularity)
int mpx_remove_event (MPX_EventSet **mpx_events, int EventCode)
int MPX_add_events (MPX_EventSet **mpx_events, int *event_list, int num_events, int domain, int granularity)
int MPX_start (MPX_EventSet *mpx_events)
int MPX_read (MPX_EventSet *mpx_events, long long *values, int called_by_stop)
int MPX_reset (MPX_EventSet *mpx_events)
int MPX_stop (MPX_EventSet *mpx_events, long long *values)
int MPX_cleanup (MPX_EventSet **mpx_events)
void MPX_shutdown (void)
int mpx_check (int EventSet)
int mpx_init (int interval_ns)

Variables

static Threadlisttlist = NULL
static unsigned int randomseed
static sigset_t sigreset
static struct itimerval itime
static struct itimerval itimestop = { {0, 0}, {0, 0} }
static struct sigaction oaction

Detailed Description

Author:
Philip Mucci mucci@cs.utk.edu
John May johnmay@llnl.gov
Nils Smeds smeds@pdc.kth.se
Haihang You you@cs.utk.edu
Kevin London london@cs.utk.edu
Maynard Johnson maynardj@us.ibm.com
Dan Terpstra terpstra@cs.utk.edu

Definition in file sw_multiplex.c.


Define Documentation

#define MPX_MINCYC   25000

Definition at line 134 of file sw_multiplex.c.

#define MPX_NONDECR_HYBRID

xxxx Will this stuff run unmodified on multiple components? What happens when several components are counting multiplexed?

Definition at line 24 of file sw_multiplex.c.

#define SCALE_EVENT   PAPI_TOT_CYC

Definition at line 440 of file sw_multiplex.c.


Function Documentation

static MasterEvent* get_my_threads_master_event_list ( void   )  [static]

Definition at line 268 of file sw_multiplex.c.

00269 {
00270     Threadlist *t = tlist;
00271     unsigned long tid;
00272 
00273     MPXDBG( "tlist is %p\n", tlist );
00274     if ( tlist == NULL )
00275         return NULL;
00276 
00277     if ( _papi_hwi_thread_id_fn == NULL )
00278         return ( tlist->head );
00279 
00280     tid = _papi_hwi_thread_id_fn(  );
00281     unsigned long pid = ( unsigned long ) getpid(  );
00282 
00283     while ( t ) {
00284         if ( t->tid == tid || ( ( tid == 0 ) && ( t->tid == pid ) ) )
00285             return ( t->head );
00286         t = t->next;
00287     }
00288     return ( NULL );
00289 }

Here is the caller graph for this function:

int mpx_add_event ( MPX_EventSet **  mpx_events,
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:

static void mpx_delete_events ( MPX_EventSet mpx_events  )  [static]

Remove events from an mpx event set (and from the master event set for this thread, if the events are unused). MUST BE CALLED WITH THE SIGNAL HANDLER DISABLED

Definition at line 1336 of file sw_multiplex.c.

01337 {
01338     int i;
01339     MasterEvent *mev;
01340 
01341     /* First decrement the reference counter for each master
01342      * event in this event set, then see if the master events
01343      * can be deleted.
01344      */
01345     for ( i = 0; i < mpx_events->num_events; i++ ) {
01346         mev = mpx_events->mev[i];
01347         --mev->uses;
01348         mpx_events->mev[i] = NULL;
01349         /* If it's no longer used, it should not be active! */
01350         assert( mev->uses || !( mev->active ) );
01351     }
01352     mpx_events->num_events = 0;
01353     mpx_remove_unused( &mpx_events->mythr->head );
01354 }

Here is the call graph for this function:

Here is the caller graph for this function:

static void mpx_delete_one_event ( MPX_EventSet mpx_events,
int  Event 
) [static]

Remove one event from an mpx event set (and from the master event set for this thread, if the events are unused). MUST BE CALLED WITH THE SIGNAL HANDLER DISABLED

Definition at line 1361 of file sw_multiplex.c.

01362 {
01363     int i;
01364     MasterEvent *mev;
01365 
01366     /* First decrement the reference counter for each master
01367      * event in this event set, then see if the master events
01368      * can be deleted.
01369      */
01370     for ( i = 0; i < mpx_events->num_events; i++ ) {
01371         mev = mpx_events->mev[i];
01372         if ( mev->pi.event_type == Event ) {
01373             --mev->uses;
01374             mpx_events->num_events--;
01375             mpx_events->mev[i] = NULL;
01376             /* If it's no longer used, it should not be active! */
01377             assert( mev->uses || !( mev->active ) );
01378             break;
01379         }
01380     }
01381 
01382     /* If we removed an event that is not last in the list we
01383      * need to compact the event list
01384      */
01385 
01386     for ( ; i < mpx_events->num_events; i++ ) {
01387         mpx_events->mev[i] = mpx_events->mev[i + 1];
01388         mpx_events->start_values[i] = mpx_events->start_values[i + 1];
01389         mpx_events->stop_values[i] = mpx_events->stop_values[i + 1];
01390         mpx_events->start_hc[i] = mpx_events->start_hc[i + 1];
01391     }
01392     mpx_events->mev[i] = NULL;
01393 
01394     mpx_remove_unused( &mpx_events->mythr->head );
01395 
01396 }

Here is the call graph for this function:

Here is the caller graph for this function:

static void mpx_handler ( int  signal  )  [static]

Definition at line 445 of file sw_multiplex.c.

00446 {
00447     int retval;
00448     MasterEvent *mev, *head;
00449     Threadlist *me = NULL;
00450 #ifdef REGENERATE
00451     int lastthread;
00452 #endif
00453 #ifdef MPX_DEBUG_OVERHEAD
00454     long long usec;
00455     int didwork = 0;
00456     usec = PAPI_get_real_usec(  );
00457 #endif
00458 #ifdef MPX_DEBUG_TIMER
00459     long long thiscall;
00460 #endif
00461 
00462     signal = signal;         /* unused */
00463 
00464     MPXDBG( "Handler in thread\n" );
00465 
00466     /* This handler can be invoked either when a timer expires
00467      * or when another thread in this handler responding to the
00468      * timer signals other threads.  We have to distinguish
00469      * these two cases so that we don't get infinite loop of 
00470      * handler calls.  To do that, we look at the value of
00471      * threads_responding.  We assume that only one thread can
00472      * be active in this signal handler at a time, since the
00473      * invoking signal is blocked while the handler is active.
00474      * If threads_responding == 0, the current thread caught
00475      * the original timer signal.  (This thread may not have
00476      * any active event lists itself, though.)  This first
00477      * thread sends a signal to each of the other threads in
00478      * our list of threads that have master events lists.  If
00479      * threads_responding != 0, then this thread was signaled
00480      * by another thread.  We decrement that value and look
00481      * for an active events.  threads_responding should
00482      * reach zero when all active threads have handled their
00483      * signal.  It's probably possible for a thread to die
00484      * before it responds to a signal; if that happens,
00485      * threads_responding won't reach zero until the next
00486      * timer signal happens.  Then the signalled thread won't
00487      * signal any other threads.  If that happens only
00488      * occasionally, there should be no harm.  Likewise if
00489      * a new thread is added that fails to get signalled.
00490      * As for locking, we have to lock this list to prevent
00491      * another thread from modifying it, but if *this* thread
00492      * is trying to update the list (from another function) and
00493      * is signaled while it holds the lock, we will have deadlock.
00494      * Therefore, noninterrupt functions that update *this* list
00495      * must disable the signal that invokes this handler.
00496      */
00497 
00498 #ifdef PTHREADS
00499     _papi_hwi_lock( MULTIPLEX_LOCK );
00500 
00501     if ( threads_responding == 0 ) {    /* this thread caught the timer sig */
00502         /* Signal the other threads with event lists */
00503 #ifdef MPX_DEBUG_TIMER
00504         thiscall = _papi_hwd_get_real_usec(  );
00505         MPXDBG( "last signal was %lld usec ago\n", thiscall - lastcall );
00506         lastcall = thiscall;
00507 #endif
00508         MPXDBG( "%#x caught it, tlist is %p\n", self, tlist );
00509         for ( t = tlist; t != NULL; t = t->next ) {
00510             if ( pthread_equal( t->thr, self ) == 0 ) {
00511                 ++threads_responding;
00512                 retval = pthread_kill( t->thr, _papi_os_info.itimer_sig );
00513                 assert( retval == 0 );
00514 #ifdef MPX_DEBUG_SIGNALS
00515                 MPXDBG( "%#x signaling %#x\n", self, t->thr );
00516 #endif
00517             }
00518         }
00519     } else {
00520 #ifdef MPX_DEBUG_SIGNALS
00521         MPXDBG( "%#x was tapped, tr = %d\n", self, threads_responding );
00522 #endif
00523         --threads_responding;
00524     }
00525 #ifdef REGENERATE
00526     lastthread = ( threads_responding == 0 );
00527 #endif
00528     _papi_hwi_unlock( MULTIPLEX_LOCK );
00529 #endif
00530 
00531     /* See if this thread has an active event list */
00532     head = get_my_threads_master_event_list(  );
00533     if ( head != NULL ) {
00534 
00535         /* Get the thread header for this master event set.  It's
00536          * always in the first record of the set (and maybe in others)
00537          * if any record in the set is active.
00538          */
00539         me = head->mythr;
00540 
00541         /* Find the event that's currently active, stop and read
00542          * it, then start the next event in the list.
00543          * No need to lock the list because other functions
00544          * disable the timer interrupt before they update the list.
00545          */
00546         if ( me != NULL && me->cur_event != NULL ) {
00547             long long counts[2];
00548             MasterEvent *cur_event = me->cur_event;
00549             long long cycles = 0, total_cycles = 0;
00550 
00551             retval = PAPI_stop( cur_event->papi_event, counts );
00552             MPXDBG( "retval=%d, cur_event=%p, I'm tid=%lx\n",
00553                     retval, cur_event, me->tid );
00554 
00555             if ( retval == PAPI_OK ) {
00556                 MPXDBG( "counts[0] = %lld counts[1] = %lld\n", counts[0],
00557                         counts[1] );
00558 
00559                 cur_event->count += counts[0];
00560                 cycles = ( cur_event->pi.event_type == SCALE_EVENT )
00561                     ? counts[0] : counts[1];
00562 
00563                 me->total_c += cycles;
00564                 total_cycles = me->total_c - cur_event->prev_total_c;
00565                 cur_event->prev_total_c = me->total_c;
00566 
00567                 /* If it's a rate, count occurrences & average later */
00568                 if ( !cur_event->is_a_rate ) {
00569                     cur_event->cycles += cycles;
00570                     if ( cycles >= MPX_MINCYC ) {   /* Only update current rate on a decent slice */
00571                         cur_event->rate_estimate =
00572                             ( double ) counts[0] / ( double ) cycles;
00573                     }
00574                     cur_event->count_estimate +=
00575                         ( long long ) ( ( double ) total_cycles *
00576                                         cur_event->rate_estimate );
00577                                         MPXDBG("New estimate = %lld (%lld cycles * %lf rate)\n",
00578                                                cur_event->count_estimate,total_cycles,
00579                                                cur_event->rate_estimate);
00580                 } else {
00581                     /* Make sure we ran long enough to get a useful measurement (otherwise
00582                      * potentially inaccurate rate measurements get averaged in with
00583                      * the same weight as longer, more accurate ones.)
00584                      */
00585                     if ( cycles >= MPX_MINCYC ) {
00586                         cur_event->cycles += 1;
00587                     } else {
00588                         cur_event->count -= counts[0];
00589                     }
00590                 }
00591             } else {
00592                 MPXDBG( "%lx retval = %d, skipping\n", me->tid, retval );
00593                 MPXDBG( "%lx value = %lld cycles = %lld\n\n",
00594                         me->tid, cur_event->count, cur_event->cycles );
00595             }
00596 
00597             MPXDBG
00598                 ( "tid(%lx): value = %lld (%lld) cycles = %lld (%lld) rate = %lf\n\n",
00599                   me->tid, cur_event->count, cur_event->count_estimate,
00600                   cur_event->cycles, total_cycles, cur_event->rate_estimate );
00601             /* Start running the next event; look for the
00602              * next one in the list that's marked active.
00603              * It's possible that this event is the only
00604              * one active; if so, we should restart it,
00605              * but only after considerating all the other
00606              * possible events.
00607              */
00608             if ( ( retval != PAPI_OK ) ||
00609                  ( ( retval == PAPI_OK ) && ( cycles >= MPX_MINCYC ) ) ) {
00610                 for ( mev =
00611                       ( cur_event->next == NULL ) ? head : cur_event->next;
00612                       mev != cur_event;
00613                       mev = ( mev->next == NULL ) ? head : mev->next ) {
00614                     /* Found the next one to start */
00615                     if ( mev->active ) {
00616                         me->cur_event = mev;
00617                         break;
00618                     }
00619                 }
00620             }
00621 
00622             if ( me->cur_event->active ) {
00623                 retval = PAPI_start( me->cur_event->papi_event );
00624             }
00625 #ifdef MPX_DEBUG_OVERHEAD
00626             didwork = 1;
00627 #endif
00628         }
00629     }
00630 #ifdef ANY_THREAD_GETS_SIGNAL
00631     else {
00632         Threadlist *t;
00633         for ( t = tlist; t != NULL; t = t->next ) {
00634             if ( ( t->tid == _papi_hwi_thread_id_fn(  ) ) ||
00635                  ( t->head == NULL ) )
00636                 continue;
00637             MPXDBG( "forwarding signal to thread %lx\n", t->tid );
00638             retval = ( *_papi_hwi_thread_kill_fn ) ( t->tid, _papi_os_info.itimer_sig );
00639             if ( retval != 0 ) {
00640                 MPXDBG( "forwarding signal to thread %lx returned %d\n",
00641                         t->tid, retval );
00642             }
00643         }
00644     }
00645 #endif
00646 
00647 #ifdef REGENERATE
00648     /* Regenerating the signal each time through has the
00649      * disadvantage that if any thread ever drops a signal,
00650      * the whole time slicing system will stop.  Using
00651      * an automatically regenerated signal may have the
00652      * disadvantage that a new signal can arrive very
00653      * soon after all the threads have finished handling
00654      * the last one, so the interval may be too small for
00655      * accurate data collection.  However, using the
00656      * MIN_CYCLES check above should alleviate this.
00657      */
00658     /* Reset the timer once all threads have responded */
00659     if ( lastthread ) {
00660         retval = setitimer( _papi_os_info.itimer_num, &itime, NULL );
00661         assert( retval == 0 );
00662 #ifdef MPX_DEBUG_TIMER
00663         MPXDBG( "timer restarted by %lx\n", me->tid );
00664 #endif
00665     }
00666 #endif
00667 
00668 #ifdef MPX_DEBUG_OVERHEAD
00669     usec = _papi_hwd_get_real_usec(  ) - usec;
00670     MPXDBG( "handler %#x did %swork in %lld usec\n",
00671             self, ( didwork ? "" : "no " ), usec );
00672 #endif
00673 }

Here is the call graph for this function:

Here is the caller graph for this function:

inline_static void mpx_hold ( void   ) 

Definition at line 180 of file sw_multiplex.c.

00181 {
00182     sigprocmask( SIG_BLOCK, &sigreset, NULL );
00183     MPXDBG( "signal held\n" );
00184 }

Here is the caller graph for this function:

int mpx_init ( int  interval_ns  ) 

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:

static void mpx_init_timers ( int  interval  )  [static]

Definition at line 194 of file sw_multiplex.c.

00195 {
00196     /* Fill in the interval timer values now to save a
00197      * little time later.
00198      */
00199 #ifdef OUTSIDE_PAPI
00200     interval = MPX_DEFAULT_INTERVAL;
00201 #endif
00202 
00203 #ifdef REGENERATE
00204     /* Signal handler restarts the timer every time it runs */
00205     itime.it_interval.tv_sec = 0;
00206     itime.it_interval.tv_usec = 0;
00207     itime.it_value.tv_sec = 0;
00208     itime.it_value.tv_usec = interval;
00209 #else
00210     /* Timer resets itself automatically */
00211     itime.it_interval.tv_sec = 0;
00212     itime.it_interval.tv_usec = interval;
00213     itime.it_value.tv_sec = 0;
00214     itime.it_value.tv_usec = interval;
00215 #endif
00216 
00217     sigemptyset( &sigreset );
00218     sigaddset( &sigreset, _papi_os_info.itimer_sig );
00219 }

Here is the caller graph for this function:

static int mpx_insert_events ( MPX_EventSet mpx_events,
int *  event_list,
int  num_events,
int  domain,
int  granularity 
) [static]

Inserts a list of events into the master event list, and adds new mev pointers to the MPX_EventSet. MUST BE CALLED WITH THE TIMER INTERRUPT DISABLED

Definition at line 1176 of file sw_multiplex.c.

01178 {
01179     int i, retval = 0, num_events_success = 0;
01180     MasterEvent *mev;
01181     PAPI_option_t options;
01182     MasterEvent **head = &mpx_events->mythr->head;
01183 
01184     MPXDBG("Inserting %p %d\n",mpx_events,mpx_events->num_events );
01185 
01186     /* Make sure we don't overrun our buffers */
01187     if (mpx_events->num_events + num_events > PAPI_MAX_SW_MPX_EVENTS) {
01188        return PAPI_ECOUNT;
01189     }
01190 
01191     /* For each event, see if there is already a corresponding
01192      * event in the master set for this thread.  If not, add it.
01193      */
01194     for ( i = 0; i < num_events; i++ ) {
01195 
01196         /* Look for a matching event in the master list */
01197         for( mev = *head; mev != NULL; mev = mev->next ) {
01198            if ( (mev->pi.event_type == event_list[i]) && 
01199             (mev->pi.domain == domain) &&
01200             (mev->pi.granularity == granularity ))
01201                 break;
01202         }
01203 
01204         /* No matching event in the list; add a new one */
01205         if ( mev == NULL ) {
01206            mev = (MasterEvent *) papi_malloc( sizeof ( MasterEvent ) );
01207            if ( mev == NULL ) {
01208               return PAPI_ENOMEM;
01209            }
01210 
01211            mev->pi.event_type = event_list[i];
01212            mev->pi.domain = domain;
01213            mev->pi.granularity = granularity;
01214            mev->uses = mev->active = 0;
01215            mev->prev_total_c = mev->count = mev->cycles = 0;
01216            mev->rate_estimate = 0.0;
01217            mev->count_estimate = 0;
01218            mev->is_a_rate = 0;
01219            mev->papi_event = PAPI_NULL;
01220             
01221            retval = PAPI_create_eventset( &( mev->papi_event ) );
01222            if ( retval != PAPI_OK ) {
01223               MPXDBG( "Event %d could not be counted.\n", 
01224                   event_list[i] );
01225               goto bail;
01226            }
01227 
01228            retval = PAPI_add_event( mev->papi_event, event_list[i] );
01229            if ( retval != PAPI_OK ) {
01230               MPXDBG( "Event %d could not be counted.\n", 
01231                   event_list[i] );
01232               goto bail;
01233            }
01234 
01235            /* Always count total cycles so we can scale results.
01236             * If user just requested cycles, 
01237             * don't add that event again. */
01238 
01239            if ( event_list[i] != SCALE_EVENT ) {
01240               retval = PAPI_add_event( mev->papi_event, SCALE_EVENT );
01241               if ( retval != PAPI_OK ) {
01242              MPXDBG( "Scale event could not be counted "
01243                  "at the same time.\n" );
01244              goto bail;
01245               }
01246            }
01247             
01248            /* Set the options for the event set */
01249            memset( &options, 0x0, sizeof ( options ) );
01250            options.domain.eventset = mev->papi_event;
01251            options.domain.domain = domain;
01252            retval = PAPI_set_opt( PAPI_DOMAIN, &options );
01253            if ( retval != PAPI_OK ) {
01254               MPXDBG( "PAPI_set_opt(PAPI_DOMAIN, ...) = %d\n", 
01255                   retval );
01256               goto bail;
01257            }
01258 
01259            memset( &options, 0x0, sizeof ( options ) );
01260            options.granularity.eventset = mev->papi_event;
01261            options.granularity.granularity = granularity;
01262            retval = PAPI_set_opt( PAPI_GRANUL, &options );
01263            if ( retval != PAPI_OK ) {
01264               if ( retval != PAPI_ECMP ) {
01265              /* ignore component errors because they typically mean
01266                 "not supported by the component" */
01267              MPXDBG( "PAPI_set_opt(PAPI_GRANUL, ...) = %d\n", 
01268                  retval );
01269              goto bail;
01270               }
01271            }
01272 
01273 
01274            /* Chain the event set into the 
01275             * master list of event sets used in
01276             * multiplexing. */
01277 
01278             mev->next = *head;
01279             *head = mev;
01280 
01281         }
01282 
01283         /* If we created a new event set, or we found a matching
01284          * eventset already in the list, then add the pointer in
01285          * the master list to this threads list. Then we bump the
01286          * number of successfully added events. */
01287     MPXDBG("Inserting now %p %d\n",mpx_events,mpx_events->num_events );
01288 
01289         mpx_events->mev[mpx_events->num_events + num_events_success] = mev;
01290         mpx_events->mev[mpx_events->num_events + num_events_success]->uses++;
01291         num_events_success++;
01292 
01293     }
01294 
01295     /* Always be sure the head master event points to the thread */
01296     if ( *head != NULL ) {
01297         ( *head )->mythr = mpx_events->mythr;
01298     }
01299     MPXDBG( "%d of %d events were added.\n", num_events_success, num_events );
01300     mpx_events->num_events += num_events_success;
01301     return ( PAPI_OK );
01302 
01303   bail:
01304     /* If there is a current mev, it is currently not linked into the list
01305      * of multiplexing events, so we can just delete that
01306      */
01307     if ( mev && mev->papi_event ) {
01308        if (PAPI_cleanup_eventset( mev->papi_event )!=PAPI_OK) {
01309          PAPIERROR("Cleanup eventset\n");
01310        }
01311        if (PAPI_destroy_eventset( &( mev->papi_event )) !=PAPI_OK) {
01312          PAPIERROR("Destory eventset\n");
01313        }
01314     }
01315     if ( mev )
01316         papi_free( mev );
01317     mev = NULL;
01318 
01319     /* Decrease the usage count of events */
01320     for ( i = 0; i < num_events_success; i++ ) {
01321         mpx_events->mev[mpx_events->num_events + i]->uses--;
01322     }
01323 
01324     /* Run the garbage collector to remove unused events */
01325     if ( num_events_success )
01326         mpx_remove_unused( head );
01327 
01328     return ( retval );
01329 }

Here is the call graph for this function:

Here is the caller graph for this function:

static MPX_EventSet* mpx_malloc ( Threadlist t  )  [static]

Definition at line 292 of file sw_multiplex.c.

00293 {
00294     MPX_EventSet *newset =
00295         ( MPX_EventSet * ) papi_malloc( sizeof ( MPX_EventSet ) );
00296     if ( newset == NULL )
00297         return ( NULL );
00298     memset( newset, 0, sizeof ( MPX_EventSet ) );
00299     newset->status = MPX_STOPPED;
00300     newset->mythr = t;
00301     return ( newset );
00302 }

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:

inline_static void mpx_release ( void   ) 

Definition at line 187 of file sw_multiplex.c.

00188 {
00189     MPXDBG( "signal released\n" );
00190     sigprocmask( SIG_UNBLOCK, &sigreset, NULL );
00191 }

Here is the caller graph for this function:

int mpx_remove_event ( MPX_EventSet **  mpx_events,
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:

static void mpx_remove_unused ( MasterEvent **  head  )  [static]

Remove events that are not used any longer from the run list of events to multiplex by the handler MUST BE CALLED WITH THE SIGNAL HANDLER DISABLED

Definition at line 1403 of file sw_multiplex.c.

01404 {
01405     MasterEvent *mev, *lastmev = NULL, *nextmev;
01406     Threadlist *thr = ( *head == NULL ) ? NULL : ( *head )->mythr;
01407     int retval;
01408 
01409     /* Clean up and remove unused master events. */
01410     for ( mev = *head; mev != NULL; mev = nextmev ) {
01411         nextmev = mev->next; /* get link before mev is freed */
01412         if ( !mev->uses ) {
01413             if ( lastmev == NULL ) {    /* this was the head event */
01414                 *head = nextmev;
01415             } else {
01416                 lastmev->next = nextmev;
01417             }
01418             retval=PAPI_cleanup_eventset( mev->papi_event );
01419             retval=PAPI_destroy_eventset( &( mev->papi_event ) );
01420             if (retval!=PAPI_OK) PAPIERROR("Error destroying event\n");
01421             papi_free( mev );
01422         } else {
01423             lastmev = mev;
01424         }
01425     }
01426 
01427     /* Always be sure the head master event points to the thread */
01428     if ( *head != NULL ) {
01429         ( *head )->mythr = thr;
01430     }
01431 }

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:

static void mpx_restore_signal ( void   )  [static]

Definition at line 247 of file sw_multiplex.c.

00248 {
00249     MPXDBG( "restore signal\n" );
00250     if ( _papi_os_info.itimer_sig != PAPI_NULL ) {
00251         if ( signal( _papi_os_info.itimer_sig, SIG_IGN ) == SIG_ERR )
00252             PAPIERROR( "sigaction stop errno %d", errno );
00253     }
00254 }

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:

static void mpx_shutdown_itimer ( void   )  [static]

Definition at line 257 of file sw_multiplex.c.

00258 {
00259     MPXDBG( "setitimer off\n" );
00260     if ( _papi_os_info.itimer_num != PAPI_NULL ) {
00261         if ( setitimer( _papi_os_info.itimer_num,
00262                ( struct itimerval * ) &itimestop, NULL ) == -1 )
00263             PAPIERROR( "setitimer stop errno %d", errno );
00264     }
00265 }

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:

static int mpx_startup_itimer ( void   )  [static]

Definition at line 222 of file sw_multiplex.c.

00223 {
00224     struct sigaction sigact;
00225 
00226     /* Set up the signal handler and the timer that triggers it */
00227 
00228     MPXDBG( "PID %d\n", getpid(  ) );
00229     memset( &sigact, 0, sizeof ( sigact ) );
00230     sigact.sa_flags = SA_RESTART;
00231     sigact.sa_handler = mpx_handler;
00232 
00233     if ( sigaction( _papi_os_info.itimer_sig, &sigact, NULL ) == -1 ) {
00234         PAPIERROR( "sigaction start errno %d", errno );
00235         return PAPI_ESYS;
00236     }
00237 
00238     if ( setitimer( _papi_os_info.itimer_num, &itime, NULL ) == -1 ) {
00239         sigaction( _papi_os_info.itimer_sig, &oaction, NULL );
00240         PAPIERROR( "setitimer start errno %d", errno );
00241         return PAPI_ESYS;
00242     }
00243     return ( PAPI_OK );
00244 }

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:


Variable Documentation

struct itimerval itime [static]

Definition at line 152 of file sw_multiplex.c.

struct itimerval itimestop = { {0, 0}, {0, 0} } [static]

Definition at line 153 of file sw_multiplex.c.

struct sigaction oaction [static]

Definition at line 154 of file sw_multiplex.c.

unsigned int randomseed [static]

Definition at line 141 of file sw_multiplex.c.

sigset_t sigreset [static]

Definition at line 151 of file sw_multiplex.c.

Threadlist* tlist = NULL [static]

List of threads that are multiplexing.

Definition at line 140 of file sw_multiplex.c.


Generated on 17 Nov 2016 for PAPI by  doxygen 1.6.1