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