Blame src/sw_multiplex.c

Packit 577717
/** 
Packit 577717
 * @file    sw_multiplex.c
Packit 577717
 * @author  Philip Mucci
Packit 577717
 *          mucci@cs.utk.edu
Packit 577717
 * @author  John May
Packit 577717
 *          johnmay@llnl.gov
Packit 577717
 * @author  Nils Smeds
Packit 577717
 *          smeds@pdc.kth.se
Packit 577717
 * @author  Haihang You
Packit 577717
 *          you@cs.utk.edu 
Packit 577717
 * @author  Kevin London
Packit 577717
 *	        london@cs.utk.edu
Packit 577717
 * @author  Maynard Johnson
Packit 577717
 *          maynardj@us.ibm.com
Packit 577717
 * @author  Dan Terpstra
Packit 577717
 *	        terpstra@cs.utk.edu
Packit 577717
 */
Packit 577717
Packit 577717
/** xxxx Will this stuff run unmodified on multiple components?
Packit 577717
    What happens when several components are counting multiplexed?
Packit 577717
*/
Packit 577717
Packit 577717
/* disable this to return to the pre 4.1.1 behavior */
Packit 577717
#define MPX_NONDECR_HYBRID
Packit 577717
Packit 577717
/* Nils Smeds */
Packit 577717
Packit 577717
/* This MPX update modifies the behaviour of the multiplexing in PAPI.
Packit 577717
 * The previous versions of the multiplexing based the value returned
Packit 577717
 * from PAPI_reads on the total counts achieved since the PAPI_start
Packit 577717
 * of the multiplexed event. This count was used as the basis of the
Packit 577717
 * extrapolation using the proportion of time that this particular
Packit 577717
 * event was active to the total time the multiplexed event was
Packit 577717
 * active. However, a typical usage of PAPI is to measure over
Packit 577717
 * sections of code by starting the event once and by comparing
Packit 577717
 * the values returned by subsequent calls to PAPI_read. The difference
Packit 577717
 * in counts is used as the measure of occured events in the code
Packit 577717
 * section between the calls. 
Packit 577717
 *
Packit 577717
 * When multiplexing is used in this fashion the time proportion used
Packit 577717
 * for extrapolation might appear inconsistent. The time fraction used
Packit 577717
 * at each PAPI_read is the total time fraction since PAPI_start. If the
Packit 577717
 * counter values achieved in each multiplex of the event varies
Packit 577717
 * largely, or if the time slices are varying in length, discrepancies
Packit 577717
 * to the behaviour without multiplexing might occur.
Packit 577717
 *
Packit 577717
 * In this version the extrapolation is made on a local time scale. At
Packit 577717
 * each completed time slice the event extrapolates the achieved count
Packit 577717
 * to a extrapolated count for the time since this event was last sliced
Packit 577717
 * out up to the current point in time. There will still be occasions
Packit 577717
 * when two consecutive PAPI_read will yield decreasing results, but all
Packit 577717
 * extrapolations are being made on time local data. If time slicing
Packit 577717
 * varies or if the count rate varies this implementation is expected to
Packit 577717
 * be more "accurate" in a loose and here unspecified meaning.
Packit 577717
 *
Packit 577717
 * The short description of the changes is that the running events has
Packit 577717
 * new fields count_estimate, rate_estimate and prev_total_c. The mpx
Packit 577717
 * events have had the meaning of start_values and stop_values modified
Packit 577717
 * to mean extrapolated start value and extrapolated stop value.
Packit 577717
 */
Packit 577717
Packit 577717
/* 
Packit 577717
Portions of the following code are
Packit 577717
Copyright (c) 2009, Lawrence Livermore National Security, LLC.  
Packit 577717
Produced at the Lawrence Livermore National Laboratory  
Packit 577717
Written by John May, johnmay@llnl.gov
Packit 577717
LLNL-CODE-421124
Packit 577717
All rights reserved.  
Packit 577717
  
Packit 577717
Redistribution and use in source and binary forms, with or
Packit 577717
without modification, are permitted provided that the following
Packit 577717
conditions are met:  
Packit 577717
  
Packit 577717
 • Redistributions of source code must retain the above copyright
Packit 577717
notice, this list of conditions and the disclaimer below. 
Packit 577717
Packit 577717
 • Redistributions in binary form must reproduce the above
Packit 577717
copyright notice, this list of conditions and the disclaimer (as
Packit 577717
noted below) in the documentation and/or other materials provided
Packit 577717
with the distribution. 
Packit 577717
Packit 577717
 • Neither the name of the LLNS/LLNL nor the names of its
Packit 577717
contributors may be used to endorse or promote products derived
Packit 577717
from this software without specific prior written permission.  
Packit 577717
  
Packit 577717
 
Packit 577717
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
Packit 577717
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
Packit 577717
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
Packit 577717
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 577717
DISCLAIMED.  IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL
Packit 577717
SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE
Packit 577717
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
Packit 577717
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
Packit 577717
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE, DATA,
Packit 577717
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON  ANY
Packit 577717
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
Packit 577717
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
Packit 577717
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
Packit 577717
OF SUCH DAMAGE.  
Packit 577717
  
Packit 577717
  
Packit 577717
Additional BSD Notice  
Packit 577717
  
Packit 577717
1. This notice is required to be provided under our contract with
Packit 577717
the U.S.  Department of Energy (DOE).  This work was produced at
Packit 577717
Lawrence Livermore National Laboratory under Contract No.
Packit 577717
DE-AC52-07NA27344 with the DOE.  
Packit 577717
  
Packit 577717
2. Neither the United States Government nor Lawrence Livermore
Packit 577717
National Security, LLC nor any of their employees, makes any
Packit 577717
warranty, express or implied, or assumes any liability or
Packit 577717
responsibility for the accuracy, completeness, or usefulness of
Packit 577717
any information, apparatus, product, or process disclosed, or
Packit 577717
represents that its use would not infringe privately-owned
Packit 577717
rights.  
Packit 577717
  
Packit 577717
3.  Also, reference herein to any specific commercial products,
Packit 577717
process, or services by trade name, trademark, manufacturer or
Packit 577717
otherwise does not necessarily constitute or imply its
Packit 577717
endorsement, recommendation, or favoring by the United States
Packit 577717
Government or Lawrence Livermore National Security, LLC.  The
Packit 577717
views and opinions of authors expressed herein do not necessarily
Packit 577717
state or reflect those of the United States Government or
Packit 577717
Lawrence Livermore National Security, LLC, and shall not be used
Packit 577717
for advertising or product endorsement purposes.  
Packit 577717
 */
Packit 577717
Packit 577717
#include "papi.h"
Packit 577717
#include "papi_internal.h"
Packit 577717
#include "papi_vector.h"
Packit 577717
#include "papi_memory.h"
Packit 577717
Packit 577717
#define MPX_MINCYC 25000
Packit 577717
Packit 577717
/* Globals for this file. */
Packit 577717
Packit 577717
/** List of threads that are multiplexing. */
Packit 577717
Packit 577717
static Threadlist *tlist = NULL;
Packit 577717
static unsigned int randomseed;
Packit 577717
Packit 577717
/* Timer stuff */
Packit 577717
Packit 577717
#include <sys/time.h>
Packit 577717
#include <string.h>
Packit 577717
#include <errno.h>
Packit 577717
#include <unistd.h> 
Packit 577717
#include <assert.h>
Packit 577717
Packit 577717
static sigset_t sigreset;
Packit 577717
static struct itimerval itime;
Packit 577717
static const struct itimerval itimestop = { {0, 0}, {0, 0} };
Packit 577717
static struct sigaction oaction;
Packit 577717
Packit 577717
/* END Globals */
Packit 577717
Packit 577717
#ifdef PTHREADS
Packit 577717
/** Number of threads that have been signaled */
Packit 577717
static int threads_responding = 0;
Packit 577717
Packit 577717
static pthread_once_t mpx_once_control = PTHREAD_ONCE_INIT;
Packit 577717
static pthread_mutex_t tlistlock;
Packit 577717
static pthread_key_t master_events_key;
Packit 577717
static pthread_key_t thread_record_key;
Packit 577717
static MasterEvent *global_master_events;
Packit 577717
static void *global_process_record;
Packit 577717
#endif
Packit 577717
Packit 577717
/* Forward prototypes */
Packit 577717
Packit 577717
static void mpx_remove_unused( MasterEvent ** head );
Packit 577717
static void mpx_delete_events( MPX_EventSet * );
Packit 577717
static void mpx_delete_one_event( MPX_EventSet * mpx_events, int Event );
Packit 577717
static int mpx_insert_events( MPX_EventSet *, int *event_list, int num_events,
Packit 577717
							  int domain, int granularity );
Packit 577717
static void mpx_handler( int signal );
Packit 577717
Packit 577717
inline_static void
Packit 577717
mpx_hold( void )
Packit 577717
{
Packit 577717
	sigprocmask( SIG_BLOCK, &sigreset, NULL );
Packit 577717
	MPXDBG( "signal held\n" );
Packit 577717
}
Packit 577717
Packit 577717
inline_static void
Packit 577717
mpx_release( void )
Packit 577717
{
Packit 577717
	MPXDBG( "signal released\n" );
Packit 577717
	sigprocmask( SIG_UNBLOCK, &sigreset, NULL );
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
mpx_init_timers( int interval )
Packit 577717
{
Packit 577717
	/* Fill in the interval timer values now to save a
Packit 577717
	 * little time later.
Packit 577717
	 */
Packit 577717
#ifdef OUTSIDE_PAPI
Packit 577717
	interval = MPX_DEFAULT_INTERVAL;
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef REGENERATE
Packit 577717
	/* Signal handler restarts the timer every time it runs */
Packit 577717
	itime.it_interval.tv_sec = 0;
Packit 577717
	itime.it_interval.tv_usec = 0;
Packit 577717
	itime.it_value.tv_sec = 0;
Packit 577717
	itime.it_value.tv_usec = interval;
Packit 577717
#else
Packit 577717
	/* Timer resets itself automatically */
Packit 577717
	itime.it_interval.tv_sec = 0;
Packit 577717
	itime.it_interval.tv_usec = interval;
Packit 577717
	itime.it_value.tv_sec = 0;
Packit 577717
	itime.it_value.tv_usec = interval;
Packit 577717
#endif
Packit 577717
Packit 577717
	sigemptyset( &sigreset );
Packit 577717
	sigaddset( &sigreset, _papi_os_info.itimer_sig );
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
mpx_startup_itimer( void )
Packit 577717
{
Packit 577717
	struct sigaction sigact;
Packit 577717
Packit 577717
	/* Set up the signal handler and the timer that triggers it */
Packit 577717
Packit 577717
	MPXDBG( "PID %d\n", getpid(  ) );
Packit 577717
	memset( &sigact, 0, sizeof ( sigact ) );
Packit 577717
	sigact.sa_flags = SA_RESTART;
Packit 577717
	sigact.sa_handler = mpx_handler;
Packit 577717
Packit 577717
	if ( sigaction( _papi_os_info.itimer_sig, &sigact, NULL ) == -1 ) {
Packit 577717
		PAPIERROR( "sigaction start errno %d", errno );
Packit 577717
		return PAPI_ESYS;
Packit 577717
	}
Packit 577717
Packit 577717
	if ( setitimer( _papi_os_info.itimer_num, &itime, NULL ) == -1 ) {
Packit 577717
		sigaction( _papi_os_info.itimer_sig, &oaction, NULL );
Packit 577717
		PAPIERROR( "setitimer start errno %d", errno );
Packit 577717
		return PAPI_ESYS;
Packit 577717
	}
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
mpx_restore_signal( void )
Packit 577717
{
Packit 577717
	MPXDBG( "restore signal\n" );
Packit 577717
	if ( _papi_os_info.itimer_sig != PAPI_NULL ) {
Packit 577717
		if ( signal( _papi_os_info.itimer_sig, SIG_IGN ) == SIG_ERR )
Packit 577717
			PAPIERROR( "sigaction stop errno %d", errno );
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
mpx_shutdown_itimer( void )
Packit 577717
{
Packit 577717
	MPXDBG( "setitimer off\n" );
Packit 577717
	if ( _papi_os_info.itimer_num != PAPI_NULL ) {
Packit 577717
		if ( setitimer( _papi_os_info.itimer_num,
Packit 577717
			   ( struct itimerval * ) &itimestop, NULL ) == -1 )
Packit 577717
			PAPIERROR( "setitimer stop errno %d", errno );
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static MasterEvent *
Packit 577717
get_my_threads_master_event_list( void )
Packit 577717
{
Packit 577717
	Threadlist *t = tlist;
Packit 577717
	unsigned long tid;
Packit 577717
Packit 577717
	MPXDBG( "tlist is %p\n", tlist );
Packit 577717
	if ( tlist == NULL )
Packit 577717
		return NULL;
Packit 577717
Packit 577717
	if ( _papi_hwi_thread_id_fn == NULL )
Packit 577717
		return ( tlist->head );
Packit 577717
Packit 577717
	tid = _papi_hwi_thread_id_fn(  );
Packit 577717
	unsigned long pid = ( unsigned long ) getpid(  );
Packit 577717
Packit 577717
	while ( t ) {
Packit 577717
		if ( t->tid == tid || ( ( tid == 0 ) && ( t->tid == pid ) ) )
Packit 577717
			return ( t->head );
Packit 577717
		t = t->next;
Packit 577717
	}
Packit 577717
	return ( NULL );
Packit 577717
}
Packit 577717
Packit 577717
static MPX_EventSet *
Packit 577717
mpx_malloc( Threadlist * t )
Packit 577717
{
Packit 577717
	MPX_EventSet *newset =
Packit 577717
		( MPX_EventSet * ) papi_malloc( sizeof ( MPX_EventSet ) );
Packit 577717
	if ( newset == NULL )
Packit 577717
		return ( NULL );
Packit 577717
	memset( newset, 0, sizeof ( MPX_EventSet ) );
Packit 577717
	newset->status = MPX_STOPPED;
Packit 577717
	newset->mythr = t;
Packit 577717
	return ( newset );
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
mpx_add_event( MPX_EventSet ** mpx_events, int EventCode, int domain,
Packit 577717
			   int granularity )
Packit 577717
{
Packit 577717
	MPX_EventSet *newset = *mpx_events;
Packit 577717
	int retval, alloced_newset = 0;
Packit 577717
	Threadlist *t;
Packit 577717
Packit 577717
	/* Get the global list of threads */
Packit 577717
Packit 577717
	MPXDBG("Adding %p %#x\n",newset,EventCode);
Packit 577717
Packit 577717
	_papi_hwi_lock( MULTIPLEX_LOCK );
Packit 577717
	t = tlist;
Packit 577717
Packit 577717
	/* If there are no threads in the list at all, then allocate the new Threadlist */
Packit 577717
Packit 577717
	if ( t == NULL ) {
Packit 577717
	  new_thread:
Packit 577717
		t = ( Threadlist * ) papi_malloc( sizeof ( Threadlist ) );
Packit 577717
		if ( t == NULL ) {
Packit 577717
			_papi_hwi_unlock( MULTIPLEX_LOCK );
Packit 577717
			return ( PAPI_ENOMEM );
Packit 577717
		}
Packit 577717
Packit 577717
		/* If we're actually threaded, fill the 
Packit 577717
		 * field with the thread_id otherwise
Packit 577717
		 * use getpid() as a placeholder. */
Packit 577717
Packit 577717
		if ( _papi_hwi_thread_id_fn ) {
Packit 577717
			MPXDBG( "New thread at %p\n", t );
Packit 577717
			t->tid = _papi_hwi_thread_id_fn(  );
Packit 577717
		} else {
Packit 577717
			MPXDBG( "New process at %p\n", t );
Packit 577717
			t->tid = ( unsigned long ) getpid(  );
Packit 577717
		}
Packit 577717
Packit 577717
		/* Fill in the fields */
Packit 577717
Packit 577717
		t->head = NULL;
Packit 577717
		t->cur_event = NULL;
Packit 577717
		t->next = tlist;
Packit 577717
		tlist = t;
Packit 577717
		MPXDBG( "New head is at %p(%lu).\n", tlist,
Packit 577717
				( long unsigned ) tlist->tid );
Packit 577717
		/* alloced_thread = 1; */
Packit 577717
	} else if ( _papi_hwi_thread_id_fn ) {
Packit 577717
Packit 577717
		/* If we are threaded, AND there exists threads in the list, 
Packit 577717
		 *  then try to find our thread in the list. */
Packit 577717
Packit 577717
		unsigned long tid = _papi_hwi_thread_id_fn(  );
Packit 577717
Packit 577717
		while ( t ) {
Packit 577717
			if ( t->tid == tid ) {
Packit 577717
				MPXDBG( "Found thread %#lx\n", t->tid );
Packit 577717
				break;
Packit 577717
			}
Packit 577717
			t = t->next;
Packit 577717
		}
Packit 577717
Packit 577717
		/* Our thread is not in the list, so make a new
Packit 577717
		 * thread entry. */
Packit 577717
Packit 577717
		if ( t == NULL ) {
Packit 577717
			MPXDBG( "New thread %lx\n", tid );
Packit 577717
			goto new_thread;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/* Now t & tlist points to our thread, also at the head of the list */
Packit 577717
Packit 577717
	/* Allocate a the MPX_EventSet if necessary */
Packit 577717
Packit 577717
	if ( newset == NULL ) {
Packit 577717
		newset = mpx_malloc( t );
Packit 577717
		if ( newset == NULL ) {
Packit 577717
			_papi_hwi_unlock( MULTIPLEX_LOCK );
Packit 577717
			return ( PAPI_ENOMEM );
Packit 577717
		}
Packit 577717
		alloced_newset = 1;
Packit 577717
	}
Packit 577717
Packit 577717
	/* Now we're finished playing with the thread list */
Packit 577717
Packit 577717
	_papi_hwi_unlock( MULTIPLEX_LOCK );
Packit 577717
Packit 577717
	/* Removed newset->num_events++, moved to mpx_insert_events() */
Packit 577717
Packit 577717
	mpx_hold(  );
Packit 577717
Packit 577717
	/* Create PAPI events (if they don't already exist) and link
Packit 577717
	 * the new event set to them, add them to the master list for
Packit 577717
	 the thread, reset master event list for this thread */
Packit 577717
Packit 577717
	retval = mpx_insert_events( newset, &EventCode, 1, 
Packit 577717
				    domain, granularity );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
		if ( alloced_newset ) {
Packit 577717
			papi_free( newset );
Packit 577717
			newset = NULL;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	mpx_release(  );
Packit 577717
Packit 577717
	/* Output the new or existing EventSet */
Packit 577717
Packit 577717
	*mpx_events = newset;
Packit 577717
Packit 577717
	return retval;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
mpx_remove_event( MPX_EventSet ** mpx_events, int EventCode )
Packit 577717
{
Packit 577717
	mpx_hold(  );
Packit 577717
	if ( *mpx_events )
Packit 577717
		mpx_delete_one_event( *mpx_events, EventCode );
Packit 577717
	mpx_release(  );
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
#ifdef MPX_DEBUG_TIMER
Packit 577717
static long long lastcall;
Packit 577717
#endif
Packit 577717
Packit 577717
Packit 577717
#ifdef _POWER6
Packit 577717
/* POWER6 can always count PM_RUN_CYC on counter 6 in domain
Packit 577717
   PAPI_DOM_ALL, and can count it on other domains on counters
Packit 577717
   1 and 2 along with a very limited number of other native
Packit 577717
   events */
Packit 577717
int _PNE_PM_RUN_CYC;
Packit 577717
#define SCALE_EVENT _PNE_PM_RUN_CYC
Packit 577717
#else
Packit 577717
#define SCALE_EVENT PAPI_TOT_CYC
Packit 577717
#endif
Packit 577717
Packit 577717
Packit 577717
static void
Packit 577717
mpx_handler( int signal )
Packit 577717
{
Packit 577717
	int retval;
Packit 577717
	MasterEvent *mev, *head;
Packit 577717
	Threadlist *me = NULL;
Packit 577717
#ifdef REGENERATE
Packit 577717
	int lastthread;
Packit 577717
#endif
Packit 577717
#ifdef MPX_DEBUG_OVERHEAD
Packit 577717
	long long usec;
Packit 577717
	int didwork = 0;
Packit 577717
	usec = PAPI_get_real_usec(  );
Packit 577717
#endif
Packit 577717
#ifdef MPX_DEBUG_TIMER
Packit 577717
	long long thiscall;
Packit 577717
#endif
Packit 577717
Packit 577717
	signal = signal;		 /* unused */
Packit 577717
Packit 577717
	MPXDBG( "Handler in thread\n" );
Packit 577717
Packit 577717
	/* This handler can be invoked either when a timer expires
Packit 577717
	 * or when another thread in this handler responding to the
Packit 577717
	 * timer signals other threads.  We have to distinguish
Packit 577717
	 * these two cases so that we don't get infinite loop of 
Packit 577717
	 * handler calls.  To do that, we look at the value of
Packit 577717
	 * threads_responding.  We assume that only one thread can
Packit 577717
	 * be active in this signal handler at a time, since the
Packit 577717
	 * invoking signal is blocked while the handler is active.
Packit 577717
	 * If threads_responding == 0, the current thread caught
Packit 577717
	 * the original timer signal.  (This thread may not have
Packit 577717
	 * any active event lists itself, though.)  This first
Packit 577717
	 * thread sends a signal to each of the other threads in
Packit 577717
	 * our list of threads that have master events lists.  If
Packit 577717
	 * threads_responding != 0, then this thread was signaled
Packit 577717
	 * by another thread.  We decrement that value and look
Packit 577717
	 * for an active events.  threads_responding should
Packit 577717
	 * reach zero when all active threads have handled their
Packit 577717
	 * signal.  It's probably possible for a thread to die
Packit 577717
	 * before it responds to a signal; if that happens,
Packit 577717
	 * threads_responding won't reach zero until the next
Packit 577717
	 * timer signal happens.  Then the signalled thread won't
Packit 577717
	 * signal any other threads.  If that happens only
Packit 577717
	 * occasionally, there should be no harm.  Likewise if
Packit 577717
	 * a new thread is added that fails to get signalled.
Packit 577717
	 * As for locking, we have to lock this list to prevent
Packit 577717
	 * another thread from modifying it, but if *this* thread
Packit 577717
	 * is trying to update the list (from another function) and
Packit 577717
	 * is signaled while it holds the lock, we will have deadlock.
Packit 577717
	 * Therefore, noninterrupt functions that update *this* list
Packit 577717
	 * must disable the signal that invokes this handler.
Packit 577717
	 */
Packit 577717
Packit 577717
#ifdef PTHREADS
Packit 577717
	_papi_hwi_lock( MULTIPLEX_LOCK );
Packit 577717
Packit 577717
	if ( threads_responding == 0 ) {	/* this thread caught the timer sig */
Packit 577717
		/* Signal the other threads with event lists */
Packit 577717
#ifdef MPX_DEBUG_TIMER
Packit 577717
		thiscall = _papi_hwd_get_real_usec(  );
Packit 577717
		MPXDBG( "last signal was %lld usec ago\n", thiscall - lastcall );
Packit 577717
		lastcall = thiscall;
Packit 577717
#endif
Packit 577717
		MPXDBG( "%#x caught it, tlist is %p\n", self, tlist );
Packit 577717
		for ( t = tlist; t != NULL; t = t->next ) {
Packit 577717
			if ( pthread_equal( t->thr, self ) == 0 ) {
Packit 577717
				++threads_responding;
Packit 577717
				retval = pthread_kill( t->thr, _papi_os_info.itimer_sig );
Packit 577717
				assert( retval == 0 );
Packit 577717
#ifdef MPX_DEBUG_SIGNALS
Packit 577717
				MPXDBG( "%#x signaling %#x\n", self, t->thr );
Packit 577717
#endif
Packit 577717
			}
Packit 577717
		}
Packit 577717
	} else {
Packit 577717
#ifdef MPX_DEBUG_SIGNALS
Packit 577717
		MPXDBG( "%#x was tapped, tr = %d\n", self, threads_responding );
Packit 577717
#endif
Packit 577717
		--threads_responding;
Packit 577717
	}
Packit 577717
#ifdef REGENERATE
Packit 577717
	lastthread = ( threads_responding == 0 );
Packit 577717
#endif
Packit 577717
	_papi_hwi_unlock( MULTIPLEX_LOCK );
Packit 577717
#endif
Packit 577717
Packit 577717
	/* See if this thread has an active event list */
Packit 577717
	head = get_my_threads_master_event_list(  );
Packit 577717
	if ( head != NULL ) {
Packit 577717
Packit 577717
		/* Get the thread header for this master event set.  It's
Packit 577717
		 * always in the first record of the set (and maybe in others)
Packit 577717
		 * if any record in the set is active.
Packit 577717
		 */
Packit 577717
		me = head->mythr;
Packit 577717
Packit 577717
		/* Find the event that's currently active, stop and read
Packit 577717
		 * it, then start the next event in the list.
Packit 577717
		 * No need to lock the list because other functions
Packit 577717
		 * disable the timer interrupt before they update the list.
Packit 577717
		 */
Packit 577717
		if ( me != NULL && me->cur_event != NULL ) {
Packit 577717
			long long counts[2];
Packit 577717
			MasterEvent *cur_event = me->cur_event;
Packit 577717
			long long cycles = 0, total_cycles = 0;
Packit 577717
Packit 577717
			retval = PAPI_stop( cur_event->papi_event, counts );
Packit 577717
			MPXDBG( "retval=%d, cur_event=%p, I'm tid=%lx\n",
Packit 577717
					retval, cur_event, me->tid );
Packit 577717
Packit 577717
			if ( retval == PAPI_OK ) {
Packit 577717
				MPXDBG( "counts[0] = %lld counts[1] = %lld\n", counts[0],
Packit 577717
						counts[1] );
Packit 577717
Packit 577717
				cur_event->count += counts[0];
Packit 577717
				cycles = ( cur_event->pi.event_type == SCALE_EVENT )
Packit 577717
					? counts[0] : counts[1];
Packit 577717
Packit 577717
				me->total_c += cycles;
Packit 577717
				total_cycles = me->total_c - cur_event->prev_total_c;
Packit 577717
				cur_event->prev_total_c = me->total_c;
Packit 577717
Packit 577717
				/* If it's a rate, count occurrences & average later */
Packit 577717
				if ( !cur_event->is_a_rate ) {
Packit 577717
					cur_event->cycles += cycles;
Packit 577717
					if ( cycles >= MPX_MINCYC ) {	/* Only update current rate on a decent slice */
Packit 577717
						cur_event->rate_estimate =
Packit 577717
							( double ) counts[0] / ( double ) cycles;
Packit 577717
					}
Packit 577717
					cur_event->count_estimate +=
Packit 577717
						( long long ) ( ( double ) total_cycles *
Packit 577717
										cur_event->rate_estimate );
Packit 577717
                                        MPXDBG("New estimate = %lld (%lld cycles * %lf rate)\n",
Packit 577717
                                               cur_event->count_estimate,total_cycles,
Packit 577717
                                               cur_event->rate_estimate);
Packit 577717
				} else {
Packit 577717
					/* Make sure we ran long enough to get a useful measurement (otherwise
Packit 577717
					 * potentially inaccurate rate measurements get averaged in with
Packit 577717
					 * the same weight as longer, more accurate ones.)
Packit 577717
					 */
Packit 577717
					if ( cycles >= MPX_MINCYC ) {
Packit 577717
						cur_event->cycles += 1;
Packit 577717
					} else {
Packit 577717
						cur_event->count -= counts[0];
Packit 577717
					}
Packit 577717
				}
Packit 577717
			} else {
Packit 577717
				MPXDBG( "%lx retval = %d, skipping\n", me->tid, retval );
Packit 577717
				MPXDBG( "%lx value = %lld cycles = %lld\n\n",
Packit 577717
						me->tid, cur_event->count, cur_event->cycles );
Packit 577717
			}
Packit 577717
Packit 577717
			MPXDBG
Packit 577717
				( "tid(%lx): value = %lld (%lld) cycles = %lld (%lld) rate = %lf\n\n",
Packit 577717
				  me->tid, cur_event->count, cur_event->count_estimate,
Packit 577717
				  cur_event->cycles, total_cycles, cur_event->rate_estimate );
Packit 577717
			/* Start running the next event; look for the
Packit 577717
			 * next one in the list that's marked active.
Packit 577717
			 * It's possible that this event is the only
Packit 577717
			 * one active; if so, we should restart it,
Packit 577717
			 * but only after considerating all the other
Packit 577717
			 * possible events.
Packit 577717
			 */
Packit 577717
			if ( ( retval != PAPI_OK ) ||
Packit 577717
				 ( ( retval == PAPI_OK ) && ( cycles >= MPX_MINCYC ) ) ) {
Packit 577717
				for ( mev =
Packit 577717
					  ( cur_event->next == NULL ) ? head : cur_event->next;
Packit 577717
					  mev != cur_event;
Packit 577717
					  mev = ( mev->next == NULL ) ? head : mev->next ) {
Packit 577717
					/* Found the next one to start */
Packit 577717
					if ( mev->active ) {
Packit 577717
						me->cur_event = mev;
Packit 577717
						break;
Packit 577717
					}
Packit 577717
				}
Packit 577717
			}
Packit 577717
Packit 577717
			if ( me->cur_event->active ) {
Packit 577717
				retval = PAPI_start( me->cur_event->papi_event );
Packit 577717
			}
Packit 577717
#ifdef MPX_DEBUG_OVERHEAD
Packit 577717
			didwork = 1;
Packit 577717
#endif
Packit 577717
		}
Packit 577717
	}
Packit 577717
#ifdef ANY_THREAD_GETS_SIGNAL
Packit 577717
	else {
Packit 577717
		Threadlist *t;
Packit 577717
		for ( t = tlist; t != NULL; t = t->next ) {
Packit 577717
			if ( ( t->tid == _papi_hwi_thread_id_fn(  ) ) ||
Packit 577717
				 ( t->head == NULL ) )
Packit 577717
				continue;
Packit 577717
			MPXDBG( "forwarding signal to thread %lx\n", t->tid );
Packit 577717
			retval = ( *_papi_hwi_thread_kill_fn ) ( t->tid, _papi_os_info.itimer_sig );
Packit 577717
			if ( retval != 0 ) {
Packit 577717
				MPXDBG( "forwarding signal to thread %lx returned %d\n",
Packit 577717
						t->tid, retval );
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef REGENERATE
Packit 577717
	/* Regenerating the signal each time through has the
Packit 577717
	 * disadvantage that if any thread ever drops a signal,
Packit 577717
	 * the whole time slicing system will stop.  Using
Packit 577717
	 * an automatically regenerated signal may have the
Packit 577717
	 * disadvantage that a new signal can arrive very
Packit 577717
	 * soon after all the threads have finished handling
Packit 577717
	 * the last one, so the interval may be too small for
Packit 577717
	 * accurate data collection.  However, using the
Packit 577717
	 * MIN_CYCLES check above should alleviate this.
Packit 577717
	 */
Packit 577717
	/* Reset the timer once all threads have responded */
Packit 577717
	if ( lastthread ) {
Packit 577717
		retval = setitimer( _papi_os_info.itimer_num, &itime, NULL );
Packit 577717
		assert( retval == 0 );
Packit 577717
#ifdef MPX_DEBUG_TIMER
Packit 577717
		MPXDBG( "timer restarted by %lx\n", me->tid );
Packit 577717
#endif
Packit 577717
	}
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef MPX_DEBUG_OVERHEAD
Packit 577717
	usec = _papi_hwd_get_real_usec(  ) - usec;
Packit 577717
	MPXDBG( "handler %#x did %swork in %lld usec\n",
Packit 577717
			self, ( didwork ? "" : "no " ), usec );
Packit 577717
#endif
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
MPX_add_events( MPX_EventSet ** mpx_events, int *event_list, int num_events,
Packit 577717
				int domain, int granularity )
Packit 577717
{
Packit 577717
	int i, retval = PAPI_OK;
Packit 577717
Packit 577717
	for ( i = 0; i < num_events; i++ ) {
Packit 577717
		retval =
Packit 577717
			mpx_add_event( mpx_events, event_list[i], domain, granularity );
Packit 577717
Packit 577717
		if ( retval != PAPI_OK )
Packit 577717
			return ( retval );
Packit 577717
	}
Packit 577717
	return ( retval );
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
MPX_start( MPX_EventSet * mpx_events )
Packit 577717
{
Packit 577717
	int retval = PAPI_OK;
Packit 577717
	int i;
Packit 577717
	long long values[2];
Packit 577717
	long long cycles_this_slice, current_thread_mpx_c = 0;
Packit 577717
	Threadlist *t;
Packit 577717
Packit 577717
	t = mpx_events->mythr;
Packit 577717
Packit 577717
	mpx_hold(  );
Packit 577717
Packit 577717
	if ( t->cur_event && t->cur_event->active ) {
Packit 577717
		current_thread_mpx_c += t->total_c;
Packit 577717
		retval = PAPI_read( t->cur_event->papi_event, values );
Packit 577717
		assert( retval == PAPI_OK );
Packit 577717
		if ( retval == PAPI_OK ) {
Packit 577717
			cycles_this_slice = ( t->cur_event->pi.event_type == SCALE_EVENT )
Packit 577717
				? values[0] : values[1];
Packit 577717
		} else {
Packit 577717
			values[0] = values[1] = 0;
Packit 577717
			cycles_this_slice = 0;
Packit 577717
		}
Packit 577717
Packit 577717
	} else {
Packit 577717
		values[0] = values[1] = 0;
Packit 577717
		cycles_this_slice = 0;
Packit 577717
	}
Packit 577717
Packit 577717
	/* Make all events in this set active, and for those
Packit 577717
	 * already active, get the current count and cycles.
Packit 577717
	 */
Packit 577717
	for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
		MasterEvent *mev = mpx_events->mev[i];
Packit 577717
Packit 577717
		if ( mev->active++ ) {
Packit 577717
			mpx_events->start_values[i] = mev->count_estimate;
Packit 577717
			mpx_events->start_hc[i] = mev->cycles;
Packit 577717
Packit 577717
			/* If this happens to be the currently-running
Packit 577717
			 * event, add in the current amounts from this
Packit 577717
			 * time slice.  If it's a rate, though, don't
Packit 577717
			 * bother since the event might not have been
Packit 577717
			 * running long enough to get an accurate count.
Packit 577717
			 */
Packit 577717
			if ( t->cur_event && !( t->cur_event->is_a_rate ) ) {
Packit 577717
#ifdef MPX_NONDECR_HYBRID
Packit 577717
				if ( mev != t->cur_event ) {	/* This event is not running this slice */
Packit 577717
					mpx_events->start_values[i] +=
Packit 577717
						( long long ) ( mev->rate_estimate *
Packit 577717
										( cycles_this_slice + t->total_c -
Packit 577717
										  mev->prev_total_c ) );
Packit 577717
				} else {	 /* The event is running, use current value + estimate */
Packit 577717
					if ( cycles_this_slice >= MPX_MINCYC )
Packit 577717
						mpx_events->start_values[i] += values[0] + ( long long )
Packit 577717
							( ( values[0] / ( double ) cycles_this_slice ) *
Packit 577717
							  ( t->total_c - mev->prev_total_c ) );
Packit 577717
					else	 /* Use previous rate if the event has run too short time */
Packit 577717
						mpx_events->start_values[i] += values[0] + ( long long )
Packit 577717
							( mev->rate_estimate *
Packit 577717
							  ( t->total_c - mev->prev_total_c ) );
Packit 577717
				}
Packit 577717
#endif
Packit 577717
			} else {
Packit 577717
				mpx_events->start_values[i] = mev->count;
Packit 577717
			}
Packit 577717
		} else {
Packit 577717
			/* The = 0 isn't actually necessary; we only need
Packit 577717
			 * to sync up the mpx event to the master event,
Packit 577717
			 * but it seems safe to set the mev to 0 here, and
Packit 577717
			 * that gives us a change to avoid (very unlikely)
Packit 577717
			 * rollover problems for events used repeatedly over
Packit 577717
			 * a long time.
Packit 577717
			 */
Packit 577717
			mpx_events->start_values[i] = 0;
Packit 577717
			mpx_events->stop_values[i] = 0;
Packit 577717
			mpx_events->start_hc[i] = mev->cycles = 0;
Packit 577717
			mev->count_estimate = 0;
Packit 577717
			mev->rate_estimate = 0.0;
Packit 577717
			mev->prev_total_c = current_thread_mpx_c;
Packit 577717
			mev->count = 0;
Packit 577717
		}
Packit 577717
		/* Adjust start value to include events and cycles
Packit 577717
		 * counted previously for this event set.
Packit 577717
		 */
Packit 577717
	}
Packit 577717
Packit 577717
	mpx_events->status = MPX_RUNNING;
Packit 577717
Packit 577717
	/* Start first counter if one isn't already running */
Packit 577717
	if ( t->cur_event == NULL ) {
Packit 577717
		/* Pick an events at random to start. */
Packit 577717
		int index = ( rand_r( &randomseed ) % mpx_events->num_events );
Packit 577717
		t->cur_event = mpx_events->mev[index];
Packit 577717
		t->total_c = 0;
Packit 577717
		t->cur_event->prev_total_c = 0;
Packit 577717
		mpx_events->start_c = 0;
Packit 577717
		retval = PAPI_start( mpx_events->mev[index]->papi_event );
Packit 577717
		assert( retval == PAPI_OK );
Packit 577717
	} else {
Packit 577717
		/* If an event is already running, record the starting cycle
Packit 577717
		 * count for mpx_events, which is the accumlated cycle count
Packit 577717
		 * for the master event set plus the cycles for this time
Packit 577717
		 * slice.
Packit 577717
		 */
Packit 577717
		mpx_events->start_c = t->total_c + cycles_this_slice;
Packit 577717
	}
Packit 577717
Packit 577717
#if defined(DEBUG)
Packit 577717
	if ( ISLEVEL( DEBUG_MULTIPLEX ) ) {
Packit 577717
		MPXDBG( "%s:%d:: start_c=%lld  thread->total_c=%lld\n", __FILE__,
Packit 577717
				__LINE__, mpx_events->start_c, t->total_c );
Packit 577717
		for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
			MPXDBG
Packit 577717
				( "%s:%d:: start_values[%d]=%lld  estimate=%lld rate=%g last active=%lld\n",
Packit 577717
				  __FILE__, __LINE__, i, mpx_events->start_values[i],
Packit 577717
				  mpx_events->mev[i]->count_estimate,
Packit 577717
				  mpx_events->mev[i]->rate_estimate,
Packit 577717
				  mpx_events->mev[i]->prev_total_c );
Packit 577717
		}
Packit 577717
	}
Packit 577717
#endif
Packit 577717
Packit 577717
	mpx_release(  );
Packit 577717
Packit 577717
	retval = mpx_startup_itimer(  );
Packit 577717
Packit 577717
	return retval;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
MPX_read( MPX_EventSet * mpx_events, long long *values, int called_by_stop )
Packit 577717
{
Packit 577717
	int i;
Packit 577717
	int retval;
Packit 577717
	long long last_value[2];
Packit 577717
	long long cycles_this_slice = 0;
Packit 577717
	MasterEvent *cur_event;
Packit 577717
	Threadlist *thread_data;
Packit 577717
Packit 577717
	if ( mpx_events->status == MPX_RUNNING ) {
Packit 577717
Packit 577717
		/* Hold timer interrupts while we read values */
Packit 577717
		mpx_hold(  );
Packit 577717
Packit 577717
		thread_data = mpx_events->mythr;
Packit 577717
		cur_event = thread_data->cur_event;
Packit 577717
Packit 577717
		retval = PAPI_read( cur_event->papi_event, last_value );
Packit 577717
		if ( retval != PAPI_OK )
Packit 577717
			return retval;
Packit 577717
Packit 577717
		cycles_this_slice = ( cur_event->pi.event_type == SCALE_EVENT )
Packit 577717
			? last_value[0] : last_value[1];
Packit 577717
Packit 577717
		/* Save the current counter values and get
Packit 577717
		 * the lastest data for the current event
Packit 577717
		 */
Packit 577717
		for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
			MasterEvent *mev = mpx_events->mev[i];
Packit 577717
Packit 577717
			if ( !( mev->is_a_rate ) ) {
Packit 577717
				mpx_events->stop_values[i] = mev->count_estimate;
Packit 577717
			}
Packit 577717
			else {
Packit 577717
				mpx_events->stop_values[i] = mev->count;
Packit 577717
			}
Packit 577717
#ifdef MPX_NONDECR_HYBRID
Packit 577717
			/* If we are called from MPX_stop() then      */
Packit 577717
                        /* adjust the final values based on the       */
Packit 577717
                        /* cycles elapsed since the last read         */
Packit 577717
                        /* otherwise, don't do this as it can cause   */
Packit 577717
                        /* decreasing values if read is called again  */
Packit 577717
                        /* before another sample happens.             */
Packit 577717
Packit 577717
                        if (called_by_stop) {
Packit 577717
Packit 577717
			   /* Extrapolate data up to the current time 
Packit 577717
			    * only if it's not a rate measurement 
Packit 577717
			    */
Packit 577717
			   if ( !( mev->is_a_rate ) ) {
Packit 577717
			      if ( mev != thread_data->cur_event ) {
Packit 577717
				 mpx_events->stop_values[i] +=
Packit 577717
						( long long ) ( mev->rate_estimate *
Packit 577717
										( cycles_this_slice +
Packit 577717
										  thread_data->total_c -
Packit 577717
										  mev->prev_total_c ) );
Packit 577717
				 MPXDBG
Packit 577717
						( "%s:%d:: Inactive %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
Packit 577717
						  __FILE__, __LINE__, i, mpx_events->stop_values[i],
Packit 577717
						  mev->count_estimate, mev->rate_estimate,
Packit 577717
						  cycles_this_slice + thread_data->total_c -
Packit 577717
						  mev->prev_total_c );
Packit 577717
			      } else {
Packit 577717
				 mpx_events->stop_values[i] += last_value[0] +
Packit 577717
						( long long ) ( mev->rate_estimate *
Packit 577717
										( thread_data->total_c -
Packit 577717
										  mev->prev_total_c ) );
Packit 577717
				 MPXDBG
Packit 577717
						( "%s:%d:: -Active- %d, stop values=%lld (est. %lld, rate %g, cycles %lld)\n",
Packit 577717
						  __FILE__, __LINE__, i, mpx_events->stop_values[i],
Packit 577717
						  mev->count_estimate, mev->rate_estimate,
Packit 577717
						  thread_data->total_c - mev->prev_total_c );
Packit 577717
			      }
Packit 577717
			   }
Packit 577717
			}
Packit 577717
#endif
Packit 577717
		}
Packit 577717
Packit 577717
		mpx_events->stop_c = thread_data->total_c + cycles_this_slice;
Packit 577717
Packit 577717
		/* Restore the interrupt */
Packit 577717
		mpx_release(  );
Packit 577717
	}
Packit 577717
Packit 577717
	/* Store the values in user array. */
Packit 577717
	for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
		MasterEvent *mev = mpx_events->mev[i];
Packit 577717
		long long elapsed_slices = 0;
Packit 577717
		long long elapsed_values = mpx_events->stop_values[i]
Packit 577717
			- mpx_events->start_values[i];
Packit 577717
Packit 577717
		/* For rates, cycles contains the number of measurements,
Packit 577717
		 * not the number of cycles, so just divide to compute
Packit 577717
		 * an average value.  This assumes that the rate was
Packit 577717
		 * constant over the whole measurement period.
Packit 577717
		 */
Packit 577717
		values[i] = elapsed_values;
Packit 577717
		if ( mev->is_a_rate ) {
Packit 577717
			/* Handler counts */
Packit 577717
			elapsed_slices = mev->cycles - mpx_events->start_hc[i];
Packit 577717
			values[i] =
Packit 577717
				elapsed_slices ? ( elapsed_values / elapsed_slices ) : 0;
Packit 577717
		}
Packit 577717
		MPXDBG( "%s:%d:: event %d, values=%lld ( %lld - %lld), cycles %lld\n",
Packit 577717
				__FILE__, __LINE__, i,
Packit 577717
				elapsed_values,
Packit 577717
				mpx_events->stop_values[i], mpx_events->start_values[i],
Packit 577717
				mev->is_a_rate ? elapsed_slices : 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	return PAPI_OK;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
MPX_reset( MPX_EventSet * mpx_events )
Packit 577717
{
Packit 577717
	int i, retval;
Packit 577717
	long long values[PAPI_MAX_SW_MPX_EVENTS];
Packit 577717
Packit 577717
	/* Get the current values from MPX_read */
Packit 577717
	retval = MPX_read( mpx_events, values, 0 );
Packit 577717
	if ( retval != PAPI_OK )
Packit 577717
		return retval;
Packit 577717
Packit 577717
	/* Disable timer interrupt */
Packit 577717
	mpx_hold(  );
Packit 577717
Packit 577717
	/* Make counters read zero by setting the start values
Packit 577717
	 * to the current counter values.
Packit 577717
	 */
Packit 577717
	for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
		MasterEvent *mev = mpx_events->mev[i];
Packit 577717
Packit 577717
		if ( mev->is_a_rate ) {
Packit 577717
			mpx_events->start_values[i] = mev->count;
Packit 577717
		} else {
Packit 577717
			mpx_events->start_values[i] += values[i];
Packit 577717
		}
Packit 577717
		mpx_events->start_hc[i] = mev->cycles;
Packit 577717
	}
Packit 577717
Packit 577717
	/* Set the start time for this set to the current cycle count */
Packit 577717
	mpx_events->start_c = mpx_events->stop_c;
Packit 577717
Packit 577717
	/* Restart the interrupt */
Packit 577717
	mpx_release(  );
Packit 577717
Packit 577717
	return PAPI_OK;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
MPX_stop( MPX_EventSet * mpx_events, long long *values )
Packit 577717
{
Packit 577717
	int i, cur_mpx_event;
Packit 577717
	int retval = PAPI_OK;
Packit 577717
	long long dummy_value[2];
Packit 577717
	long long dummy_mpx_values[PAPI_MAX_SW_MPX_EVENTS];
Packit 577717
	/* long long cycles_this_slice, total_cycles; */
Packit 577717
	MasterEvent *cur_event = NULL, *head;
Packit 577717
	Threadlist *thr = NULL;
Packit 577717
Packit 577717
	if ( mpx_events == NULL )
Packit 577717
		return PAPI_EINVAL;
Packit 577717
	if ( mpx_events->status != MPX_RUNNING )
Packit 577717
		return PAPI_ENOTRUN;
Packit 577717
Packit 577717
	/* Read the counter values, this updates mpx_events->stop_values[] */
Packit 577717
	MPXDBG( "Start\n" );
Packit 577717
	if ( values == NULL )
Packit 577717
	  retval = MPX_read( mpx_events, dummy_mpx_values, 1 );
Packit 577717
	else
Packit 577717
	  retval = MPX_read( mpx_events, values, 1 );
Packit 577717
Packit 577717
	/* Block timer interrupts while modifying active events */
Packit 577717
	mpx_hold(  );
Packit 577717
Packit 577717
	/* Get the master event list for this thread. */
Packit 577717
	head = get_my_threads_master_event_list(  );
Packit 577717
	if (!head) {
Packit 577717
	  retval=PAPI_EBUG;
Packit 577717
	  goto exit_mpx_stop;
Packit 577717
	}
Packit 577717
Packit 577717
	/* Get this threads data structure */
Packit 577717
	thr = head->mythr;
Packit 577717
	cur_event = thr->cur_event;
Packit 577717
Packit 577717
	/* This would be a good spot to "hold" the counter and then restart
Packit 577717
	 * it at the end, but PAPI_start resets counters so it is not possible
Packit 577717
	 */
Packit 577717
Packit 577717
	/* Run through all the events decrement their activity counters. */
Packit 577717
	cur_mpx_event = -1;
Packit 577717
	for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
		--mpx_events->mev[i]->active;
Packit 577717
		if ( mpx_events->mev[i] == cur_event )
Packit 577717
			cur_mpx_event = i;
Packit 577717
	}
Packit 577717
Packit 577717
	/* One event in this set is currently running, if this was the
Packit 577717
	 * last active event set using this event, we need to start the next 
Packit 577717
	 * event if there still is one left in the queue
Packit 577717
	 */
Packit 577717
	if ( cur_mpx_event > -1 ) {
Packit 577717
		MasterEvent *tmp, *mev = mpx_events->mev[cur_mpx_event];
Packit 577717
Packit 577717
		if ( mev->active == 0 ) {
Packit 577717
			/* Event is now inactive; stop it 
Packit 577717
			 * There is no need to update master event set 
Packit 577717
			 * counters as this is the last active user
Packit 577717
			 */
Packit 577717
			retval = PAPI_stop( mev->papi_event, dummy_value );
Packit 577717
			mev->rate_estimate = 0.0;
Packit 577717
Packit 577717
			/* Fall-back value if none is found */
Packit 577717
			thr->cur_event = NULL;
Packit 577717
			/* Now find a new cur_event */
Packit 577717
			for ( tmp = ( cur_event->next == NULL ) ? head : cur_event->next;
Packit 577717
				  tmp != cur_event;
Packit 577717
				  tmp = ( tmp->next == NULL ) ? head : tmp->next ) {
Packit 577717
				if ( tmp->active ) {	/* Found the next one to start */
Packit 577717
					thr->cur_event = tmp;
Packit 577717
					break;
Packit 577717
				}
Packit 577717
			}
Packit 577717
Packit 577717
			if ( thr->cur_event != NULL ) {
Packit 577717
				retval = PAPI_start( thr->cur_event->papi_event );
Packit 577717
				assert( retval == PAPI_OK );
Packit 577717
			} else {
Packit 577717
				mpx_shutdown_itimer(  );
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	mpx_events->status = MPX_STOPPED;
Packit 577717
Packit 577717
exit_mpx_stop:
Packit 577717
	MPXDBG( "End\n" );
Packit 577717
Packit 577717
	/* Restore the timer (for other event sets that may be running) */
Packit 577717
	mpx_release(  );
Packit 577717
Packit 577717
	return retval;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
MPX_cleanup( MPX_EventSet ** mpx_events )
Packit 577717
{
Packit 577717
#ifdef PTHREADS
Packit 577717
	int retval;
Packit 577717
#endif
Packit 577717
Packit 577717
	if ( mpx_events == NULL )
Packit 577717
	   return PAPI_EINVAL;
Packit 577717
Packit 577717
	if ( *mpx_events == NULL )
Packit 577717
	   return PAPI_OK;
Packit 577717
Packit 577717
	if (( *mpx_events )->status == MPX_RUNNING )
Packit 577717
	   return PAPI_EINVAL;
Packit 577717
Packit 577717
	mpx_hold(  );
Packit 577717
Packit 577717
	/* Remove master events from this event set and from
Packit 577717
	 * the master list, if necessary.
Packit 577717
	 */
Packit 577717
	mpx_delete_events( *mpx_events );
Packit 577717
Packit 577717
	mpx_release(  );
Packit 577717
Packit 577717
	/* Free all the memory */
Packit 577717
Packit 577717
	papi_free( *mpx_events );
Packit 577717
Packit 577717
	*mpx_events = NULL;
Packit 577717
	return PAPI_OK;
Packit 577717
}
Packit 577717
Packit 577717
void
Packit 577717
MPX_shutdown( void )
Packit 577717
{
Packit 577717
	MPXDBG( "%d\n", getpid(  ) );
Packit 577717
	mpx_shutdown_itimer(  );
Packit 577717
	mpx_restore_signal(  );
Packit 577717
Packit 577717
	if ( tlist ) {
Packit 577717
	       Threadlist *next,*t=tlist;
Packit 577717
Packit 577717
		while(t!=NULL) {
Packit 577717
		   next=t->next;
Packit 577717
		   papi_free( t );
Packit 577717
		   t = next;			
Packit 577717
		}
Packit 577717
		tlist = NULL;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
mpx_check( int EventSet )
Packit 577717
{
Packit 577717
	/* Currently, there is only the need for one mpx check: if
Packit 577717
	 * running on POWER6/perfctr platform, the domain must
Packit 577717
	 * include user, kernel, and supervisor, since the scale
Packit 577717
	 * event uses the dedicated counter #6, PM_RUN_CYC, which
Packit 577717
	 * cannot be controlled on a domain level.
Packit 577717
	 */
Packit 577717
	EventSetInfo_t *ESI = _papi_hwi_lookup_EventSet( EventSet );
Packit 577717
Packit 577717
	if (ESI==NULL) return PAPI_EBUG;
Packit 577717
Packit 577717
	if ( strstr( _papi_hwd[ESI->CmpIdx]->cmp_info.name, "perfctr.c" ) == NULL )
Packit 577717
		return PAPI_OK;
Packit 577717
Packit 577717
	if ( strcmp( _papi_hwi_system_info.hw_info.model_string, "POWER6" ) == 0 ) {
Packit 577717
		unsigned int chk_domain =
Packit 577717
			PAPI_DOM_USER + PAPI_DOM_KERNEL + PAPI_DOM_SUPERVISOR;
Packit 577717
Packit 577717
		if ( ( ESI->domain.domain & chk_domain ) != chk_domain ) {
Packit 577717
			PAPIERROR
Packit 577717
				( "This platform requires PAPI_DOM_USER+PAPI_DOM_KERNEL+PAPI_DOM_SUPERVISOR\n"
Packit 577717
				  "to be set in the domain when using multiplexing.  Instead, found %#x\n",
Packit 577717
				  ESI->domain.domain );
Packit 577717
			return ( PAPI_EINVAL_DOM );
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return PAPI_OK;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
mpx_init( int interval_ns )
Packit 577717
{
Packit 577717
#if defined(PTHREADS) || defined(_POWER6)
Packit 577717
	int retval;
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef _POWER6
Packit 577717
	retval = PAPI_event_name_to_code( "PM_RUN_CYC", &_PNE_PM_RUN_CYC );
Packit 577717
	if ( retval != PAPI_OK )
Packit 577717
		return ( retval );
Packit 577717
#endif
Packit 577717
	tlist = NULL;
Packit 577717
	mpx_hold(  );
Packit 577717
	mpx_shutdown_itimer(  );
Packit 577717
	mpx_init_timers( interval_ns / 1000 );
Packit 577717
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
/** Inserts a list of events into the master event list, 
Packit 577717
   and adds new mev pointers to the MPX_EventSet. 
Packit 577717
   MUST BE CALLED WITH THE TIMER INTERRUPT DISABLED */
Packit 577717
Packit 577717
static int
Packit 577717
mpx_insert_events( MPX_EventSet *mpx_events, int *event_list,
Packit 577717
		   int num_events, int domain, int granularity )
Packit 577717
{
Packit 577717
	int i, retval = 0, num_events_success = 0;
Packit 577717
	MasterEvent *mev;
Packit 577717
	PAPI_option_t options;
Packit 577717
	MasterEvent **head = &mpx_events->mythr->head;
Packit 577717
Packit 577717
	MPXDBG("Inserting %p %d\n",mpx_events,mpx_events->num_events );
Packit 577717
Packit 577717
	/* Make sure we don't overrun our buffers */
Packit 577717
	if (mpx_events->num_events + num_events > PAPI_MAX_SW_MPX_EVENTS) {
Packit 577717
	   return PAPI_ECOUNT;
Packit 577717
	}
Packit 577717
Packit 577717
	/* For each event, see if there is already a corresponding
Packit 577717
	 * event in the master set for this thread.  If not, add it.
Packit 577717
	 */
Packit 577717
	for ( i = 0; i < num_events; i++ ) {
Packit 577717
Packit 577717
		/* Look for a matching event in the master list */
Packit 577717
		for( mev = *head; mev != NULL; mev = mev->next ) {
Packit 577717
		   if ( (mev->pi.event_type == event_list[i]) && 
Packit 577717
			(mev->pi.domain == domain) &&
Packit 577717
			(mev->pi.granularity == granularity ))
Packit 577717
				break;
Packit 577717
		}
Packit 577717
Packit 577717
		/* No matching event in the list; add a new one */
Packit 577717
		if ( mev == NULL ) {
Packit 577717
		   mev = (MasterEvent *) papi_malloc( sizeof ( MasterEvent ) );
Packit 577717
		   if ( mev == NULL ) {
Packit 577717
		      return PAPI_ENOMEM;
Packit 577717
		   }
Packit 577717
Packit 577717
		   mev->pi.event_type = event_list[i];
Packit 577717
		   mev->pi.domain = domain;
Packit 577717
		   mev->pi.granularity = granularity;
Packit 577717
		   mev->uses = mev->active = 0;
Packit 577717
		   mev->prev_total_c = mev->count = mev->cycles = 0;
Packit 577717
		   mev->rate_estimate = 0.0;
Packit 577717
		   mev->count_estimate = 0;
Packit 577717
		   mev->is_a_rate = 0;
Packit 577717
		   mev->papi_event = PAPI_NULL;
Packit 577717
			
Packit 577717
		   retval = PAPI_create_eventset( &( mev->papi_event ) );
Packit 577717
		   if ( retval != PAPI_OK ) {
Packit 577717
		      MPXDBG( "Event %d could not be counted.\n", 
Packit 577717
			      event_list[i] );
Packit 577717
		      goto bail;
Packit 577717
		   }
Packit 577717
Packit 577717
		   retval = PAPI_add_event( mev->papi_event, event_list[i] );
Packit 577717
		   if ( retval != PAPI_OK ) {
Packit 577717
		      MPXDBG( "Event %d could not be counted.\n", 
Packit 577717
			      event_list[i] );
Packit 577717
		      goto bail;
Packit 577717
		   }
Packit 577717
Packit 577717
		   /* Always count total cycles so we can scale results.
Packit 577717
		    * If user just requested cycles, 
Packit 577717
		    * don't add that event again. */
Packit 577717
Packit 577717
		   if ( event_list[i] != SCALE_EVENT ) {
Packit 577717
		      retval = PAPI_add_event( mev->papi_event, SCALE_EVENT );
Packit 577717
		      if ( retval != PAPI_OK ) {
Packit 577717
			 MPXDBG( "Scale event could not be counted "
Packit 577717
				 "at the same time.\n" );
Packit 577717
			 goto bail;
Packit 577717
		      }
Packit 577717
		   }
Packit 577717
			
Packit 577717
		   /* Set the options for the event set */
Packit 577717
		   memset( &options, 0x0, sizeof ( options ) );
Packit 577717
		   options.domain.eventset = mev->papi_event;
Packit 577717
		   options.domain.domain = domain;
Packit 577717
		   retval = PAPI_set_opt( PAPI_DOMAIN, &options );
Packit 577717
		   if ( retval != PAPI_OK ) {
Packit 577717
		      MPXDBG( "PAPI_set_opt(PAPI_DOMAIN, ...) = %d\n", 
Packit 577717
			      retval );
Packit 577717
		      goto bail;
Packit 577717
		   }
Packit 577717
Packit 577717
		   memset( &options, 0x0, sizeof ( options ) );
Packit 577717
		   options.granularity.eventset = mev->papi_event;
Packit 577717
		   options.granularity.granularity = granularity;
Packit 577717
		   retval = PAPI_set_opt( PAPI_GRANUL, &options );
Packit 577717
		   if ( retval != PAPI_OK ) {
Packit 577717
		      if ( retval != PAPI_ECMP ) {
Packit 577717
			 /* ignore component errors because they typically mean
Packit 577717
			    "not supported by the component" */
Packit 577717
			 MPXDBG( "PAPI_set_opt(PAPI_GRANUL, ...) = %d\n", 
Packit 577717
				 retval );
Packit 577717
			 goto bail;
Packit 577717
		      }
Packit 577717
		   }
Packit 577717
Packit 577717
Packit 577717
		   /* Chain the event set into the 
Packit 577717
		    * master list of event sets used in
Packit 577717
		    * multiplexing. */
Packit 577717
Packit 577717
		    mev->next = *head;
Packit 577717
		    *head = mev;
Packit 577717
Packit 577717
		}
Packit 577717
Packit 577717
		/* If we created a new event set, or we found a matching
Packit 577717
		 * eventset already in the list, then add the pointer in
Packit 577717
		 * the master list to this threads list. Then we bump the
Packit 577717
		 * number of successfully added events. */
Packit 577717
	MPXDBG("Inserting now %p %d\n",mpx_events,mpx_events->num_events );
Packit 577717
Packit 577717
		mpx_events->mev[mpx_events->num_events + num_events_success] = mev;
Packit 577717
		mpx_events->mev[mpx_events->num_events + num_events_success]->uses++;
Packit 577717
		num_events_success++;
Packit 577717
Packit 577717
	}
Packit 577717
Packit 577717
	/* Always be sure the head master event points to the thread */
Packit 577717
	if ( *head != NULL ) {
Packit 577717
		( *head )->mythr = mpx_events->mythr;
Packit 577717
	}
Packit 577717
	MPXDBG( "%d of %d events were added.\n", num_events_success, num_events );
Packit 577717
	mpx_events->num_events += num_events_success;
Packit 577717
	return ( PAPI_OK );
Packit 577717
Packit 577717
  bail:
Packit 577717
	/* If there is a current mev, it is currently not linked into the list
Packit 577717
	 * of multiplexing events, so we can just delete that
Packit 577717
	 */
Packit 577717
	if ( mev && mev->papi_event ) {
Packit 577717
	   if (PAPI_cleanup_eventset( mev->papi_event )!=PAPI_OK) {
Packit 577717
	     PAPIERROR("Cleanup eventset\n");
Packit 577717
	   }
Packit 577717
	   if (PAPI_destroy_eventset( &( mev->papi_event )) !=PAPI_OK) {
Packit 577717
	     PAPIERROR("Destory eventset\n");
Packit 577717
	   }
Packit 577717
	}
Packit 577717
	if ( mev )
Packit 577717
		papi_free( mev );
Packit 577717
	mev = NULL;
Packit 577717
Packit 577717
	/* Decrease the usage count of events */
Packit 577717
	for ( i = 0; i < num_events_success; i++ ) {
Packit 577717
		mpx_events->mev[mpx_events->num_events + i]->uses--;
Packit 577717
	}
Packit 577717
Packit 577717
	/* Run the garbage collector to remove unused events */
Packit 577717
	if ( num_events_success )
Packit 577717
		mpx_remove_unused( head );
Packit 577717
Packit 577717
	return ( retval );
Packit 577717
}
Packit 577717
Packit 577717
/** Remove events from an mpx event set (and from the
Packit 577717
 * master event set for this thread, if the events are unused).
Packit 577717
 * MUST BE CALLED WITH THE SIGNAL HANDLER DISABLED
Packit 577717
 */
Packit 577717
static void
Packit 577717
mpx_delete_events( MPX_EventSet * mpx_events )
Packit 577717
{
Packit 577717
	int i;
Packit 577717
	MasterEvent *mev;
Packit 577717
Packit 577717
	/* First decrement the reference counter for each master
Packit 577717
	 * event in this event set, then see if the master events
Packit 577717
	 * can be deleted.
Packit 577717
	 */
Packit 577717
	for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
		mev = mpx_events->mev[i];
Packit 577717
		--mev->uses;
Packit 577717
		mpx_events->mev[i] = NULL;
Packit 577717
		/* If it's no longer used, it should not be active! */
Packit 577717
		assert( mev->uses || !( mev->active ) );
Packit 577717
	}
Packit 577717
	mpx_events->num_events = 0;
Packit 577717
	mpx_remove_unused( &mpx_events->mythr->head );
Packit 577717
}
Packit 577717
Packit 577717
/** Remove one event from an mpx event set (and from the
Packit 577717
 * master event set for this thread, if the events are unused).
Packit 577717
 * MUST BE CALLED WITH THE SIGNAL HANDLER DISABLED
Packit 577717
 */
Packit 577717
static void
Packit 577717
mpx_delete_one_event( MPX_EventSet * mpx_events, int Event )
Packit 577717
{
Packit 577717
	int i;
Packit 577717
	MasterEvent *mev;
Packit 577717
Packit 577717
	/* First decrement the reference counter for each master
Packit 577717
	 * event in this event set, then see if the master events
Packit 577717
	 * can be deleted.
Packit 577717
	 */
Packit 577717
	for ( i = 0; i < mpx_events->num_events; i++ ) {
Packit 577717
		mev = mpx_events->mev[i];
Packit 577717
		if ( mev->pi.event_type == Event ) {
Packit 577717
			--mev->uses;
Packit 577717
			mpx_events->num_events--;
Packit 577717
			mpx_events->mev[i] = NULL;
Packit 577717
			/* If it's no longer used, it should not be active! */
Packit 577717
			assert( mev->uses || !( mev->active ) );
Packit 577717
			break;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/* If we removed an event that is not last in the list we
Packit 577717
	 * need to compact the event list
Packit 577717
	 */
Packit 577717
Packit 577717
	for ( ; i < mpx_events->num_events; i++ ) {
Packit 577717
		mpx_events->mev[i] = mpx_events->mev[i + 1];
Packit 577717
		mpx_events->start_values[i] = mpx_events->start_values[i + 1];
Packit 577717
		mpx_events->stop_values[i] = mpx_events->stop_values[i + 1];
Packit 577717
		mpx_events->start_hc[i] = mpx_events->start_hc[i + 1];
Packit 577717
	}
Packit 577717
	mpx_events->mev[i] = NULL;
Packit 577717
Packit 577717
	mpx_remove_unused( &mpx_events->mythr->head );
Packit 577717
Packit 577717
}
Packit 577717
Packit 577717
/** Remove events that are not used any longer from the run 
Packit 577717
 * list of events to multiplex by the handler
Packit 577717
 * MUST BE CALLED WITH THE SIGNAL HANDLER DISABLED
Packit 577717
 */
Packit 577717
static void
Packit 577717
mpx_remove_unused( MasterEvent ** head )
Packit 577717
{
Packit 577717
	MasterEvent *mev, *lastmev = NULL, *nextmev;
Packit 577717
	Threadlist *thr = ( *head == NULL ) ? NULL : ( *head )->mythr;
Packit 577717
	int retval;
Packit 577717
Packit 577717
	/* Clean up and remove unused master events. */
Packit 577717
	for ( mev = *head; mev != NULL; mev = nextmev ) {
Packit 577717
		nextmev = mev->next; /* get link before mev is freed */
Packit 577717
		if ( !mev->uses ) {
Packit 577717
			if ( lastmev == NULL ) {	/* this was the head event */
Packit 577717
				*head = nextmev;
Packit 577717
			} else {
Packit 577717
				lastmev->next = nextmev;
Packit 577717
			}
Packit 577717
			retval=PAPI_cleanup_eventset( mev->papi_event );
Packit 577717
			retval=PAPI_destroy_eventset( &( mev->papi_event ) );
Packit 577717
			if (retval!=PAPI_OK) PAPIERROR("Error destroying event\n");
Packit 577717
			papi_free( mev );
Packit 577717
		} else {
Packit 577717
			lastmev = mev;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/* Always be sure the head master event points to the thread */
Packit 577717
	if ( *head != NULL ) {
Packit 577717
		( *head )->mythr = thr;
Packit 577717
	}
Packit 577717
}