PAPI  5.3.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 occured 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 /*
63 Portions of the following code are
64 Copyright (c) 2009, Lawrence Livermore National Security, LLC.
65 Produced at the Lawrence Livermore National Laboratory
66 Written by John May, johnmay@llnl.gov
67 LLNL-CODE-421124
68 All rights reserved.
69 
70 Redistribution and use in source and binary forms, with or
71 without modification, are permitted provided that the following
72 conditions are met:
73 
74  Redistributions of source code must retain the above copyright
75 notice, this list of conditions and the disclaimer below.
76 
77  Redistributions in binary form must reproduce the above
78 copyright notice, this list of conditions and the disclaimer (as
79 noted below) in the documentation and/or other materials provided
80 with the distribution.
81 
82  Neither the name of the LLNS/LLNL nor the names of its
83 contributors may be used to endorse or promote products derived
84 from this software without specific prior written permission.
85 
86 
87 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
88 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
89 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
90 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
91 DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL
92 SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE
93 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
94 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
95 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
96 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
97 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
98 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
99 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
100 OF SUCH DAMAGE.
101 
102 
103 Additional BSD Notice
104 
105 1. This notice is required to be provided under our contract with
106 the U.S. Department of Energy (DOE). This work was produced at
107 Lawrence Livermore National Laboratory under Contract No.
108 DE-AC52-07NA27344 with the DOE.
109 
110 2. Neither the United States Government nor Lawrence Livermore
111 National Security, LLC nor any of their employees, makes any
112 warranty, express or implied, or assumes any liability or
113 responsibility for the accuracy, completeness, or usefulness of
114 any information, apparatus, product, or process disclosed, or
115 represents that its use would not infringe privately-owned
116 rights.
117 
118 3. Also, reference herein to any specific commercial products,
119 process, or services by trade name, trademark, manufacturer or
120 otherwise does not necessarily constitute or imply its
121 endorsement, recommendation, or favoring by the United States
122 Government or Lawrence Livermore National Security, LLC. The
123 views and opinions of authors expressed herein do not necessarily
124 state or reflect those of the United States Government or
125 Lawrence Livermore National Security, LLC, and shall not be used
126 for 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 
140 static Threadlist *tlist = NULL;
141 static 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 
151 static sigset_t sigreset;
152 static struct itimerval itime;
153 static const struct itimerval itimestop = { {0, 0}, {0, 0} };
154 static struct sigaction oaction;
155 
156 /* END Globals */
157 
158 #ifdef PTHREADS
159 
160 static int threads_responding = 0;
161 
162 static pthread_once_t mpx_once_control = PTHREAD_ONCE_INIT;
163 static pthread_mutex_t tlistlock;
164 static pthread_key_t master_events_key;
165 static pthread_key_t thread_record_key;
166 static MasterEvent *global_master_events;
167 static void *global_process_record;
168 #endif
169 
170 /* Forward prototypes */
171 
172 static void mpx_remove_unused( MasterEvent ** head );
173 static void mpx_delete_events( MPX_EventSet * );
174 static void mpx_delete_one_event( MPX_EventSet * mpx_events, int Event );
175 static int mpx_insert_events( MPX_EventSet *, int *event_list, int num_events,
176  int domain, int granularity );
177 static void mpx_handler( int signal );
178 
179 inline_static void
180 mpx_hold( void )
181 {
182  sigprocmask( SIG_BLOCK, &sigreset, NULL );
183  MPXDBG( "signal held\n" );
184 }
185 
186 inline_static void
187 mpx_release( void )
188 {
189  MPXDBG( "signal released\n" );
190  sigprocmask( SIG_UNBLOCK, &sigreset, NULL );
191 }
192 
193 static void
194 mpx_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 
221 static 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 ) {
239  sigaction( _papi_os_info.itimer_sig, &oaction, NULL );
240  PAPIERROR( "setitimer start errno %d", errno );
241  return PAPI_ESYS;
242  }
243  return ( PAPI_OK );
244 }
245 
246 static 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 
256 static 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 
267 static 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 
291 static 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 
304 int
305 mpx_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 
333  if ( _papi_hwi_thread_id_fn ) {
334  MPXDBG( "New thread at %p\n", t );
335  t->tid = _papi_hwi_thread_id_fn( );
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 0x%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 
417 int
418 mpx_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
428 static 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 */
437 int _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 
444 static 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;
512  retval = pthread_kill( t->thr, _papi_os_info.itimer_sig );
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 ) {
623  retval = PAPI_start( me->cur_event->papi_event );
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 
675 int
676 MPX_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 
691 int
692 MPX_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;
706  retval = PAPI_read( t->cur_event->papi_event, values );
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 
817  retval = mpx_startup_itimer( );
818 
819  return retval;
820 }
821 
822 int
823 MPX_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 
936 int
937 MPX_reset( MPX_EventSet * mpx_events )
938 {
939  int i, retval;
940  long long values[PAPI_MAX_SW_MPX_EVENTS];
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 
973 int
974 MPX_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) {
1002  retval=PAPI_EBUG;
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 ) {
1050  retval = PAPI_start( thr->cur_event->papi_event );
1051  assert( retval == PAPI_OK );
1052  } else {
1054  }
1055  }
1056  }
1057  mpx_events->status = MPX_STOPPED;
1058 
1059 exit_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 
1068 int
1069 MPX_cleanup( MPX_EventSet ** mpx_events )
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 
1101 void
1103 {
1104  MPXDBG( "%d\n", getpid( ) );
1106  mpx_restore_signal( );
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 
1120 int
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  */
1129  EventSetInfo_t *ESI = _papi_hwi_lookup_EventSet( EventSet );
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  if ( ESI == NULL )
1140  return ( PAPI_ENOEVST );
1141 
1142  if ( ( ESI->domain.domain & chk_domain ) != chk_domain ) {
1143  PAPIERROR
1144  ( "This platform requires PAPI_DOM_USER+PAPI_DOM_KERNEL+PAPI_DOM_SUPERVISOR\n"
1145  "to be set in the domain when using multiplexing. Instead, found %#x\n",
1146  ESI->domain.domain );
1147  return ( PAPI_EINVAL_DOM );
1148  }
1149  }
1150  return PAPI_OK;
1151 }
1152 
1153 int
1154 mpx_init( int interval_ns )
1155 {
1156 #if defined(PTHREADS) || defined(_POWER6)
1157  int retval;
1158 #endif
1159 
1160 #ifdef _POWER6
1161  retval = PAPI_event_name_to_code( "PM_RUN_CYC", &_PNE_PM_RUN_CYC );
1162  if ( retval != PAPI_OK )
1163  return ( retval );
1164 #endif
1165  tlist = NULL;
1166  mpx_hold( );
1168  mpx_init_timers( interval_ns / 1000 );
1169 
1170  return ( PAPI_OK );
1171 }
1172 
1177 static int
1178 mpx_insert_events( MPX_EventSet *mpx_events, int *event_list,
1179  int num_events, int domain, int granularity )
1180 {
1181  int i, retval = 0, num_events_success = 0;
1182  MasterEvent *mev;
1184  MasterEvent **head = &mpx_events->mythr->head;
1185 
1186  MPXDBG("Inserting %p %d\n",mpx_events,mpx_events->num_events );
1187 
1188  /* Make sure we don't overrun our buffers */
1189  if (mpx_events->num_events + num_events > PAPI_MAX_SW_MPX_EVENTS) {
1190  return PAPI_ECOUNT;
1191  }
1192 
1193  /* For each event, see if there is already a corresponding
1194  * event in the master set for this thread. If not, add it.
1195  */
1196  for ( i = 0; i < num_events; i++ ) {
1197 
1198  /* Look for a matching event in the master list */
1199  for( mev = *head; mev != NULL; mev = mev->next ) {
1200  if ( (mev->pi.event_type == event_list[i]) &&
1201  (mev->pi.domain == domain) &&
1202  (mev->pi.granularity == granularity ))
1203  break;
1204  }
1205 
1206  /* No matching event in the list; add a new one */
1207  if ( mev == NULL ) {
1208  mev = (MasterEvent *) papi_malloc( sizeof ( MasterEvent ) );
1209  if ( mev == NULL ) {
1210  return PAPI_ENOMEM;
1211  }
1212 
1213  mev->pi.event_type = event_list[i];
1214  mev->pi.domain = domain;
1215  mev->pi.granularity = granularity;
1216  mev->uses = mev->active = 0;
1217  mev->prev_total_c = mev->count = mev->cycles = 0;
1218  mev->rate_estimate = 0.0;
1219  mev->count_estimate = 0;
1220  mev->is_a_rate = 0;
1221  mev->papi_event = PAPI_NULL;
1222 
1223  retval = PAPI_create_eventset( &( mev->papi_event ) );
1224  if ( retval != PAPI_OK ) {
1225  MPXDBG( "Event %d could not be counted.\n",
1226  event_list[i] );
1227  goto bail;
1228  }
1229 
1230  retval = PAPI_add_event( mev->papi_event, event_list[i] );
1231  if ( retval != PAPI_OK ) {
1232  MPXDBG( "Event %d could not be counted.\n",
1233  event_list[i] );
1234  goto bail;
1235  }
1236 
1237  /* Always count total cycles so we can scale results.
1238  * If user just requested cycles,
1239  * don't add that event again. */
1240 
1241  if ( event_list[i] != SCALE_EVENT ) {
1242  retval = PAPI_add_event( mev->papi_event, SCALE_EVENT );
1243  if ( retval != PAPI_OK ) {
1244  MPXDBG( "Scale event could not be counted "
1245  "at the same time.\n" );
1246  goto bail;
1247  }
1248  }
1249 
1250  /* Set the options for the event set */
1251  memset( &options, 0x0, sizeof ( options ) );
1252  options.domain.eventset = mev->papi_event;
1253  options.domain.domain = domain;
1254  retval = PAPI_set_opt( PAPI_DOMAIN, &options );
1255  if ( retval != PAPI_OK ) {
1256  MPXDBG( "PAPI_set_opt(PAPI_DOMAIN, ...) = %d\n",
1257  retval );
1258  goto bail;
1259  }
1260 
1261  memset( &options, 0x0, sizeof ( options ) );
1262  options.granularity.eventset = mev->papi_event;
1263  options.granularity.granularity = granularity;
1264  retval = PAPI_set_opt( PAPI_GRANUL, &options );
1265  if ( retval != PAPI_OK ) {
1266  if ( retval != PAPI_ECMP ) {
1267  /* ignore component errors because they typically mean
1268  "not supported by the component" */
1269  MPXDBG( "PAPI_set_opt(PAPI_GRANUL, ...) = %d\n",
1270  retval );
1271  goto bail;
1272  }
1273  }
1274 
1275 
1276  /* Chain the event set into the
1277  * master list of event sets used in
1278  * multiplexing. */
1279 
1280  mev->next = *head;
1281  *head = mev;
1282 
1283  }
1284 
1285  /* If we created a new event set, or we found a matching
1286  * eventset already in the list, then add the pointer in
1287  * the master list to this threads list. Then we bump the
1288  * number of successfully added events. */
1289  MPXDBG("Inserting now %p %d\n",mpx_events,mpx_events->num_events );
1290 
1291  mpx_events->mev[mpx_events->num_events + num_events_success] = mev;
1292  mpx_events->mev[mpx_events->num_events + num_events_success]->uses++;
1293  num_events_success++;
1294 
1295  }
1296 
1297  /* Always be sure the head master event points to the thread */
1298  if ( *head != NULL ) {
1299  ( *head )->mythr = mpx_events->mythr;
1300  }
1301  MPXDBG( "%d of %d events were added.\n", num_events_success, num_events );
1302  mpx_events->num_events += num_events_success;
1303  return ( PAPI_OK );
1304 
1305  bail:
1306  /* If there is a current mev, it is currently not linked into the list
1307  * of multiplexing events, so we can just delete that
1308  */
1309  if ( mev && mev->papi_event ) {
1310  if (PAPI_cleanup_eventset( mev->papi_event )!=PAPI_OK) {
1311  PAPIERROR("Cleanup eventset\n");
1312  }
1313  if (PAPI_destroy_eventset( &( mev->papi_event )) !=PAPI_OK) {
1314  PAPIERROR("Destory eventset\n");
1315  }
1316  }
1317  if ( mev )
1318  papi_free( mev );
1319  mev = NULL;
1320 
1321  /* Decrease the usage count of events */
1322  for ( i = 0; i < num_events_success; i++ ) {
1323  mpx_events->mev[mpx_events->num_events + i]->uses--;
1324  }
1325 
1326  /* Run the garbage collector to remove unused events */
1327  if ( num_events_success )
1328  mpx_remove_unused( head );
1329 
1330  return ( retval );
1331 }
1332 
1337 static void
1339 {
1340  int i;
1341  MasterEvent *mev;
1342 
1343  /* First decrement the reference counter for each master
1344  * event in this event set, then see if the master events
1345  * can be deleted.
1346  */
1347  for ( i = 0; i < mpx_events->num_events; i++ ) {
1348  mev = mpx_events->mev[i];
1349  --mev->uses;
1350  mpx_events->mev[i] = NULL;
1351  /* If it's no longer used, it should not be active! */
1352  assert( mev->uses || !( mev->active ) );
1353  }
1354  mpx_events->num_events = 0;
1355  mpx_remove_unused( &mpx_events->mythr->head );
1356 }
1357 
1362 static void
1364 {
1365  int i;
1366  MasterEvent *mev;
1367 
1368  /* First decrement the reference counter for each master
1369  * event in this event set, then see if the master events
1370  * can be deleted.
1371  */
1372  for ( i = 0; i < mpx_events->num_events; i++ ) {
1373  mev = mpx_events->mev[i];
1374  if ( mev->pi.event_type == Event ) {
1375  --mev->uses;
1376  mpx_events->num_events--;
1377  mpx_events->mev[i] = NULL;
1378  /* If it's no longer used, it should not be active! */
1379  assert( mev->uses || !( mev->active ) );
1380  break;
1381  }
1382  }
1383 
1384  /* If we removed an event that is not last in the list we
1385  * need to compact the event list
1386  */
1387 
1388  for ( ; i < mpx_events->num_events; i++ ) {
1389  mpx_events->mev[i] = mpx_events->mev[i + 1];
1390  mpx_events->start_values[i] = mpx_events->start_values[i + 1];
1391  mpx_events->stop_values[i] = mpx_events->stop_values[i + 1];
1392  mpx_events->start_hc[i] = mpx_events->start_hc[i + 1];
1393  }
1394  mpx_events->mev[i] = NULL;
1395 
1396  mpx_remove_unused( &mpx_events->mythr->head );
1397 
1398 }
1399 
1404 static void
1406 {
1407  MasterEvent *mev, *lastmev = NULL, *nextmev;
1408  Threadlist *thr = ( *head == NULL ) ? NULL : ( *head )->mythr;
1409  int retval;
1410 
1411  /* Clean up and remove unused master events. */
1412  for ( mev = *head; mev != NULL; mev = nextmev ) {
1413  nextmev = mev->next; /* get link before mev is freed */
1414  if ( !mev->uses ) {
1415  if ( lastmev == NULL ) { /* this was the head event */
1416  *head = nextmev;
1417  } else {
1418  lastmev->next = nextmev;
1419  }
1422  if (retval!=PAPI_OK) PAPIERROR("Error destroying event\n");
1423  papi_free( mev );
1424  } else {
1425  lastmev = mev;
1426  }
1427  }
1428 
1429  /* Always be sure the head master event points to the thread */
1430  if ( *head != NULL ) {
1431  ( *head )->mythr = thr;
1432  }
1433 }
memset(eventId, 0, size)
int PAPI_stop(int EventSet, long long *values)
Definition: papi.c:2225
#define PAPI_EINVAL_DOM
Definition: fpapi.h:126
int errno
#define PAPI_ENOMEM
Definition: fpapi.h:107
#define DEBUG_MULTIPLEX
Definition: papi_debug.h:31
unsigned int me
Definition: iozone.c:20357
long long total_c
int PAPI_add_event(int EventSet, int EventCode)
Definition: papi.c:1597
inline_static void mpx_hold(void)
Definition: sw_multiplex.c:180
#define PAPI_NULL
Definition: fpapi.h:13
#define papi_free(a)
Definition: papi_memory.h:35
gc head
Definition: libasync.c:669
#define papi_malloc(a)
Definition: papi_memory.h:34
static void mpx_shutdown_itimer(void)
Definition: sw_multiplex.c:257
double rate_estimate
long long stop_c
Definition: sw_multiplex.h:25
void MPX_shutdown(void)
static Threadlist * tlist
Definition: sw_multiplex.c:140
int num_events
PAPI_granularity_option_t granularity
Definition: papi.h:848
for(i=0;i<=max_y;i++)
Definition: iozone.c:11615
int MPX_stop(MPX_EventSet *mpx_events, long long *values)
Definition: sw_multiplex.c:974
long long stop_values[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:27
EventSetDomainInfo_t domain
return PAPI_OK
Definition: linux-nvml.c:458
static void mpx_handler(int signal)
Definition: sw_multiplex.c:445
#define PAPI_DOM_KERNEL
Definition: fpapi.h:22
A pointer to the following is passed to PAPI_set/get_opt()
Definition: papi.h:843
return PAPI_EINVAL
Definition: linux-nvml.c:408
#define PAPI_MAX_SW_MPX_EVENTS
Definition: sw_multiplex.h:4
EventSetInfo_t * _papi_hwi_lookup_EventSet(int eventset)
long long start_hc[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:28
static double
Definition: fileop.c:1281
int PAPI_set_opt(int option, PAPI_option_t *ptr)
Definition: papi.c:3360
Return codes and api definitions.
int MPX_read(MPX_EventSet *mpx_events, long long *values, int called_by_stop)
Definition: sw_multiplex.c:823
static struct itimerval itimestop
Definition: sw_multiplex.c:153
int MPX_add_events(MPX_EventSet **mpx_events, int *event_list, int num_events, int domain, int granularity)
Definition: sw_multiplex.c:676
struct _masterevent * mev[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:21
#define PAPI_ECOUNT
Definition: fpapi.h:128
t
Definition: iozone.c:23562
MPX_status status
Definition: sw_multiplex.h:17
static unsigned int randomseed
Definition: sw_multiplex.c:141
int i
Definition: fileop.c:140
inline_static int _papi_hwi_lock(int lck)
Definition: threads.h:64
#define PAPI_ENOEVST
Definition: fpapi.h:116
static void mpx_remove_unused(MasterEvent **head)
static void mpx_delete_one_event(MPX_EventSet *mpx_events, int Event)
PAPI_os_info_t _papi_os_info
Definition: aix.c:1210
int MPX_start(MPX_EventSet *mpx_events)
Definition: sw_multiplex.c:692
#define PAPI_DOM_SUPERVISOR
Definition: fpapi.h:24
static int pid
#define MULTIPLEX_LOCK
Definition: papi_internal.h:86
#define PAPI_ECMP
Definition: fpapi.h:109
MasterEvent * cur_event
static void mpx_restore_signal(void)
Definition: sw_multiplex.c:247
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:78
MasterEvent * head
void *long long tid
Definition: iozone.c:18586
static int mpx_insert_events(MPX_EventSet *, int *event_list, int num_events, int domain, int granularity)
int MPX_cleanup(MPX_EventSet **mpx_events)
long long
Definition: iozone.c:19827
long long cycles
int granularity
void PAPIERROR(char *format,...)
static int mpx_startup_itimer(void)
Definition: sw_multiplex.c:222
#define PAPI_DOMAIN
Definition: fpapi.h:50
int mpx_add_event(MPX_EventSet **mpx_events, int EventCode, int domain, int granularity)
Definition: sw_multiplex.c:305
static struct sigaction oaction
Definition: sw_multiplex.c:154
#define inline_static
struct _masterevent * next
#define MPX_MINCYC
Definition: sw_multiplex.c:134
#define PAPI_GRANUL
Definition: fpapi.h:52
int PAPI_cleanup_eventset(int EventSet)
Definition: papi.c:2795
int mpx_init(int interval_ns)
int PAPI_create_eventset(int *EventSet)
Definition: papi.c:1399
unsigned long int(* _papi_hwi_thread_id_fn)(void)
Definition: threads.c:42
#define PAPI_ESYS
Definition: fpapi.h:108
PapiInfo pi
papi_mdi_t _papi_hwi_system_info
Definition: papi_internal.c:57
PAPI_hw_info_t hw_info
int PAPI_event_name_to_code(char *in, int *out)
Definition: papi.c:1003
#define SCALE_EVENT
Definition: sw_multiplex.c:440
nsize_list next
Definition: iozone.c:20053
struct _threadlist * mythr
Definition: sw_multiplex.h:19
int EventSet
int MPX_reset(MPX_EventSet *mpx_events)
Definition: sw_multiplex.c:937
#define MPXDBG(format, args...)
Definition: papi_debug.h:67
static MPX_EventSet * mpx_malloc(Threadlist *t)
Definition: sw_multiplex.c:292
static void mpx_init_timers(int interval)
Definition: sw_multiplex.c:194
#define PAPI_EBUG
Definition: fpapi.h:111
long long PAPI_get_real_usec(void)
Definition: papi.c:6125
struct _threadlist * next
int mpx_remove_event(MPX_EventSet **mpx_events, int EventCode)
Definition: sw_multiplex.c:418
long long event_type
static MasterEvent * get_my_threads_master_event_list(void)
Definition: sw_multiplex.c:268
#define PAPI_ENOTRUN
Definition: fpapi.h:114
#define ISLEVEL(a)
Definition: papi_debug.h:54
int Event[MAX_EVENTS]
struct papi_vectors * _papi_hwd[]
int PAPI_destroy_eventset(int *EventSet)
Definition: papi.c:1937
PAPI_domain_option_t domain
Definition: papi.h:850
char model_string[PAPI_MAX_STR_LEN]
Definition: papi.h:785
int PAPI_read(int EventSet, long long *values)
Definition: papi.c:2469
static sigset_t sigreset
Definition: sw_multiplex.c:151
#define PAPI_DOM_USER
Definition: fpapi.h:21
long long count
unsigned long int tid
inline_static void mpx_release(void)
Definition: sw_multiplex.c:187
int PAPI_start(int EventSet)
Definition: papi.c:2019
static struct itimerval itime
Definition: sw_multiplex.c:152
static long long values[NUM_EVENTS]
Definition: init_fini.c:10
ssize_t retval
Definition: libasync.c:338
long long tmp
Definition: iozone.c:12031
struct _threadlist * mythr
static void mpx_delete_events(MPX_EventSet *)
long long start_values[PAPI_MAX_SW_MPX_EVENTS]
Definition: sw_multiplex.h:26
long long count_estimate
long long prev_total_c
static options_t options
int mpx_check(int EventSet)
signal(SIGINT, signal_handler)
long long start_c
Definition: sw_multiplex.h:25