PAPI 7.1.0.0
Loading...
Searching...
No Matches
sw_multiplex.c
Go to the documentation of this file.
1
23/* disable this to return to the pre 4.1.1 behavior */
24#define MPX_NONDECR_HYBRID
25
26/* Nils Smeds */
27
28/* This MPX update modifies the behaviour of the multiplexing in PAPI.
29 * The previous versions of the multiplexing based the value returned
30 * from PAPI_reads on the total counts achieved since the PAPI_start
31 * of the multiplexed event. This count was used as the basis of the
32 * extrapolation using the proportion of time that this particular
33 * event was active to the total time the multiplexed event was
34 * active. However, a typical usage of PAPI is to measure over
35 * sections of code by starting the event once and by comparing
36 * the values returned by subsequent calls to PAPI_read. The difference
37 * in counts is used as the measure of occurred events in the code
38 * section between the calls.
39 *
40 * When multiplexing is used in this fashion the time proportion used
41 * for extrapolation might appear inconsistent. The time fraction used
42 * at each PAPI_read is the total time fraction since PAPI_start. If the
43 * counter values achieved in each multiplex of the event varies
44 * largely, or if the time slices are varying in length, discrepancies
45 * to the behaviour without multiplexing might occur.
46 *
47 * In this version the extrapolation is made on a local time scale. At
48 * each completed time slice the event extrapolates the achieved count
49 * to a extrapolated count for the time since this event was last sliced
50 * out up to the current point in time. There will still be occasions
51 * when two consecutive PAPI_read will yield decreasing results, but all
52 * extrapolations are being made on time local data. If time slicing
53 * varies or if the count rate varies this implementation is expected to
54 * be more "accurate" in a loose and here unspecified meaning.
55 *
56 * The short description of the changes is that the running events has
57 * new fields count_estimate, rate_estimate and prev_total_c. The mpx
58 * events have had the meaning of start_values and stop_values modified
59 * to mean extrapolated start value and extrapolated stop value.
60 */
61
62/*
63Portions of the following code are
64Copyright (c) 2009, Lawrence Livermore National Security, LLC.
65Produced at the Lawrence Livermore National Laboratory
66Written by John May, johnmay@llnl.gov
67LLNL-CODE-421124
68All rights reserved.
69
70Redistribution and use in source and binary forms, with or
71without modification, are permitted provided that the following
72conditions are met:
73
74 • Redistributions of source code must retain the above copyright
75notice, this list of conditions and the disclaimer below.
76
77 • Redistributions in binary form must reproduce the above
78copyright notice, this list of conditions and the disclaimer (as
79noted below) in the documentation and/or other materials provided
80with the distribution.
81
82 • Neither the name of the LLNS/LLNL nor the names of its
83contributors may be used to endorse or promote products derived
84from this software without specific prior written permission.
85
86
87THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
88CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
89INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
90MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
91DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL
92SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE
93LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
94OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
95PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
96OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
97THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
98TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
99OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
100OF SUCH DAMAGE.
101
102
103Additional BSD Notice
104
1051. This notice is required to be provided under our contract with
106the U.S. Department of Energy (DOE). This work was produced at
107Lawrence Livermore National Laboratory under Contract No.
108DE-AC52-07NA27344 with the DOE.
109
1102. Neither the United States Government nor Lawrence Livermore
111National Security, LLC nor any of their employees, makes any
112warranty, express or implied, or assumes any liability or
113responsibility for the accuracy, completeness, or usefulness of
114any information, apparatus, product, or process disclosed, or
115represents that its use would not infringe privately-owned
116rights.
117
1183. Also, reference herein to any specific commercial products,
119process, or services by trade name, trademark, manufacturer or
120otherwise does not necessarily constitute or imply its
121endorsement, recommendation, or favoring by the United States
122Government or Lawrence Livermore National Security, LLC. The
123views and opinions of authors expressed herein do not necessarily
124state or reflect those of the United States Government or
125Lawrence Livermore National Security, LLC, and shall not be used
126for advertising or product endorsement purposes.
127 */
128
129#include "papi.h"
130#include "papi_internal.h"
131#include "papi_vector.h"
132#include "papi_memory.h"
133
134#define MPX_MINCYC 25000
135
136/* Globals for this file. */
137
140static Threadlist *tlist = NULL;
141static unsigned int randomseed;
142
143/* Timer stuff */
144
145#include <sys/time.h>
146#include <string.h>
147#include <errno.h>
148#include <unistd.h>
149#include <assert.h>
150
152static struct itimerval itime;
153static const struct itimerval itimestop = { {0, 0}, {0, 0} };
154static struct sigaction oaction;
155
156/* END Globals */
157
158#ifdef PTHREADS
160static int threads_responding = 0;
161
162static pthread_once_t mpx_once_control = PTHREAD_ONCE_INIT;
163static pthread_mutex_t tlistlock;
164static pthread_key_t master_events_key;
165static pthread_key_t thread_record_key;
166static MasterEvent *global_master_events;
167static void *global_process_record;
168#endif
169
170/* Forward prototypes */
171
172static void mpx_remove_unused( MasterEvent ** head );
173static void mpx_delete_events( MPX_EventSet * );
174static void mpx_delete_one_event( MPX_EventSet * mpx_events, int Event );
175static int mpx_insert_events( MPX_EventSet *, int *event_list, int num_events,
176 int domain, int granularity );
177static void mpx_handler( int signal );
178
179inline_static void
180mpx_hold( void )
181{
182 sigprocmask( SIG_BLOCK, &sigreset, NULL );
183 MPXDBG( "signal held\n" );
184}
185
186inline_static void
188{
189 MPXDBG( "signal released\n" );
190 sigprocmask( SIG_UNBLOCK, &sigreset, NULL );
191}
192
193static void
194mpx_init_timers( int interval )
195{
196 /* Fill in the interval timer values now to save a
197 * little time later.
198 */
199#ifdef OUTSIDE_PAPI
200 interval = MPX_DEFAULT_INTERVAL;
201#endif
202
203#ifdef REGENERATE
204 /* Signal handler restarts the timer every time it runs */
205 itime.it_interval.tv_sec = 0;
206 itime.it_interval.tv_usec = 0;
207 itime.it_value.tv_sec = 0;
208 itime.it_value.tv_usec = interval;
209#else
210 /* Timer resets itself automatically */
211 itime.it_interval.tv_sec = 0;
212 itime.it_interval.tv_usec = interval;
213 itime.it_value.tv_sec = 0;
214 itime.it_value.tv_usec = interval;
215#endif
216
217 sigemptyset( &sigreset );
218 sigaddset( &sigreset, _papi_os_info.itimer_sig );
219}
220
221static int
223{
224 struct sigaction sigact;
225
226 /* Set up the signal handler and the timer that triggers it */
227
228 MPXDBG( "PID %d\n", getpid( ) );
229 memset( &sigact, 0, sizeof ( sigact ) );
230 sigact.sa_flags = SA_RESTART;
231 sigact.sa_handler = mpx_handler;
232
233 if ( sigaction( _papi_os_info.itimer_sig, &sigact, NULL ) == -1 ) {
234 PAPIERROR( "sigaction start errno %d", errno );
235 return PAPI_ESYS;
236 }
237
238 if ( setitimer( _papi_os_info.itimer_num, &itime, NULL ) == -1 ) {
240 PAPIERROR( "setitimer start errno %d", errno );
241 return PAPI_ESYS;
242 }
243 return ( PAPI_OK );
244}
245
246static void
248{
249 MPXDBG( "restore signal\n" );
251 if ( signal( _papi_os_info.itimer_sig, SIG_IGN ) == SIG_ERR )
252 PAPIERROR( "sigaction stop errno %d", errno );
253 }
254}
255
256static void
258{
259 MPXDBG( "setitimer off\n" );
261 if ( setitimer( _papi_os_info.itimer_num,
262 ( struct itimerval * ) &itimestop, NULL ) == -1 )
263 PAPIERROR( "setitimer stop errno %d", errno );
264 }
265}
266
267static MasterEvent *
269{
270 Threadlist *t = tlist;
271 unsigned long tid;
272
273 MPXDBG( "tlist is %p\n", tlist );
274 if ( tlist == NULL )
275 return NULL;
276
277 if ( _papi_hwi_thread_id_fn == NULL )
278 return ( tlist->head );
279
280 tid = _papi_hwi_thread_id_fn( );
281 unsigned long pid = ( unsigned long ) getpid( );
282
283 while ( t ) {
284 if ( t->tid == tid || ( ( tid == 0 ) && ( t->tid == pid ) ) )
285 return ( t->head );
286 t = t->next;
287 }
288 return ( NULL );
289}
290
291static MPX_EventSet *
293{
294 MPX_EventSet *newset =
295 ( MPX_EventSet * ) papi_malloc( sizeof ( MPX_EventSet ) );
296 if ( newset == NULL )
297 return ( NULL );
298 memset( newset, 0, sizeof ( MPX_EventSet ) );
299 newset->status = MPX_STOPPED;
300 newset->mythr = t;
301 return ( newset );
302}
303
304int
305mpx_add_event( MPX_EventSet ** mpx_events, int EventCode, int domain,
306 int granularity )
307{
308 MPX_EventSet *newset = *mpx_events;
309 int retval, alloced_newset = 0;
310 Threadlist *t;
311
312 /* Get the global list of threads */
313
314 MPXDBG("Adding %p %#x\n",newset,EventCode);
315
317 t = tlist;
318
319 /* If there are no threads in the list at all, then allocate the new Threadlist */
320
321 if ( t == NULL ) {
322 new_thread:
323 t = ( Threadlist * ) papi_malloc( sizeof ( Threadlist ) );
324 if ( t == NULL ) {
326 return ( PAPI_ENOMEM );
327 }
328
329 /* If we're actually threaded, fill the
330 * field with the thread_id otherwise
331 * use getpid() as a placeholder. */
332
334 MPXDBG( "New thread at %p\n", t );
336 } else {
337 MPXDBG( "New process at %p\n", t );
338 t->tid = ( unsigned long ) getpid( );
339 }
340
341 /* Fill in the fields */
342
343 t->head = NULL;
344 t->cur_event = NULL;
345 t->next = tlist;
346 tlist = t;
347 MPXDBG( "New head is at %p(%lu).\n", tlist,
348 ( long unsigned ) tlist->tid );
349 /* alloced_thread = 1; */
350 } else if ( _papi_hwi_thread_id_fn ) {
351
352 /* If we are threaded, AND there exists threads in the list,
353 * then try to find our thread in the list. */
354
355 unsigned long tid = _papi_hwi_thread_id_fn( );
356
357 while ( t ) {
358 if ( t->tid == tid ) {
359 MPXDBG( "Found thread %#lx\n", t->tid );
360 break;
361 }
362 t = t->next;
363 }
364
365 /* Our thread is not in the list, so make a new
366 * thread entry. */
367
368 if ( t == NULL ) {
369 MPXDBG( "New thread %lx\n", tid );
370 goto new_thread;
371 }
372 }
373
374 /* Now t & tlist points to our thread, also at the head of the list */
375
376 /* Allocate a the MPX_EventSet if necessary */
377
378 if ( newset == NULL ) {
379 newset = mpx_malloc( t );
380 if ( newset == NULL ) {
382 return ( PAPI_ENOMEM );
383 }
384 alloced_newset = 1;
385 }
386
387 /* Now we're finished playing with the thread list */
388
390
391 /* Removed newset->num_events++, moved to mpx_insert_events() */
392
393 mpx_hold( );
394
395 /* Create PAPI events (if they don't already exist) and link
396 * the new event set to them, add them to the master list for
397 the thread, reset master event list for this thread */
398
399 retval = mpx_insert_events( newset, &EventCode, 1,
400 domain, granularity );
401 if ( retval != PAPI_OK ) {
402 if ( alloced_newset ) {
403 papi_free( newset );
404 newset = NULL;
405 }
406 }
407
408 mpx_release( );
409
410 /* Output the new or existing EventSet */
411
412 *mpx_events = newset;
413
414 return retval;
415}
416
417int
418mpx_remove_event( MPX_EventSet ** mpx_events, int EventCode )
419{
420 mpx_hold( );
421 if ( *mpx_events )
422 mpx_delete_one_event( *mpx_events, EventCode );
423 mpx_release( );
424 return ( PAPI_OK );
425}
426
427#ifdef MPX_DEBUG_TIMER
428static long long lastcall;
429#endif
430
431
432#ifdef _POWER6
433/* POWER6 can always count PM_RUN_CYC on counter 6 in domain
434 PAPI_DOM_ALL, and can count it on other domains on counters
435 1 and 2 along with a very limited number of other native
436 events */
437int _PNE_PM_RUN_CYC;
438#define SCALE_EVENT _PNE_PM_RUN_CYC
439#else
440#define SCALE_EVENT PAPI_TOT_CYC
441#endif
442
443
444static void
446{
447 int retval;
448 MasterEvent *mev, *head;
449 Threadlist *me = NULL;
450#ifdef REGENERATE
451 int lastthread;
452#endif
453#ifdef MPX_DEBUG_OVERHEAD
454 long long usec;
455 int didwork = 0;
456 usec = PAPI_get_real_usec( );
457#endif
458#ifdef MPX_DEBUG_TIMER
459 long long thiscall;
460#endif
461
462 signal = signal; /* unused */
463
464 MPXDBG( "Handler in thread\n" );
465
466 /* This handler can be invoked either when a timer expires
467 * or when another thread in this handler responding to the
468 * timer signals other threads. We have to distinguish
469 * these two cases so that we don't get infinite loop of
470 * handler calls. To do that, we look at the value of
471 * threads_responding. We assume that only one thread can
472 * be active in this signal handler at a time, since the
473 * invoking signal is blocked while the handler is active.
474 * If threads_responding == 0, the current thread caught
475 * the original timer signal. (This thread may not have
476 * any active event lists itself, though.) This first
477 * thread sends a signal to each of the other threads in
478 * our list of threads that have master events lists. If
479 * threads_responding != 0, then this thread was signaled
480 * by another thread. We decrement that value and look
481 * for an active events. threads_responding should
482 * reach zero when all active threads have handled their
483 * signal. It's probably possible for a thread to die
484 * before it responds to a signal; if that happens,
485 * threads_responding won't reach zero until the next
486 * timer signal happens. Then the signalled thread won't
487 * signal any other threads. If that happens only
488 * occasionally, there should be no harm. Likewise if
489 * a new thread is added that fails to get signalled.
490 * As for locking, we have to lock this list to prevent
491 * another thread from modifying it, but if *this* thread
492 * is trying to update the list (from another function) and
493 * is signaled while it holds the lock, we will have deadlock.
494 * Therefore, noninterrupt functions that update *this* list
495 * must disable the signal that invokes this handler.
496 */
497
498#ifdef PTHREADS
500
501 if ( threads_responding == 0 ) { /* this thread caught the timer sig */
502 /* Signal the other threads with event lists */
503#ifdef MPX_DEBUG_TIMER
504 thiscall = _papi_hwd_get_real_usec( );
505 MPXDBG( "last signal was %lld usec ago\n", thiscall - lastcall );
506 lastcall = thiscall;
507#endif
508 MPXDBG( "%#x caught it, tlist is %p\n", self, tlist );
509 for ( t = tlist; t != NULL; t = t->next ) {
510 if ( pthread_equal( t->thr, self ) == 0 ) {
511 ++threads_responding;
513 assert( retval == 0 );
514#ifdef MPX_DEBUG_SIGNALS
515 MPXDBG( "%#x signaling %#x\n", self, t->thr );
516#endif
517 }
518 }
519 } else {
520#ifdef MPX_DEBUG_SIGNALS
521 MPXDBG( "%#x was tapped, tr = %d\n", self, threads_responding );
522#endif
523 --threads_responding;
524 }
525#ifdef REGENERATE
526 lastthread = ( threads_responding == 0 );
527#endif
529#endif
530
531 /* See if this thread has an active event list */
533 if ( head != NULL ) {
534
535 /* Get the thread header for this master event set. It's
536 * always in the first record of the set (and maybe in others)
537 * if any record in the set is active.
538 */
539 me = head->mythr;
540
541 /* Find the event that's currently active, stop and read
542 * it, then start the next event in the list.
543 * No need to lock the list because other functions
544 * disable the timer interrupt before they update the list.
545 */
546 if ( me != NULL && me->cur_event != NULL ) {
547 long long counts[2];
548 MasterEvent *cur_event = me->cur_event;
549 long long cycles = 0, total_cycles = 0;
550
551 retval = PAPI_stop( cur_event->papi_event, counts );
552 MPXDBG( "retval=%d, cur_event=%p, I'm tid=%lx\n",
553 retval, cur_event, me->tid );
554
555 if ( retval == PAPI_OK ) {
556 MPXDBG( "counts[0] = %lld counts[1] = %lld\n", counts[0],
557 counts[1] );
558
559 cur_event->count += counts[0];
560 cycles = ( cur_event->pi.event_type == SCALE_EVENT )
561 ? counts[0] : counts[1];
562
563 me->total_c += cycles;
564 total_cycles = me->total_c - cur_event->prev_total_c;
565 cur_event->prev_total_c = me->total_c;
566
567 /* If it's a rate, count occurrences & average later */
568 if ( !cur_event->is_a_rate ) {
569 cur_event->cycles += cycles;
570 if ( cycles >= MPX_MINCYC ) { /* Only update current rate on a decent slice */
571 cur_event->rate_estimate =
572 ( double ) counts[0] / ( double ) cycles;
573 }
574 cur_event->count_estimate +=
575 ( long long ) ( ( double ) total_cycles *
576 cur_event->rate_estimate );
577 MPXDBG("New estimate = %lld (%lld cycles * %lf rate)\n",
578 cur_event->count_estimate,total_cycles,
579 cur_event->rate_estimate);
580 } else {
581 /* Make sure we ran long enough to get a useful measurement (otherwise
582 * potentially inaccurate rate measurements get averaged in with
583 * the same weight as longer, more accurate ones.)
584 */
585 if ( cycles >= MPX_MINCYC ) {
586 cur_event->cycles += 1;
587 } else {
588 cur_event->count -= counts[0];
589 }
590 }
591 } else {
592 MPXDBG( "%lx retval = %d, skipping\n", me->tid, retval );
593 MPXDBG( "%lx value = %lld cycles = %lld\n\n",
594 me->tid, cur_event->count, cur_event->cycles );
595 }
596
597 MPXDBG
598 ( "tid(%lx): value = %lld (%lld) cycles = %lld (%lld) rate = %lf\n\n",
599 me->tid, cur_event->count, cur_event->count_estimate,
600 cur_event->cycles, total_cycles, cur_event->rate_estimate );
601 /* Start running the next event; look for the
602 * next one in the list that's marked active.
603 * It's possible that this event is the only
604 * one active; if so, we should restart it,
605 * but only after considerating all the other
606 * possible events.
607 */
608 if ( ( retval != PAPI_OK ) ||
609 ( ( retval == PAPI_OK ) && ( cycles >= MPX_MINCYC ) ) ) {
610 for ( mev =
611 ( cur_event->next == NULL ) ? head : cur_event->next;
612 mev != cur_event;
613 mev = ( mev->next == NULL ) ? head : mev->next ) {
614 /* Found the next one to start */
615 if ( mev->active ) {
616 me->cur_event = mev;
617 break;
618 }
619 }
620 }
621
622 if ( me->cur_event->active ) {
624 }
625#ifdef MPX_DEBUG_OVERHEAD
626 didwork = 1;
627#endif
628 }
629 }
630#ifdef ANY_THREAD_GETS_SIGNAL
631 else {
632 Threadlist *t;
633 for ( t = tlist; t != NULL; t = t->next ) {
634 if ( ( t->tid == _papi_hwi_thread_id_fn( ) ) ||
635 ( t->head == NULL ) )
636 continue;
637 MPXDBG( "forwarding signal to thread %lx\n", t->tid );
638 retval = ( *_papi_hwi_thread_kill_fn ) ( t->tid, _papi_os_info.itimer_sig );
639 if ( retval != 0 ) {
640 MPXDBG( "forwarding signal to thread %lx returned %d\n",
641 t->tid, retval );
642 }
643 }
644 }
645#endif
646
647#ifdef REGENERATE
648 /* Regenerating the signal each time through has the
649 * disadvantage that if any thread ever drops a signal,
650 * the whole time slicing system will stop. Using
651 * an automatically regenerated signal may have the
652 * disadvantage that a new signal can arrive very
653 * soon after all the threads have finished handling
654 * the last one, so the interval may be too small for
655 * accurate data collection. However, using the
656 * MIN_CYCLES check above should alleviate this.
657 */
658 /* Reset the timer once all threads have responded */
659 if ( lastthread ) {
660 retval = setitimer( _papi_os_info.itimer_num, &itime, NULL );
661 assert( retval == 0 );
662#ifdef MPX_DEBUG_TIMER
663 MPXDBG( "timer restarted by %lx\n", me->tid );
664#endif
665 }
666#endif
667
668#ifdef MPX_DEBUG_OVERHEAD
669 usec = _papi_hwd_get_real_usec( ) - usec;
670 MPXDBG( "handler %#x did %swork in %lld usec\n",
671 self, ( didwork ? "" : "no " ), usec );
672#endif
673}
674
675int
676MPX_add_events( MPX_EventSet ** mpx_events, int *event_list, int num_events,
677 int domain, int granularity )
678{
679 int i, retval = PAPI_OK;
680
681 for ( i = 0; i < num_events; i++ ) {
682 retval =
683 mpx_add_event( mpx_events, event_list[i], domain, granularity );
684
685 if ( retval != PAPI_OK )
686 return ( retval );
687 }
688 return ( retval );
689}
690
691int
692MPX_start( MPX_EventSet * mpx_events )
693{
694 int retval = PAPI_OK;
695 int i;
696 long long values[2];
697 long long cycles_this_slice, current_thread_mpx_c = 0;
698 Threadlist *t;
699
700 t = mpx_events->mythr;
701
702 mpx_hold( );
703
704 if ( t->cur_event && t->cur_event->active ) {
705 current_thread_mpx_c += t->total_c;
707 assert( retval == PAPI_OK );
708 if ( retval == PAPI_OK ) {
709 cycles_this_slice = ( t->cur_event->pi.event_type == SCALE_EVENT )
710 ? values[0] : values[1];
711 } else {
712 values[0] = values[1] = 0;
713 cycles_this_slice = 0;
714 }
715
716 } else {
717 values[0] = values[1] = 0;
718 cycles_this_slice = 0;
719 }
720
721 /* Make all events in this set active, and for those
722 * already active, get the current count and cycles.
723 */
724 for ( i = 0; i < mpx_events->num_events; i++ ) {
725 MasterEvent *mev = mpx_events->mev[i];
726
727 if ( mev->active++ ) {
728 mpx_events->start_values[i] = mev->count_estimate;
729 mpx_events->start_hc[i] = mev->cycles;
730
731 /* If this happens to be the currently-running
732 * event, add in the current amounts from this
733 * time slice. If it's a rate, though, don't
734 * bother since the event might not have been
735 * running long enough to get an accurate count.
736 */
737 if ( t->cur_event && !( t->cur_event->is_a_rate ) ) {
738#ifdef MPX_NONDECR_HYBRID
739 if ( mev != t->cur_event ) { /* This event is not running this slice */
740 mpx_events->start_values[i] +=
741 ( long long ) ( mev->rate_estimate *
742 ( cycles_this_slice + t->total_c -
743 mev->prev_total_c ) );
744 } else { /* The event is running, use current value + estimate */
745 if ( cycles_this_slice >= MPX_MINCYC )
746 mpx_events->start_values[i] += values[0] + ( long long )
747 ( ( values[0] / ( double ) cycles_this_slice ) *
748 ( t->total_c - mev->prev_total_c ) );
749 else /* Use previous rate if the event has run too short time */
750 mpx_events->start_values[i] += values[0] + ( long long )
751 ( mev->rate_estimate *
752 ( t->total_c - mev->prev_total_c ) );
753 }
754#endif
755 } else {
756 mpx_events->start_values[i] = mev->count;
757 }
758 } else {
759 /* The = 0 isn't actually necessary; we only need
760 * to sync up the mpx event to the master event,
761 * but it seems safe to set the mev to 0 here, and
762 * that gives us a change to avoid (very unlikely)
763 * rollover problems for events used repeatedly over
764 * a long time.
765 */
766 mpx_events->start_values[i] = 0;
767 mpx_events->stop_values[i] = 0;
768 mpx_events->start_hc[i] = mev->cycles = 0;
769 mev->count_estimate = 0;
770 mev->rate_estimate = 0.0;
771 mev->prev_total_c = current_thread_mpx_c;
772 mev->count = 0;
773 }
774 /* Adjust start value to include events and cycles
775 * counted previously for this event set.
776 */
777 }
778
779 mpx_events->status = MPX_RUNNING;
780
781 /* Start first counter if one isn't already running */
782 if ( t->cur_event == NULL ) {
783 /* Pick an events at random to start. */
784 int index = ( rand_r( &randomseed ) % mpx_events->num_events );
785 t->cur_event = mpx_events->mev[index];
786 t->total_c = 0;
787 t->cur_event->prev_total_c = 0;
788 mpx_events->start_c = 0;
789 retval = PAPI_start( mpx_events->mev[index]->papi_event );
790 assert( retval == PAPI_OK );
791 } else {
792 /* If an event is already running, record the starting cycle
793 * count for mpx_events, which is the accumlated cycle count
794 * for the master event set plus the cycles for this time
795 * slice.
796 */
797 mpx_events->start_c = t->total_c + cycles_this_slice;
798 }
799
800#if defined(DEBUG)
801 if ( ISLEVEL( DEBUG_MULTIPLEX ) ) {
802 MPXDBG( "%s:%d:: start_c=%lld thread->total_c=%lld\n", __FILE__,
803 __LINE__, mpx_events->start_c, t->total_c );
804 for ( i = 0; i < mpx_events->num_events; i++ ) {
805 MPXDBG
806 ( "%s:%d:: start_values[%d]=%lld estimate=%lld rate=%g last active=%lld\n",
807 __FILE__, __LINE__, i, mpx_events->start_values[i],
808 mpx_events->mev[i]->count_estimate,
809 mpx_events->mev[i]->rate_estimate,
810 mpx_events->mev[i]->prev_total_c );
811 }
812 }
813#endif
814
815 mpx_release( );
816
818
819 return retval;
820}
821
822int
823MPX_read( MPX_EventSet * mpx_events, long long *values, int called_by_stop )
824{
825 int i;
826 int retval;
827 long long last_value[2];
828 long long cycles_this_slice = 0;
829 MasterEvent *cur_event;
830 Threadlist *thread_data;
831
832 if ( mpx_events->status == MPX_RUNNING ) {
833
834 /* Hold timer interrupts while we read values */
835 mpx_hold( );
836
837 thread_data = mpx_events->mythr;
838 cur_event = thread_data->cur_event;
839
840 retval = PAPI_read( cur_event->papi_event, last_value );
841 if ( retval != PAPI_OK )
842 return retval;
843
844 cycles_this_slice = ( cur_event->pi.event_type == SCALE_EVENT )
845 ? last_value[0] : last_value[1];
846
847 /* Save the current counter values and get
848 * the lastest data for the current event
849 */
850 for ( i = 0; i < mpx_events->num_events; i++ ) {
851 MasterEvent *mev = mpx_events->mev[i];
852
853 if ( !( mev->is_a_rate ) ) {
854 mpx_events->stop_values[i] = mev->count_estimate;
855 }
856 else {
857 mpx_events->stop_values[i] = mev->count;
858 }
859#ifdef MPX_NONDECR_HYBRID
860 /* If we are called from MPX_stop() then */
861 /* adjust the final values based on the */
862 /* cycles elapsed since the last read */
863 /* otherwise, don't do this as it can cause */
864 /* decreasing values if read is called again */
865 /* before another sample happens. */
866
867 if (called_by_stop) {
868
869 /* Extrapolate data up to the current time
870 * only if it's not a rate measurement
871 */
872 if ( !( mev->is_a_rate ) ) {
873 if ( mev != thread_data->cur_event ) {
874 mpx_events->stop_values[i] +=
875 ( long long ) ( mev->rate_estimate *
876 ( cycles_this_slice +
877 thread_data->total_c -
878 mev->prev_total_c ) );
879 MPXDBG
880 ( "%s:%d:: Inactive %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
881 __FILE__, __LINE__, i, mpx_events->stop_values[i],
882 mev->count_estimate, mev->rate_estimate,
883 cycles_this_slice + thread_data->total_c -
884 mev->prev_total_c );
885 } else {
886 mpx_events->stop_values[i] += last_value[0] +
887 ( long long ) ( mev->rate_estimate *
888 ( thread_data->total_c -
889 mev->prev_total_c ) );
890 MPXDBG
891 ( "%s:%d:: -Active- %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
892 __FILE__, __LINE__, i, mpx_events->stop_values[i],
893 mev->count_estimate, mev->rate_estimate,
894 thread_data->total_c - mev->prev_total_c );
895 }
896 }
897 }
898#endif
899 }
900
901 mpx_events->stop_c = thread_data->total_c + cycles_this_slice;
902
903 /* Restore the interrupt */
904 mpx_release( );
905 }
906
907 /* Store the values in user array. */
908 for ( i = 0; i < mpx_events->num_events; i++ ) {
909 MasterEvent *mev = mpx_events->mev[i];
910 long long elapsed_slices = 0;
911 long long elapsed_values = mpx_events->stop_values[i]
912 - mpx_events->start_values[i];
913
914 /* For rates, cycles contains the number of measurements,
915 * not the number of cycles, so just divide to compute
916 * an average value. This assumes that the rate was
917 * constant over the whole measurement period.
918 */
919 values[i] = elapsed_values;
920 if ( mev->is_a_rate ) {
921 /* Handler counts */
922 elapsed_slices = mev->cycles - mpx_events->start_hc[i];
923 values[i] =
924 elapsed_slices ? ( elapsed_values / elapsed_slices ) : 0;
925 }
926 MPXDBG( "%s:%d:: event %d, values=%lld ( %lld - %lld), cycles %lld\n",
927 __FILE__, __LINE__, i,
928 elapsed_values,
929 mpx_events->stop_values[i], mpx_events->start_values[i],
930 mev->is_a_rate ? elapsed_slices : 0 );
931 }
932
933 return PAPI_OK;
934}
935
936int
937MPX_reset( MPX_EventSet * mpx_events )
938{
939 int i, retval;
941
942 /* Get the current values from MPX_read */
943 retval = MPX_read( mpx_events, values, 0 );
944 if ( retval != PAPI_OK )
945 return retval;
946
947 /* Disable timer interrupt */
948 mpx_hold( );
949
950 /* Make counters read zero by setting the start values
951 * to the current counter values.
952 */
953 for ( i = 0; i < mpx_events->num_events; i++ ) {
954 MasterEvent *mev = mpx_events->mev[i];
955
956 if ( mev->is_a_rate ) {
957 mpx_events->start_values[i] = mev->count;
958 } else {
959 mpx_events->start_values[i] += values[i];
960 }
961 mpx_events->start_hc[i] = mev->cycles;
962 }
963
964 /* Set the start time for this set to the current cycle count */
965 mpx_events->start_c = mpx_events->stop_c;
966
967 /* Restart the interrupt */
968 mpx_release( );
969
970 return PAPI_OK;
971}
972
973int
974MPX_stop( MPX_EventSet * mpx_events, long long *values )
975{
976 int i, cur_mpx_event;
977 int retval = PAPI_OK;
978 long long dummy_value[2];
979 long long dummy_mpx_values[PAPI_MAX_SW_MPX_EVENTS];
980 /* long long cycles_this_slice, total_cycles; */
981 MasterEvent *cur_event = NULL, *head;
982 Threadlist *thr = NULL;
983
984 if ( mpx_events == NULL )
985 return PAPI_EINVAL;
986 if ( mpx_events->status != MPX_RUNNING )
987 return PAPI_ENOTRUN;
988
989 /* Read the counter values, this updates mpx_events->stop_values[] */
990 MPXDBG( "Start\n" );
991 if ( values == NULL )
992 retval = MPX_read( mpx_events, dummy_mpx_values, 1 );
993 else
994 retval = MPX_read( mpx_events, values, 1 );
995
996 /* Block timer interrupts while modifying active events */
997 mpx_hold( );
998
999 /* Get the master event list for this thread. */
1001 if (!head) {
1003 goto exit_mpx_stop;
1004 }
1005
1006 /* Get this threads data structure */
1007 thr = head->mythr;
1008 cur_event = thr->cur_event;
1009
1010 /* This would be a good spot to "hold" the counter and then restart
1011 * it at the end, but PAPI_start resets counters so it is not possible
1012 */
1013
1014 /* Run through all the events decrement their activity counters. */
1015 cur_mpx_event = -1;
1016 for ( i = 0; i < mpx_events->num_events; i++ ) {
1017 --mpx_events->mev[i]->active;
1018 if ( mpx_events->mev[i] == cur_event )
1019 cur_mpx_event = i;
1020 }
1021
1022 /* One event in this set is currently running, if this was the
1023 * last active event set using this event, we need to start the next
1024 * event if there still is one left in the queue
1025 */
1026 if ( cur_mpx_event > -1 ) {
1027 MasterEvent *tmp, *mev = mpx_events->mev[cur_mpx_event];
1028
1029 if ( mev->active == 0 ) {
1030 /* Event is now inactive; stop it
1031 * There is no need to update master event set
1032 * counters as this is the last active user
1033 */
1034 retval = PAPI_stop( mev->papi_event, dummy_value );
1035 mev->rate_estimate = 0.0;
1036
1037 /* Fall-back value if none is found */
1038 thr->cur_event = NULL;
1039 /* Now find a new cur_event */
1040 for ( tmp = ( cur_event->next == NULL ) ? head : cur_event->next;
1041 tmp != cur_event;
1042 tmp = ( tmp->next == NULL ) ? head : tmp->next ) {
1043 if ( tmp->active ) { /* Found the next one to start */
1044 thr->cur_event = tmp;
1045 break;
1046 }
1047 }
1048
1049 if ( thr->cur_event != NULL ) {
1051 assert( retval == PAPI_OK );
1052 } else {
1054 }
1055 }
1056 }
1057 mpx_events->status = MPX_STOPPED;
1058
1059exit_mpx_stop:
1060 MPXDBG( "End\n" );
1061
1062 /* Restore the timer (for other event sets that may be running) */
1063 mpx_release( );
1064
1065 return retval;
1066}
1067
1068int
1070{
1071#ifdef PTHREADS
1072 int retval;
1073#endif
1074
1075 if ( mpx_events == NULL )
1076 return PAPI_EINVAL;
1077
1078 if ( *mpx_events == NULL )
1079 return PAPI_OK;
1080
1081 if (( *mpx_events )->status == MPX_RUNNING )
1082 return PAPI_EINVAL;
1083
1084 mpx_hold( );
1085
1086 /* Remove master events from this event set and from
1087 * the master list, if necessary.
1088 */
1089 mpx_delete_events( *mpx_events );
1090
1091 mpx_release( );
1092
1093 /* Free all the memory */
1094
1095 papi_free( *mpx_events );
1096
1097 *mpx_events = NULL;
1098 return PAPI_OK;
1099}
1100
1101void
1103{
1104 MPXDBG( "%d\n", getpid( ) );
1107
1108 if ( tlist ) {
1109 Threadlist *next,*t=tlist;
1110
1111 while(t!=NULL) {
1112 next=t->next;
1113 papi_free( t );
1114 t = next;
1115 }
1116 tlist = NULL;
1117 }
1118}
1119
1120int
1122{
1123 /* Currently, there is only the need for one mpx check: if
1124 * running on POWER6/perfctr platform, the domain must
1125 * include user, kernel, and supervisor, since the scale
1126 * event uses the dedicated counter #6, PM_RUN_CYC, which
1127 * cannot be controlled on a domain level.
1128 */
1130
1131 if (ESI==NULL) return PAPI_EBUG;
1132
1133 if ( strstr( _papi_hwd[ESI->CmpIdx]->cmp_info.name, "perfctr.c" ) == NULL )
1134 return PAPI_OK;
1135
1136 if ( strcmp( _papi_hwi_system_info.hw_info.model_string, "POWER6" ) == 0 ) {
1137 unsigned int chk_domain =
1139
1140 if ( ( ESI->domain.domain & chk_domain ) != chk_domain ) {
1141 PAPIERROR
1142 ( "This platform requires PAPI_DOM_USER+PAPI_DOM_KERNEL+PAPI_DOM_SUPERVISOR\n"
1143 "to be set in the domain when using multiplexing. Instead, found %#x\n",
1144 ESI->domain.domain );
1145 return ( PAPI_EINVAL_DOM );
1146 }
1147 }
1148 return PAPI_OK;
1149}
1150
1151int
1152mpx_init( int interval_ns )
1153{
1154#if defined(PTHREADS) || defined(_POWER6)
1155 int retval;
1156#endif
1157
1158#ifdef _POWER6
1159 retval = PAPI_event_name_to_code( "PM_RUN_CYC", &_PNE_PM_RUN_CYC );
1160 if ( retval != PAPI_OK )
1161 return ( retval );
1162#endif
1163 tlist = NULL;
1164 mpx_hold( );
1166 mpx_init_timers( interval_ns / 1000 );
1167
1168 return ( PAPI_OK );
1169}
1170
1175static int
1176mpx_insert_events( MPX_EventSet *mpx_events, int *event_list,
1177 int num_events, int domain, int granularity )
1178{
1179 int i, retval = 0, num_events_success = 0;
1180 MasterEvent *mev;
1182 MasterEvent **head = &mpx_events->mythr->head;
1183
1184 MPXDBG("Inserting %p %d\n",mpx_events,mpx_events->num_events );
1185
1186 /* Make sure we don't overrun our buffers */
1187 if (mpx_events->num_events + num_events > PAPI_MAX_SW_MPX_EVENTS) {
1188 return PAPI_ECOUNT;
1189 }
1190
1191 /* For each event, see if there is already a corresponding
1192 * event in the master set for this thread. If not, add it.
1193 */
1194 for ( i = 0; i < num_events; i++ ) {
1195
1196 /* Look for a matching event in the master list */
1197 for( mev = *head; mev != NULL; mev = mev->next ) {
1198 if ( (mev->pi.event_type == event_list[i]) &&
1199 (mev->pi.domain == domain) &&
1200 (mev->pi.granularity == granularity ))
1201 break;
1202 }
1203
1204 /* No matching event in the list; add a new one */
1205 if ( mev == NULL ) {
1206 mev = (MasterEvent *) papi_malloc( sizeof ( MasterEvent ) );
1207 if ( mev == NULL ) {
1208 return PAPI_ENOMEM;
1209 }
1210
1211 mev->pi.event_type = event_list[i];
1212 mev->pi.domain = domain;
1213 mev->pi.granularity = granularity;
1214 mev->uses = mev->active = 0;
1215 mev->prev_total_c = mev->count = mev->cycles = 0;
1216 mev->rate_estimate = 0.0;
1217 mev->count_estimate = 0;
1218 mev->is_a_rate = 0;
1219 mev->papi_event = PAPI_NULL;
1220
1221 retval = PAPI_create_eventset( &( mev->papi_event ) );
1222 if ( retval != PAPI_OK ) {
1223 MPXDBG( "Event %d could not be counted.\n",
1224 event_list[i] );
1225 goto bail;
1226 }
1227
1228 retval = PAPI_add_event( mev->papi_event, event_list[i] );
1229 if ( retval != PAPI_OK ) {
1230 MPXDBG( "Event %d could not be counted.\n",
1231 event_list[i] );
1232 goto bail;
1233 }
1234
1235 /* Always count total cycles so we can scale results.
1236 * If user just requested cycles,
1237 * don't add that event again. */
1238
1239 if ( event_list[i] != SCALE_EVENT ) {
1241 if ( retval != PAPI_OK ) {
1242 MPXDBG( "Scale event could not be counted "
1243 "at the same time.\n" );
1244 goto bail;
1245 }
1246 }
1247
1248 /* Set the options for the event set */
1249 memset( &options, 0x0, sizeof ( options ) );
1250 options.domain.eventset = mev->papi_event;
1251 options.domain.domain = domain;
1253 if ( retval != PAPI_OK ) {
1254 MPXDBG( "PAPI_set_opt(PAPI_DOMAIN, ...) = %d\n",
1255 retval );
1256 goto bail;
1257 }
1258
1259 memset( &options, 0x0, sizeof ( options ) );
1260 options.granularity.eventset = mev->papi_event;
1261 options.granularity.granularity = granularity;
1263 if ( retval != PAPI_OK ) {
1264 if ( retval != PAPI_ECMP ) {
1265 /* ignore component errors because they typically mean
1266 "not supported by the component" */
1267 MPXDBG( "PAPI_set_opt(PAPI_GRANUL, ...) = %d\n",
1268 retval );
1269 goto bail;
1270 }
1271 }
1272
1273
1274 /* Chain the event set into the
1275 * master list of event sets used in
1276 * multiplexing. */
1277
1278 mev->next = *head;
1279 *head = mev;
1280
1281 }
1282
1283 /* If we created a new event set, or we found a matching
1284 * eventset already in the list, then add the pointer in
1285 * the master list to this threads list. Then we bump the
1286 * number of successfully added events. */
1287 MPXDBG("Inserting now %p %d\n",mpx_events,mpx_events->num_events );
1288
1289 mpx_events->mev[mpx_events->num_events + num_events_success] = mev;
1290 mpx_events->mev[mpx_events->num_events + num_events_success]->uses++;
1291 num_events_success++;
1292
1293 }
1294
1295 /* Always be sure the head master event points to the thread */
1296 if ( *head != NULL ) {
1297 ( *head )->mythr = mpx_events->mythr;
1298 }
1299 MPXDBG( "%d of %d events were added.\n", num_events_success, num_events );
1300 mpx_events->num_events += num_events_success;
1301 return ( PAPI_OK );
1302
1303 bail:
1304 /* If there is a current mev, it is currently not linked into the list
1305 * of multiplexing events, so we can just delete that
1306 */
1307 if ( mev && mev->papi_event ) {
1309 PAPIERROR("Cleanup eventset\n");
1310 }
1311 if (PAPI_destroy_eventset( &( mev->papi_event )) !=PAPI_OK) {
1312 PAPIERROR("Destroy eventset\n");
1313 }
1314 }
1315 if ( mev )
1316 papi_free( mev );
1317 mev = NULL;
1318
1319 /* Decrease the usage count of events */
1320 for ( i = 0; i < num_events_success; i++ ) {
1321 mpx_events->mev[mpx_events->num_events + i]->uses--;
1322 }
1323
1324 /* Run the garbage collector to remove unused events */
1325 if ( num_events_success )
1326 mpx_remove_unused( head );
1327
1328 return ( retval );
1329}
1330
1335static void
1337{
1338 int i;
1339 MasterEvent *mev;
1340
1341 /* First decrement the reference counter for each master
1342 * event in this event set, then see if the master events
1343 * can be deleted.
1344 */
1345 for ( i = 0; i < mpx_events->num_events; i++ ) {
1346 mev = mpx_events->mev[i];
1347 --mev->uses;
1348 mpx_events->mev[i] = NULL;
1349 /* If it's no longer used, it should not be active! */
1350 assert( mev->uses || !( mev->active ) );
1351 }
1352 mpx_events->num_events = 0;
1353 mpx_remove_unused( &mpx_events->mythr->head );
1354}
1355
1360static void
1362{
1363 int i;
1364 MasterEvent *mev;
1365
1366 /* First decrement the reference counter for each master
1367 * event in this event set, then see if the master events
1368 * can be deleted.
1369 */
1370 for ( i = 0; i < mpx_events->num_events; i++ ) {
1371 mev = mpx_events->mev[i];
1372 if ( mev->pi.event_type == Event ) {
1373 --mev->uses;
1374 mpx_events->num_events--;
1375 mpx_events->mev[i] = NULL;
1376 /* If it's no longer used, it should not be active! */
1377 assert( mev->uses || !( mev->active ) );
1378 break;
1379 }
1380 }
1381
1382 /* If we removed an event that is not last in the list we
1383 * need to compact the event list
1384 */
1385
1386 for ( ; i < mpx_events->num_events; i++ ) {
1387 mpx_events->mev[i] = mpx_events->mev[i + 1];
1388 mpx_events->start_values[i] = mpx_events->start_values[i + 1];
1389 mpx_events->stop_values[i] = mpx_events->stop_values[i + 1];
1390 mpx_events->start_hc[i] = mpx_events->start_hc[i + 1];
1391 }
1392 mpx_events->mev[i] = NULL;
1393
1394 mpx_remove_unused( &mpx_events->mythr->head );
1395
1396}
1397
1402static void
1404{
1405 MasterEvent *mev, *lastmev = NULL, *nextmev;
1406 Threadlist *thr = ( *head == NULL ) ? NULL : ( *head )->mythr;
1407 int retval;
1408
1409 /* Clean up and remove unused master events. */
1410 for ( mev = *head; mev != NULL; mev = nextmev ) {
1411 nextmev = mev->next; /* get link before mev is freed */
1412 if ( !mev->uses ) {
1413 if ( lastmev == NULL ) { /* this was the head event */
1414 *head = nextmev;
1415 } else {
1416 lastmev->next = nextmev;
1417 }
1420 if (retval!=PAPI_OK) PAPIERROR("Error destroying event\n");
1421 papi_free( mev );
1422 } else {
1423 lastmev = mev;
1424 }
1425 }
1426
1427 /* Always be sure the head master event points to the thread */
1428 if ( *head != NULL ) {
1429 ( *head )->mythr = thr;
1430 }
1431}
double tmp
int i
PAPI_os_info_t _papi_os_info
Definition: aix.c:1210
int errno
static int Event[MAX_EVENTS]
add PAPI preset or native hardware event to an event set
Empty and destroy an EventSet.
Create a new empty PAPI EventSet.
Empty and destroy an EventSet.
Convert a name to a numeric hardware event code.
get real time counter value in microseconds
Read hardware counters from an event set.
Set PAPI library or event set options.
Start counting hardware events in an event set.
Stop counting hardware events in an event set.
struct papi_vectors * _papi_hwd[]
#define PAPI_DOM_USER
Definition: f90papi.h:174
#define PAPI_EBUG
Definition: f90papi.h:176
#define PAPI_OK
Definition: f90papi.h:73
#define PAPI_NULL
Definition: f90papi.h:78
#define PAPI_GRANUL
Definition: f90papi.h:179
#define PAPI_DOM_KERNEL
Definition: f90papi.h:254
#define PAPI_DOM_SUPERVISOR
Definition: f90papi.h:109
#define PAPI_ECOUNT
Definition: f90papi.h:195
#define PAPI_EINVAL
Definition: f90papi.h:115
#define PAPI_EINVAL_DOM
Definition: f90papi.h:175
#define PAPI_DOMAIN
Definition: f90papi.h:159
#define PAPI_ESYS
Definition: f90papi.h:136
#define PAPI_ECMP
Definition: f90papi.h:214
#define PAPI_ENOMEM
Definition: f90papi.h:16
#define PAPI_ENOTRUN
Definition: f90papi.h:146
static int EventSet
Definition: init_fini.c:8
static long long values[NUM_EVENTS]
Definition: init_fini.c:10
static int num_events
Return codes and api definitions.
unsigned long int(* _papi_hwi_thread_id_fn)(void)
Definition: threads.c:42
#define ISLEVEL(a)
Definition: papi_debug.h:55
#define DEBUG_MULTIPLEX
Definition: papi_debug.h:31
#define MPXDBG(format, args...)
Definition: papi_debug.h:68
__sighandler_t signal(int __sig, __sighandler_t __handler) __attribute__((__nothrow__
unsigned int pthread_key_t
int sigaction(int __sig, const struct sigaction *__restrict __act, struct sigaction *__restrict __oact) __attribute__((__nothrow__
int pthread_once_t
int pthread_kill(pthread_t __threadid, int __signo) __attribute__((__nothrow__
int sigprocmask(int __how, const sigset_t *__restrict __set, sigset_t *__restrict __oset) __attribute__((__nothrow__
void PAPIERROR(char *format,...)
EventSetInfo_t * _papi_hwi_lookup_EventSet(int eventset)
#define inline_static
#define MULTIPLEX_LOCK
Definition: papi_internal.h:86
#define papi_free(a)
Definition: papi_memory.h:35
#define papi_malloc(a)
Definition: papi_memory.h:34
static options_t options
papi_mdi_t _papi_hwi_system_info
Definition: papi_internal.c:56
long long int long long
Definition: sde_internal.h:85
static int pid
EventSetDomainInfo_t domain
long long start_c
Definition: sw_multiplex.h:25
MPX_status status
Definition: sw_multiplex.h:17
struct _masterevent * mev[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:21
long long stop_c
Definition: sw_multiplex.h:25
long long stop_values[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:27
long long start_values[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:26
long long start_hc[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:28
struct _threadlist * mythr
Definition: sw_multiplex.h:19
struct _threadlist * mythr
struct _masterevent * next
long long prev_total_c
double rate_estimate
long long count
long long count_estimate
long long cycles
PapiInfo pi
char model_string[PAPI_MAX_STR_LEN]
Definition: papi.h:784
int granularity
long long event_type
struct _threadlist * next
MasterEvent * head
unsigned long int tid
MasterEvent * cur_event
long long total_c
PAPI_hw_info_t hw_info
static int mpx_insert_events(MPX_EventSet *, int *event_list, int num_events, int domain, int granularity)
inline_static void mpx_hold(void)
Definition: sw_multiplex.c:180
static void mpx_delete_one_event(MPX_EventSet *mpx_events, int Event)
static void mpx_handler(int signal)
Definition: sw_multiplex.c:445
static int mpx_startup_itimer(void)
Definition: sw_multiplex.c:222
static void mpx_restore_signal(void)
Definition: sw_multiplex.c:247
static const struct itimerval itimestop
Definition: sw_multiplex.c:153
int mpx_remove_event(MPX_EventSet **mpx_events, int EventCode)
Definition: sw_multiplex.c:418
static Threadlist * tlist
Definition: sw_multiplex.c:140
static struct itimerval itime
Definition: sw_multiplex.c:152
static MPX_EventSet * mpx_malloc(Threadlist *t)
Definition: sw_multiplex.c:292
void MPX_shutdown(void)
int mpx_check(int EventSet)
int MPX_read(MPX_EventSet *mpx_events, long long *values, int called_by_stop)
Definition: sw_multiplex.c:823
static struct sigaction oaction
Definition: sw_multiplex.c:154
inline_static void mpx_release(void)
Definition: sw_multiplex.c:187
int mpx_init(int interval_ns)
static void mpx_shutdown_itimer(void)
Definition: sw_multiplex.c:257
static void mpx_delete_events(MPX_EventSet *)
int MPX_add_events(MPX_EventSet **mpx_events, int *event_list, int num_events, int domain, int granularity)
Definition: sw_multiplex.c:676
int mpx_add_event(MPX_EventSet **mpx_events, int EventCode, int domain, int granularity)
Definition: sw_multiplex.c:305
int MPX_start(MPX_EventSet *mpx_events)
Definition: sw_multiplex.c:692
static MasterEvent * get_my_threads_master_event_list(void)
Definition: sw_multiplex.c:268
int MPX_reset(MPX_EventSet *mpx_events)
Definition: sw_multiplex.c:937
static unsigned int randomseed
Definition: sw_multiplex.c:141
static void mpx_remove_unused(MasterEvent **head)
int MPX_stop(MPX_EventSet *mpx_events, long long *values)
Definition: sw_multiplex.c:974
#define SCALE_EVENT
Definition: sw_multiplex.c:440
#define MPX_MINCYC
Definition: sw_multiplex.c:134
static sigset_t sigreset
Definition: sw_multiplex.c:151
static void mpx_init_timers(int interval)
Definition: sw_multiplex.c:194
int MPX_cleanup(MPX_EventSet **mpx_events)
#define PAPI_MAX_SW_MPX_EVENTS
Definition: sw_multiplex.h:4
@ MPX_RUNNING
Definition: sw_multiplex.h:10
@ MPX_STOPPED
Definition: sw_multiplex.h:10
inline_static int _papi_hwi_lock(int lck)
Definition: threads.h:69
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:83
A pointer to the following is passed to PAPI_set/get_opt()
Definition: papi.h:843
int retval
Definition: zero_fork.c:53