PAPI  5.0.1.0
sw_multiplex.c
Go to the documentation of this file.
00001 
00023 /* disable this to return to the pre 4.1.1 behavior */
00024 #define MPX_NONDECR_HYBRID
00025 
00026 /* Nils Smeds */
00027 
00028 /* This MPX update modifies the behaviour of the multiplexing in PAPI.
00029  * The previous versions of the multiplexing based the value returned
00030  * from PAPI_reads on the total counts achieved since the PAPI_start
00031  * of the multiplexed event. This count was used as the basis of the
00032  * extrapolation using the proportion of time that this particular
00033  * event was active to the total time the multiplexed event was
00034  * active. However, a typical usage of PAPI is to measure over
00035  * sections of code by starting the event once and by comparing
00036  * the values returned by subsequent calls to PAPI_read. The difference
00037  * in counts is used as the measure of occured events in the code
00038  * section between the calls. 
00039  *
00040  * When multiplexing is used in this fashion the time proportion used
00041  * for extrapolation might appear inconsistent. The time fraction used
00042  * at each PAPI_read is the total time fraction since PAPI_start. If the
00043  * counter values achieved in each multiplex of the event varies
00044  * largely, or if the time slices are varying in length, discrepancies
00045  * to the behaviour without multiplexing might occur.
00046  *
00047  * In this version the extrapolation is made on a local time scale. At
00048  * each completed time slice the event extrapolates the achieved count
00049  * to a extrapolated count for the time since this event was last sliced
00050  * out up to the current point in time. There will still be occasions
00051  * when two consecutive PAPI_read will yield decreasing results, but all
00052  * extrapolations are being made on time local data. If time slicing
00053  * varies or if the count rate varies this implementation is expected to
00054  * be more "accurate" in a loose and here unspecified meaning.
00055  *
00056  * The short description of the changes is that the running events has
00057  * new fields count_estimate, rate_estimate and prev_total_c. The mpx
00058  * events have had the meaning of start_values and stop_values modified
00059  * to mean extrapolated start value and extrapolated stop value.
00060  */
00061 
00062 /* 
00063 Portions of the following code are
00064 Copyright (c) 2009, Lawrence Livermore National Security, LLC.  
00065 Produced at the Lawrence Livermore National Laboratory  
00066 Written by John May, johnmay@llnl.gov
00067 LLNL-CODE-421124
00068 All rights reserved.  
00069   
00070 Redistribution and use in source and binary forms, with or
00071 without modification, are permitted provided that the following
00072 conditions are met:  
00073   
00074  • Redistributions of source code must retain the above copyright
00075 notice, this list of conditions and the disclaimer below. 
00076 
00077  • Redistributions in binary form must reproduce the above
00078 copyright notice, this list of conditions and the disclaimer (as
00079 noted below) in the documentation and/or other materials provided
00080 with the distribution. 
00081 
00082  • Neither the name of the LLNS/LLNL nor the names of its
00083 contributors may be used to endorse or promote products derived
00084 from this software without specific prior written permission.  
00085   
00086  
00087 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00088 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
00089 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00090 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00091 DISCLAIMED.  IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL
00092 SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE
00093 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
00094 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00095 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE, DATA,
00096 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON  ANY
00097 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00098 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00099 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00100 OF SUCH DAMAGE.  
00101   
00102   
00103 Additional BSD Notice  
00104   
00105 1. This notice is required to be provided under our contract with
00106 the U.S.  Department of Energy (DOE).  This work was produced at
00107 Lawrence Livermore National Laboratory under Contract No.
00108 DE-AC52-07NA27344 with the DOE.  
00109   
00110 2. Neither the United States Government nor Lawrence Livermore
00111 National Security, LLC nor any of their employees, makes any
00112 warranty, express or implied, or assumes any liability or
00113 responsibility for the accuracy, completeness, or usefulness of
00114 any information, apparatus, product, or process disclosed, or
00115 represents that its use would not infringe privately-owned
00116 rights.  
00117   
00118 3.  Also, reference herein to any specific commercial products,
00119 process, or services by trade name, trademark, manufacturer or
00120 otherwise does not necessarily constitute or imply its
00121 endorsement, recommendation, or favoring by the United States
00122 Government or Lawrence Livermore National Security, LLC.  The
00123 views and opinions of authors expressed herein do not necessarily
00124 state or reflect those of the United States Government or
00125 Lawrence Livermore National Security, LLC, and shall not be used
00126 for advertising or product endorsement purposes.  
00127  */
00128 
00129 #include "papi.h"
00130 #include "papi_internal.h"
00131 #include "papi_vector.h"
00132 #include "papi_memory.h"
00133 
00134 #define MPX_MINCYC 25000
00135 
00136 /* Globals for this file. */
00137 
00140 static Threadlist *tlist = NULL;
00141 static unsigned int randomseed;
00142 
00143 /* Timer stuff */
00144 
00145 #include <sys/time.h>
00146 #include <string.h>
00147 #include <errno.h>
00148 #include <unistd.h> 
00149 #include <assert.h>
00150 
00151 static sigset_t sigreset;
00152 static struct itimerval itime;
00153 static const struct itimerval itimestop = { {0, 0}, {0, 0} };
00154 static struct sigaction oaction;
00155 
00156 /* END Globals */
00157 
00158 #ifdef PTHREADS
00159 
00160 static int threads_responding = 0;
00161 
00162 static pthread_once_t mpx_once_control = PTHREAD_ONCE_INIT;
00163 static pthread_mutex_t tlistlock;
00164 static pthread_key_t master_events_key;
00165 static pthread_key_t thread_record_key;
00166 static MasterEvent *global_master_events;
00167 static void *global_process_record;
00168 #endif
00169 
00170 /* Forward prototypes */
00171 
00172 static void mpx_remove_unused( MasterEvent ** head );
00173 static void mpx_delete_events( MPX_EventSet * );
00174 static void mpx_delete_one_event( MPX_EventSet * mpx_events, int Event );
00175 static int mpx_insert_events( MPX_EventSet *, int *event_list, int num_events,
00176                               int domain, int granularity );
00177 static void mpx_handler( int signal );
00178 
00179 inline_static void
00180 mpx_hold( void )
00181 {
00182     sigprocmask( SIG_BLOCK, &sigreset, NULL );
00183     MPXDBG( "signal held\n" );
00184 }
00185 
00186 inline_static void
00187 mpx_release( void )
00188 {
00189     MPXDBG( "signal released\n" );
00190     sigprocmask( SIG_UNBLOCK, &sigreset, NULL );
00191 }
00192 
00193 static void
00194 mpx_init_timers( int interval )
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 }
00220 
00221 static int
00222 mpx_startup_itimer( void )
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 }
00245 
00246 static void
00247 mpx_restore_signal( void )
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 }
00255 
00256 static void
00257 mpx_shutdown_itimer( void )
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 }
00266 
00267 static MasterEvent *
00268 get_my_threads_master_event_list( void )
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 }
00290 
00291 static MPX_EventSet *
00292 mpx_malloc( Threadlist * t )
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 }
00303 
00304 int
00305 mpx_add_event( MPX_EventSet ** mpx_events, int EventCode, int domain,
00306                int granularity )
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 0x%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 }
00416 
00417 int
00418 mpx_remove_event( MPX_EventSet ** mpx_events, int EventCode )
00419 {
00420     mpx_hold(  );
00421     if ( *mpx_events )
00422         mpx_delete_one_event( *mpx_events, EventCode );
00423     mpx_release(  );
00424     return ( PAPI_OK );
00425 }
00426 
00427 #ifdef MPX_DEBUG_TIMER
00428 static long long lastcall;
00429 #endif
00430 
00431 
00432 #ifdef _POWER6
00433 /* POWER6 can always count PM_RUN_CYC on counter 6 in domain
00434    PAPI_DOM_ALL, and can count it on other domains on counters
00435    1 and 2 along with a very limited number of other native
00436    events */
00437 int _PNE_PM_RUN_CYC;
00438 #define SCALE_EVENT _PNE_PM_RUN_CYC
00439 #else
00440 #define SCALE_EVENT PAPI_TOT_CYC
00441 #endif
00442 
00443 
00444 static void
00445 mpx_handler( int signal )
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 }
00674 
00675 int
00676 MPX_add_events( MPX_EventSet ** mpx_events, int *event_list, int num_events,
00677                 int domain, int granularity )
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 }
00690 
00691 int
00692 MPX_start( MPX_EventSet * mpx_events )
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 }
00821 
00822 int
00823 MPX_read( MPX_EventSet * mpx_events, long long *values, int called_by_stop )
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 }
00935 
00936 int
00937 MPX_reset( MPX_EventSet * mpx_events )
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 }
00972 
00973 int
00974 MPX_stop( MPX_EventSet * mpx_events, long long *values )
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 }
01067 
01068 int
01069 MPX_cleanup( MPX_EventSet ** mpx_events )
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 }
01100 
01101 void
01102 MPX_shutdown( void )
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 }
01119 
01120 int
01121 mpx_check( int EventSet )
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         if ( ESI == NULL )
01140             return ( PAPI_ENOEVST );
01141 
01142         if ( ( ESI->domain.domain & chk_domain ) != chk_domain ) {
01143             PAPIERROR
01144                 ( "This platform requires PAPI_DOM_USER+PAPI_DOM_KERNEL+PAPI_DOM_SUPERVISOR\n"
01145                   "to be set in the domain when using multiplexing.  Instead, found 0X%x\n",
01146                   ESI->domain.domain );
01147             return ( PAPI_EINVAL_DOM );
01148         }
01149     }
01150     return PAPI_OK;
01151 }
01152 
01153 int
01154 mpx_init( int interval_ns )
01155 {
01156 #if defined(PTHREADS) || defined(_POWER6)
01157     int retval;
01158 #endif
01159 
01160 #ifdef _POWER6
01161     retval = PAPI_event_name_to_code( "PM_RUN_CYC", &_PNE_PM_RUN_CYC );
01162     if ( retval != PAPI_OK )
01163         return ( retval );
01164 #endif
01165     tlist = NULL;
01166     mpx_hold(  );
01167     mpx_shutdown_itimer(  );
01168     mpx_init_timers( interval_ns / 1000 );
01169 
01170     return ( PAPI_OK );
01171 }
01172 
01177 static int
01178 mpx_insert_events( MPX_EventSet *mpx_events, int *event_list,
01179            int num_events, int domain, int granularity )
01180 {
01181     int i, retval = 0, num_events_success = 0;
01182     MasterEvent *mev;
01183     PAPI_option_t options;
01184     MasterEvent **head = &mpx_events->mythr->head;
01185 
01186     MPXDBG("Inserting %p %d\n",mpx_events,mpx_events->num_events );
01187 
01188     /* Make sure we don't overrun our buffers */
01189     if (mpx_events->num_events + num_events > PAPI_MAX_SW_MPX_EVENTS) {
01190        return PAPI_ECOUNT;
01191     }
01192 
01193     /* For each event, see if there is already a corresponding
01194      * event in the master set for this thread.  If not, add it.
01195      */
01196     for ( i = 0; i < num_events; i++ ) {
01197 
01198         /* Look for a matching event in the master list */
01199         for( mev = *head; mev != NULL; mev = mev->next ) {
01200            if ( (mev->pi.event_type == event_list[i]) && 
01201             (mev->pi.domain == domain) &&
01202             (mev->pi.granularity == granularity ))
01203                 break;
01204         }
01205 
01206         /* No matching event in the list; add a new one */
01207         if ( mev == NULL ) {
01208            mev = (MasterEvent *) papi_malloc( sizeof ( MasterEvent ) );
01209            if ( mev == NULL ) {
01210               return PAPI_ENOMEM;
01211            }
01212 
01213            mev->pi.event_type = event_list[i];
01214            mev->pi.domain = domain;
01215            mev->pi.granularity = granularity;
01216            mev->uses = mev->active = 0;
01217            mev->prev_total_c = mev->count = mev->cycles = 0;
01218            mev->rate_estimate = 0.0;
01219            mev->count_estimate = 0;
01220            mev->is_a_rate = 0;
01221            mev->papi_event = PAPI_NULL;
01222             
01223            retval = PAPI_create_eventset( &( mev->papi_event ) );
01224            if ( retval != PAPI_OK ) {
01225               MPXDBG( "Event %d could not be counted.\n", 
01226                   event_list[i] );
01227               goto bail;
01228            }
01229 
01230            retval = PAPI_add_event( mev->papi_event, event_list[i] );
01231            if ( retval != PAPI_OK ) {
01232               MPXDBG( "Event %d could not be counted.\n", 
01233                   event_list[i] );
01234               goto bail;
01235            }
01236 
01237            /* Always count total cycles so we can scale results.
01238             * If user just requested cycles, 
01239             * don't add that event again. */
01240 
01241            if ( event_list[i] != SCALE_EVENT ) {
01242               retval = PAPI_add_event( mev->papi_event, SCALE_EVENT );
01243               if ( retval != PAPI_OK ) {
01244              MPXDBG( "Scale event could not be counted "
01245                  "at the same time.\n" );
01246              goto bail;
01247               }
01248            }
01249             
01250            /* Set the options for the event set */
01251            memset( &options, 0x0, sizeof ( options ) );
01252            options.domain.eventset = mev->papi_event;
01253            options.domain.domain = domain;
01254            retval = PAPI_set_opt( PAPI_DOMAIN, &options );
01255            if ( retval != PAPI_OK ) {
01256               MPXDBG( "PAPI_set_opt(PAPI_DOMAIN, ...) = %d\n", 
01257                   retval );
01258               goto bail;
01259            }
01260 
01261            memset( &options, 0x0, sizeof ( options ) );
01262            options.granularity.eventset = mev->papi_event;
01263            options.granularity.granularity = granularity;
01264            retval = PAPI_set_opt( PAPI_GRANUL, &options );
01265            if ( retval != PAPI_OK ) {
01266               if ( retval != PAPI_ECMP ) {
01267              /* ignore component errors because they typically mean
01268                 "not supported by the component" */
01269              MPXDBG( "PAPI_set_opt(PAPI_GRANUL, ...) = %d\n", 
01270                  retval );
01271              goto bail;
01272               }
01273            }
01274 
01275 
01276            /* Chain the event set into the 
01277             * master list of event sets used in
01278             * multiplexing. */
01279 
01280             mev->next = *head;
01281             *head = mev;
01282 
01283         }
01284 
01285         /* If we created a new event set, or we found a matching
01286          * eventset already in the list, then add the pointer in
01287          * the master list to this threads list. Then we bump the
01288          * number of successfully added events. */
01289     MPXDBG("Inserting now %p %d\n",mpx_events,mpx_events->num_events );
01290 
01291         mpx_events->mev[mpx_events->num_events + num_events_success] = mev;
01292         mpx_events->mev[mpx_events->num_events + num_events_success]->uses++;
01293         num_events_success++;
01294 
01295     }
01296 
01297     /* Always be sure the head master event points to the thread */
01298     if ( *head != NULL ) {
01299         ( *head )->mythr = mpx_events->mythr;
01300     }
01301     MPXDBG( "%d of %d events were added.\n", num_events_success, num_events );
01302     mpx_events->num_events += num_events_success;
01303     return ( PAPI_OK );
01304 
01305   bail:
01306     /* If there is a current mev, it is currently not linked into the list
01307      * of multiplexing events, so we can just delete that
01308      */
01309     if ( mev && mev->papi_event ) {
01310        if (PAPI_cleanup_eventset( mev->papi_event )!=PAPI_OK) {
01311          PAPIERROR("Cleanup eventset\n");
01312        }
01313        if (PAPI_destroy_eventset( &( mev->papi_event )) !=PAPI_OK) {
01314          PAPIERROR("Destory eventset\n");
01315        }
01316     }
01317     if ( mev )
01318         papi_free( mev );
01319     mev = NULL;
01320 
01321     /* Decrease the usage count of events */
01322     for ( i = 0; i < num_events_success; i++ ) {
01323         mpx_events->mev[mpx_events->num_events + i]->uses--;
01324     }
01325 
01326     /* Run the garbage collector to remove unused events */
01327     if ( num_events_success )
01328         mpx_remove_unused( head );
01329 
01330     return ( retval );
01331 }
01332 
01337 static void
01338 mpx_delete_events( MPX_EventSet * mpx_events )
01339 {
01340     int i;
01341     MasterEvent *mev;
01342 
01343     /* First decrement the reference counter for each master
01344      * event in this event set, then see if the master events
01345      * can be deleted.
01346      */
01347     for ( i = 0; i < mpx_events->num_events; i++ ) {
01348         mev = mpx_events->mev[i];
01349         --mev->uses;
01350         mpx_events->mev[i] = NULL;
01351         /* If it's no longer used, it should not be active! */
01352         assert( mev->uses || !( mev->active ) );
01353     }
01354     mpx_events->num_events = 0;
01355     mpx_remove_unused( &mpx_events->mythr->head );
01356 }
01357 
01362 static void
01363 mpx_delete_one_event( MPX_EventSet * mpx_events, int Event )
01364 {
01365     int i;
01366     MasterEvent *mev;
01367 
01368     /* First decrement the reference counter for each master
01369      * event in this event set, then see if the master events
01370      * can be deleted.
01371      */
01372     for ( i = 0; i < mpx_events->num_events; i++ ) {
01373         mev = mpx_events->mev[i];
01374         if ( mev->pi.event_type == Event ) {
01375             --mev->uses;
01376             mpx_events->num_events--;
01377             mpx_events->mev[i] = NULL;
01378             /* If it's no longer used, it should not be active! */
01379             assert( mev->uses || !( mev->active ) );
01380             break;
01381         }
01382     }
01383 
01384     /* If we removed an event that is not last in the list we
01385      * need to compact the event list
01386      */
01387 
01388     for ( ; i < mpx_events->num_events; i++ ) {
01389         mpx_events->mev[i] = mpx_events->mev[i + 1];
01390         mpx_events->start_values[i] = mpx_events->start_values[i + 1];
01391         mpx_events->stop_values[i] = mpx_events->stop_values[i + 1];
01392         mpx_events->start_hc[i] = mpx_events->start_hc[i + 1];
01393     }
01394     mpx_events->mev[i] = NULL;
01395 
01396     mpx_remove_unused( &mpx_events->mythr->head );
01397 
01398 }
01399 
01404 static void
01405 mpx_remove_unused( MasterEvent ** head )
01406 {
01407     MasterEvent *mev, *lastmev = NULL, *nextmev;
01408     Threadlist *thr = ( *head == NULL ) ? NULL : ( *head )->mythr;
01409     int retval;
01410 
01411     /* Clean up and remove unused master events. */
01412     for ( mev = *head; mev != NULL; mev = nextmev ) {
01413         nextmev = mev->next; /* get link before mev is freed */
01414         if ( !mev->uses ) {
01415             if ( lastmev == NULL ) {    /* this was the head event */
01416                 *head = nextmev;
01417             } else {
01418                 lastmev->next = nextmev;
01419             }
01420             retval=PAPI_cleanup_eventset( mev->papi_event );
01421             retval=PAPI_destroy_eventset( &( mev->papi_event ) );
01422             if (retval!=PAPI_OK) PAPIERROR("Error destroying event\n");
01423             papi_free( mev );
01424         } else {
01425             lastmev = mev;
01426         }
01427     }
01428 
01429     /* Always be sure the head master event points to the thread */
01430     if ( *head != NULL ) {
01431         ( *head )->mythr = thr;
01432     }
01433 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines