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