Ejemplo n.º 1
0
static CpuInfo_t *
allocate_cpu( unsigned int cpu_num )
{
   THRDBG("Entry: cpu_num: %d\n", cpu_num);
	CpuInfo_t *cpu;
	int i;

	cpu = ( CpuInfo_t * ) papi_malloc( sizeof ( CpuInfo_t ) );
	if ( cpu == NULL )
		return ( NULL );
	memset( cpu, 0x00, sizeof ( CpuInfo_t ) );
	
	/* identify the cpu this info structure represents */
	cpu->cpu_num = cpu_num;

	cpu->context = ( hwd_context_t ** ) papi_malloc( sizeof ( hwd_context_t * ) *
										  ( size_t ) papi_num_components );
	if ( !cpu->context ) {
		papi_free( cpu );
		return ( NULL );
	}
	
	cpu->running_eventset =
		( EventSetInfo_t ** ) papi_malloc( sizeof ( EventSetInfo_t * ) *
										   ( size_t ) papi_num_components );
	if ( !cpu->running_eventset ) {
		papi_free( cpu->context );
		papi_free( cpu );
		return ( NULL );
	}

	for ( i = 0; i < papi_num_components; i++ ) {
		cpu->context[i] =
			( void * ) papi_malloc( ( size_t ) _papi_hwd[i]->size.context );
		cpu->running_eventset[i] = NULL;
		if ( cpu->context[i] == NULL ) {
			for ( i--; i >= 0; i-- )
				papi_free( cpu->context[i] );
			papi_free( cpu->context );
			papi_free( cpu );
			return ( NULL );
		}
		memset( cpu->context[i], 0x00,
				( size_t ) _papi_hwd[i]->size.context );
	}

	THRDBG( "Allocated CpuInfo: %p\n", cpu );
	return ( cpu );
}
Ejemplo n.º 2
0
/** Initialize hardware counters, setup the function vector table
 * and get hardware information, this routine is called when the
 * PAPI process is initialized (IE PAPI_library_init)
 */
int coretemp_init_substrate ()
{
	int ret;
	int i;
	int mib[4];
	size_t len;
	char tmp[128];

	SUBDBG("coretemp_init_substrate...\n");

	/* Count the number of cores (counters) that have sensors allocated */
	i = 0;
	CORETEMP_NUM_EVENTS = 0;
	sprintf (tmp, "dev.coretemp.%d.%%driver", i);
	len = 4;
	ret = sysctlnametomib (tmp, mib, &len);
	while (ret != -1)
	{
		CORETEMP_NUM_EVENTS++;
		i++;
		sprintf (tmp, "dev.coretemp.%d.%%driver", i);
		len = 4;
		ret = sysctlnametomib (tmp, mib, &len);
	}

	/* Allocate memory for the our event table */
	coretemp_native_table = (coretemp_native_event_entry_t *)
		papi_malloc (sizeof (coretemp_native_event_entry_t) * CORETEMP_NUM_EVENTS);
	if (coretemp_native_table == NULL)
	{
		perror( "malloc():Could not get memory for coretemp events table" );
		return EXIT_FAILURE;
	}

	/* Allocate native events internal structures */
	for (i = 0; i < CORETEMP_NUM_EVENTS; i++)
	{
		/* Event name */
		sprintf (coretemp_native_table[i].name, "CORETEMP_CPU_%d", i);

		/* Event description */
		sprintf (coretemp_native_table[i].description, "CPU On-Die Thermal Sensor #%d", i);

		/* Event extra bits -> save MIB to faster access later */
		sprintf (tmp, "dev.cpu.%d.temperature", i);
		len = 4;
		if (sysctlnametomib (tmp, coretemp_native_table[i].resources.mib, &len) == -1)
			return PAPI_ESBSTR;

		coretemp_native_table[i].resources.selector = i+1;
	}

	return PAPI_OK;
}
Ejemplo n.º 3
0
static MPX_EventSet *
mpx_malloc( Threadlist * t )
{
	MPX_EventSet *newset =
		( MPX_EventSet * ) papi_malloc( sizeof ( MPX_EventSet ) );
	if ( newset == NULL )
		return ( NULL );
	memset( newset, 0, sizeof ( MPX_EventSet ) );
	newset->status = MPX_STOPPED;
	newset->mythr = t;
	return ( newset );
}
/* The function below, _xml_content(), is a hook into expat's XML
 * parser.  _xml_content() defines how the parser handles the
 * text between tags in PAPI's XML file.  The information between
 * tags is usally text for event descriptions.
 */
static void _xml_content(void *data, const char *el, const int len) {
   int i;
   if(location==SPARSE_DESC) {
      _papi_hwi_presets.info[sparse_index].long_descr = papi_malloc(len+1);
      for(i=0; i<len; i++) _papi_hwi_presets.info[sparse_index].long_descr[i]=el[i];
      _papi_hwi_presets.info[sparse_index].long_descr[len]='\0';
      /* the XML data currently doesn't contain a short description */
      _papi_hwi_presets.info[sparse_index].short_descr = NULL;
      sparse_index++;
      _papi_hwi_presets.data[sparse_index] = NULL;
      location=SPARSE_EVENT_SEARCH;
   }
}
Ejemplo n.º 5
0
/******************************************************************************
 ********  BEGIN FUNCTIONS  USED INTERNALLY SPECIFIC TO THIS COMPONENT ********
 *****************************************************************************/
static int resize_native_table() {
	counter_info** new_table;
	int new_size = table_size*2;
	new_table = (counter_info**)papi_malloc(sizeof(counter_info*) * new_size);
	if (NULL==new_table)
		return PAPI_ENOMEM;
	if ( lustre_native_table) {
		memcpy(new_table, lustre_native_table, sizeof(counter_info*) * table_size );
		papi_free(lustre_native_table);
	}
	lustre_native_table = new_table;
	table_size*=2;
	return PAPI_OK;
}
Ejemplo n.º 6
0
/* Initialize hardware counters, setup the function vector table
 * and get hardware information, this routine is called when the
 * PAPI process is initialized (IE PAPI_library_init)
 */
int
_net_init_component( int cidx  )
{
    int i = 0;
    struct temp_event *t, *last;

    if ( is_initialized )
        return PAPI_OK;

    memset(_net_register_start, 0,
           NET_MAX_COUNTERS*sizeof(_net_register_start[0]));
    memset(_net_register_current, 0,
           NET_MAX_COUNTERS*sizeof(_net_register_current[0]));

    is_initialized = 1;

    /* The network interfaces are listed in /proc/net/dev */
    num_events = generateNetEventList();

    if ( num_events < 0 )  /* PAPI errors */
        return num_events;

    if ( num_events == 0 )  /* No network interfaces found */
        return PAPI_OK;

    t = root;
    _net_native_events = (NET_native_event_entry_t*)
                         papi_malloc(sizeof(NET_native_event_entry_t) * num_events);
    do {
        strncpy(_net_native_events[i].name, t->name, PAPI_MAX_STR_LEN-1);
        _net_native_events[i].name[PAPI_MAX_STR_LEN-1] = '\0';
        strncpy(_net_native_events[i].description, t->description, PAPI_MAX_STR_LEN-1);
        _net_native_events[i].description[PAPI_MAX_STR_LEN-1] = '\0';
        _net_native_events[i].resources.selector = i + 1;
        last    = t;
        t       = t->next;
        papi_free(last);
        i++;
    } while (t != NULL);
    root = NULL;

    /* Export the total number of events available */
    _net_vector.cmp_info.num_native_events = num_events;

    /* Export the component id */
    _net_vector.cmp_info.CmpIdx = cidx;

    return PAPI_OK;
}
Ejemplo n.º 7
0
/** @internal
 * This function is called to determine the state of the system.
 * We may as well set the HighLevelInfo so you don't have to look it
 * up again.
 */
int
_internal_check_state( HighLevelInfo ** outgoing )
{
    int retval;
    HighLevelInfo *state = NULL;

    /* Only allow one thread at a time in here */
    if ( init_level == PAPI_NOT_INITED ) {
        retval = PAPI_library_init( PAPI_VER_CURRENT );
        if ( retval != PAPI_VER_CURRENT ) {
            return ( retval );
        } else {
            _papi_hwi_lock( HIGHLEVEL_LOCK );
            init_level = PAPI_HIGH_LEVEL_INITED;
            _papi_hwi_unlock( HIGHLEVEL_LOCK );
        }
    }

    /*
     * Do we have the thread specific data setup yet?
     */
    if ( ( retval =
                PAPI_get_thr_specific( PAPI_HIGH_LEVEL_TLS, ( void * ) &state ) )
            != PAPI_OK || state == NULL ) {
        state = ( HighLevelInfo * ) papi_malloc( sizeof ( HighLevelInfo ) );
        if ( state == NULL )
            return ( PAPI_ENOMEM );

        memset( state, 0, sizeof ( HighLevelInfo ) );
        state->EventSet = -1;

        if ( ( retval = PAPI_create_eventset( &state->EventSet ) ) != PAPI_OK )
            return ( retval );

        if ( ( retval =
                    PAPI_set_thr_specific( PAPI_HIGH_LEVEL_TLS,
                                           state ) ) != PAPI_OK )
            return ( retval );
    }
    *outgoing = state;
    return ( PAPI_OK );
}
Ejemplo n.º 8
0
static ThreadInfo_t *
allocate_thread( int tid )
{
	ThreadInfo_t *thread;
	int i;

	/* The Thread EventSet is special. It is not in the EventSet list, but is pointed
	   to by each EventSet of that particular thread. */

	thread = ( ThreadInfo_t * ) papi_malloc( sizeof ( ThreadInfo_t ) );
	if ( thread == NULL )
		return ( NULL );
	memset( thread, 0x00, sizeof ( ThreadInfo_t ) );

	thread->context =
		( hwd_context_t ** ) papi_malloc( sizeof ( hwd_context_t * ) *
										  ( size_t ) papi_num_components );
	if ( !thread->context ) {
		papi_free( thread );
		return ( NULL );
	}

	thread->running_eventset =
		( EventSetInfo_t ** ) papi_malloc( sizeof ( EventSetInfo_t * ) *
										   ( size_t ) papi_num_components );
	if ( !thread->running_eventset ) {
		papi_free( thread->context );
		papi_free( thread );
		return ( NULL );
	}

	for ( i = 0; i < papi_num_components; i++ ) {
		thread->context[i] =
			( void * ) papi_malloc( ( size_t ) _papi_hwd[i]->size.context );
		thread->running_eventset[i] = NULL;
		if ( thread->context[i] == NULL ) {
			for ( i--; i >= 0; i-- )
				papi_free( thread->context[i] );
			papi_free( thread->context );
			papi_free( thread );
			return ( NULL );
		}
		memset( thread->context[i], 0x00,
				( size_t ) _papi_hwd[i]->size.context );
	}

	if ( _papi_hwi_thread_id_fn ) {
           thread->tid = ( *_papi_hwi_thread_id_fn ) (  );
	}
	else {
	   thread->tid = ( unsigned long ) getpid(  );
	}

	thread->allocator_tid=thread->tid;

	if (tid == 0 ) {
	}
	else {
	  thread->tid=tid;
	}

	THRDBG( "Allocated thread %ld at %p, allocator: %ld\n", thread->tid, 
		thread,
		thread->allocator_tid );

	return thread;
}
Ejemplo n.º 9
0
int
_ultra_hwd_update_shlib_info( papi_mdi_t *mdi )
{
	/*??? system call takes very long */

	char cmd_line[PAPI_HUGE_STR_LEN + PAPI_HUGE_STR_LEN], fname[L_tmpnam];
	char line[256];
	char address[16], size[10], flags[64], objname[256];
	PAPI_address_map_t *tmp = NULL;

	FILE *f = NULL;
	int t_index = 0, i;
	struct map_record
	{
		long address;
		int size;
		int flags;
		char objname[256];
		struct map_record *next;
	} *tmpr, *head, *curr;

	tmpnam( fname );
	SUBDBG( "Temporary name %s\n", fname );

	sprintf( cmd_line, "/bin/pmap %d > %s", ( int ) getpid(  ), fname );
	if ( system( cmd_line ) != 0 ) {
		PAPIERROR( "Could not run %s to get shared library address map",
				   cmd_line );
		return ( PAPI_OK );
	}

	f = fopen( fname, "r" );
	if ( f == NULL ) {
		PAPIERROR( "fopen(%s) returned < 0", fname );
		remove( fname );
		return ( PAPI_OK );
	}

	/* ignore the first line */
	fgets( line, 256, f );
	head = curr = NULL;
	while ( fgets( line, 256, f ) != NULL ) {
		/* discard the last line */
		if ( strncmp( line, " total", 6 ) != 0 ) {
			sscanf( line, "%s %s %s %s", address, size, flags, objname );
			if ( objname[0] == '/' ) {
				tmpr =
					( struct map_record * )
					papi_malloc( sizeof ( struct map_record ) );
				if ( tmpr == NULL )
					return ( -1 );
				tmpr->next = NULL;
				if ( curr ) {
					curr->next = tmpr;
					curr = tmpr;
				}
				if ( head == NULL ) {
					curr = head = tmpr;
				}

				SUBDBG( "%s\n", objname );

				if ( ( strstr( flags, "read" ) && strstr( flags, "exec" ) ) ||
					 ( strstr( flags, "r" ) && strstr( flags, "x" ) ) ) {
					if ( !( strstr( flags, "write" ) || strstr( flags, "w" ) ) ) {	/* text segment */
						t_index++;
						tmpr->flags = 1;
					} else {
						tmpr->flags = 0;
					}
					sscanf( address, "%lx", &tmpr->address );
					sscanf( size, "%d", &tmpr->size );
					tmpr->size *= 1024;
					strcpy( tmpr->objname, objname );
				}

			}

		}
	}
	tmp =
		( PAPI_address_map_t * ) papi_calloc( t_index - 1,
											  sizeof ( PAPI_address_map_t ) );

	if ( tmp == NULL ) {
		PAPIERROR( "Error allocating shared library address map" );
		return ( PAPI_ENOMEM );
	}

	t_index = -1;
	tmpr = curr = head;
	i = 0;
	while ( curr != NULL ) {
		if ( strcmp( _papi_hwi_system_info.exe_info.address_info.name,
					 basename( curr->objname ) ) == 0 ) {
			if ( curr->flags ) {
				_papi_hwi_system_info.exe_info.address_info.text_start =
					( caddr_t ) curr->address;
				_papi_hwi_system_info.exe_info.address_info.text_end =
					( caddr_t ) ( curr->address + curr->size );
			} else {
				_papi_hwi_system_info.exe_info.address_info.data_start =
					( caddr_t ) curr->address;
				_papi_hwi_system_info.exe_info.address_info.data_end =
					( caddr_t ) ( curr->address + curr->size );
			}
		} else {
			if ( curr->flags ) {
				t_index++;
				tmp[t_index].text_start = ( caddr_t ) curr->address;
				tmp[t_index].text_end =
					( caddr_t ) ( curr->address + curr->size );
				strncpy( tmp[t_index].name, curr->objname,
						 PAPI_HUGE_STR_LEN - 1 );
				tmp[t_index].name[PAPI_HUGE_STR_LEN - 1] = '\0';
			} else {
				if ( t_index < 0 )
					continue;
				tmp[t_index].data_start = ( caddr_t ) curr->address;
				tmp[t_index].data_end =
					( caddr_t ) ( curr->address + curr->size );
			}
		}
		tmpr = curr->next;
		/* free the temporary allocated memory */
		papi_free( curr );
		curr = tmpr;
	}						 /* end of while */

	remove( fname );
	fclose( f );
	if ( _papi_hwi_system_info.shlib_info.map )
		papi_free( _papi_hwi_system_info.shlib_info.map );
	_papi_hwi_system_info.shlib_info.map = tmp;
	_papi_hwi_system_info.shlib_info.count = t_index + 1;

	return ( PAPI_OK );

}
Ejemplo n.º 10
0
static int
build_tables( void )
{
	int i;
	int regno;
	int npic;
	einfo_t *ep;
	int n;
	int npresets;
	npic = cpc_getnpic( cpuver );
	nctrs = 0;
	for ( regno = 0; regno < npic; ++regno ) {
		cpc_walk_names( cpuver, regno, 0, action );
	}
	SUBDBG( "%d counters\n", nctrs );
	if ( ( ctrs = papi_malloc( nctrs * sizeof ( struct ctr_info ) ) ) == 0 ) {
		return PAPI_ENOMEM;
	}
	nctrs = 0;
	for ( regno = 0; regno < npic; ++regno ) {
		cpc_walk_names( cpuver, regno, ( void * ) 1, action );
	}
	SUBDBG( "%d counters\n", nctrs );
#if DEBUG
	if ( ISLEVEL( DEBUG_SUBSTRATE ) ) {
		for ( i = 0; i < nctrs; ++i ) {
			SUBDBG( "%s: bits (%x,%x) pics %x\n", ctrs[i].name, ctrs[i].bits[0],
					ctrs[i].bits[1], ctrs[i].bitmask );
		}
	}
#endif
	/* Build the native event table */
	if ( ( native_table =
		   papi_malloc( nctrs * sizeof ( native_info_t ) ) ) == 0 ) {
		papi_free( ctrs );
		return PAPI_ENOMEM;
	}
	for ( i = 0; i < nctrs; ++i ) {
		native_table[i].name[39] = 0;
		strncpy( native_table[i].name, ctrs[i].name, 39 );
		if ( ctrs[i].bitmask & 1 )
			native_table[i].encoding[0] = ctrs[i].bits[0];
		else
			native_table[i].encoding[0] = -1;
		if ( ctrs[i].bitmask & 2 )
			native_table[i].encoding[1] = ctrs[i].bits[1];
		else
			native_table[i].encoding[1] = -1;
	}
	papi_free( ctrs );

	/* Build the preset table */
	if ( cpuver <= CPC_ULTRA2 ) {
		n = sizeof ( us2info ) / sizeof ( einfo_t );
		ep = us2info;
	} else if ( cpuver <= LASTULTRA3 ) {
		n = sizeof ( us3info ) / sizeof ( einfo_t );
		ep = us3info;
	} else
		return PAPI_ESBSTR;
	preset_table = papi_malloc( ( n + 1 ) * sizeof ( hwi_search_t ) );
	npresets = 0;
	for ( i = 0; i < n; ++i ) {
		add_preset( preset_table, &npresets, ep[i] );
	}
	memset( &preset_table[npresets], 0, sizeof ( hwi_search_t ) );

#ifdef DEBUG
	if ( ISLEVEL( DEBUG_SUBSTRATE ) ) {
		SUBDBG( "Native table: %d\n", nctrs );
		for ( i = 0; i < nctrs; ++i ) {
			SUBDBG( "%40s: %8x %8x\n", native_table[i].name,
					native_table[i].encoding[0], native_table[i].encoding[1] );
		}
		SUBDBG( "\nPreset table: %d\n", npresets );
		for ( i = 0; preset_table[i].event_code != 0; ++i ) {
			SUBDBG( "%8x: op %2d e0 %8x e1 %8x\n",
					preset_table[i].event_code,
					preset_table[i].data.derived,
					preset_table[i].data.native[0],
					preset_table[i].data.native[1] );
		}
	}
#endif

	_solaris_vector.cmp_info.num_native_events = nctrs;

	return PAPI_OK;
}
Ejemplo n.º 11
0
/** Initialize hardware counters, setup the function vector table
 * and get hardware information, this routine is called when the
 * PAPI process is initialized (IE PAPI_library_init)
 */
		int
_papi_nvml_init_substrate( int cidx )
{
		nvmlReturn_t ret;
		cudaError_t cuerr;

		int cuda_count = 0;
		unsigned int nvml_count = 0;

		ret = nvmlInit();
		if ( NVML_SUCCESS != ret ) {
				strcpy(_nvml_vector.cmp_info.disabled_reason, "The NVIDIA managament library failed to initialize.");
				goto disable;
		}

		cuerr = cuInit( 0 );
		if ( CUDA_SUCCESS != cuerr ) {
				strcpy(_nvml_vector.cmp_info.disabled_reason, "The CUDA library failed to initialize.");
				goto disable;
		}

		/* Figure out the number of CUDA devices in the system */
		ret = nvmlDeviceGetCount( &nvml_count );
		if ( NVML_SUCCESS != ret ) {
				strcpy(_nvml_vector.cmp_info.disabled_reason, "Unable to get a count of devices from the NVIDIA managament library.");
				goto disable;
		}

		cuerr = cudaGetDeviceCount( &cuda_count );
		if ( CUDA_SUCCESS != cuerr ) {
				strcpy(_nvml_vector.cmp_info.disabled_reason, "Unable to get a device count from CUDA.");
				goto disable;
		}

		/* We can probably recover from this, when we're clever */
		if ( nvml_count != cuda_count ) {
				strcpy(_nvml_vector.cmp_info.disabled_reason, "Cuda and the NVIDIA managament library have different device counts.");
				goto disable;
		}

		device_count = cuda_count;

		/* A per device representation of what events are present */
		features = (int*)papi_malloc(sizeof(int) * device_count );

		/* Handles to each device */
		devices = (nvmlDevice_t*)papi_malloc(sizeof(nvmlDevice_t) * device_count);

		/* Figure out what events are supported on each card. */
		if ( (papi_errorcode = detectDevices( ) ) != PAPI_OK ) {
			papi_free(features);
			papi_free(devices);
			sprintf(_nvml_vector.cmp_info.disabled_reason, "An error occured in device feature detection, please check your NVIDIA Management Library and CUDA install." );
			goto disable;
		}

		/* The assumption is that if everything went swimmingly in detectDevices, 
			all nvml calls here should be fine. */
		createNativeEvents( );

		/* Export the total number of events available */
		_nvml_vector.cmp_info.num_native_events = num_events;

		/* Export the component id */
		_nvml_vector.cmp_info.CmpIdx = cidx;

		/* Export the number of 'counters' */
		_nvml_vector.cmp_info.num_cntrs = num_events;

		return PAPI_OK;

disable:
		_nvml_vector.cmp_info.num_cntrs = 0;
		return PAPI_OK;	
}
Ejemplo n.º 12
0
/* The function below, _xml_start(), is a hook into expat's XML
 * parser.  _xml_start() defines how the parser handles the
 * opening tags in PAPI's XML file.  This function can be understood
 * more easily if you follow along with its logic while looking at
 * papi_events.xml.  The location variable is a global telling us
 * where we are in the XML file.  Have we found our architecture's
 * events yet?  Are we looking at an event definition?...etc.
 */
static void
_xml_start( void *data, const char *el, const char **attr )
{
	int native_encoding;

	if ( location == SPARSE_BEGIN && !strcmp( "papistdevents", el ) ) {
		location = SPARSE_EVENT_SEARCH;
	} else if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
		_papi_hwi_presets[sparse_index].info.symbol = papi_strdup( attr[1] );
//      strcpy(_papi_hwi_presets.info[sparse_index].symbol, attr[1]);
		location = SPARSE_EVENT;
	} else if ( location == SPARSE_EVENT && !strcmp( "desc", el ) ) {
		location = SPARSE_DESC;
	} else if ( location == ARCH_SEARCH && !strcmp( "availevents", el ) &&
				!strcmp( xml_arch, attr[1] ) ) {
		location = DENSE_EVENT_SEARCH;
	} else if ( location == DENSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
		if ( !strcmp( "PAPI_NULL", attr[1] ) ) {
			location = FINISHED;
			return;
		} else if ( PAPI_event_name_to_code( ( char * ) attr[1], &sparse_index )
					!= PAPI_OK ) {
			PAPIERROR( "Improper Preset name given in XML file for %s.",
					   attr[1] );
			error = 1;
		}
		sparse_index &= PAPI_PRESET_AND_MASK;

		/* allocate and initialize data space for this event */
		papi_valid_free( _papi_hwi_presets[sparse_index].data );
		_papi_hwi_presets[sparse_index].data =
			papi_malloc( sizeof ( hwi_preset_data_t ) );
		native_index = 0;
		_papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
		_papi_hwi_presets[sparse_index].data->operation[0] = '\0';


		if ( attr[2] ) {	 /* derived event */
			_papi_hwi_presets[sparse_index].data->derived =
				_papi_hwi_derived_type( ( char * ) attr[3] );
			/* where does DERIVED POSTSCRIPT get encoded?? */
			if ( _papi_hwi_presets[sparse_index].data->derived == -1 ) {
				PAPIERROR( "No derived type match for %s in Preset XML file.",
						   attr[3] );
				error = 1;
			}

			if ( attr[5] ) {
				_papi_hwi_presets[sparse_index].count = atoi( attr[5] );
			} else {
				PAPIERROR( "No count given for %s in Preset XML file.",
						   attr[1] );
				error = 1;
			}
		} else {
			_papi_hwi_presets[sparse_index].data->derived = NOT_DERIVED;
			_papi_hwi_presets[sparse_index].count = 1;
		}
		location = DENSE_NATIVE_SEARCH;
	} else if ( location == DENSE_NATIVE_SEARCH && !strcmp( "native", el ) ) {
		location = DENSE_NATIVE_DESC;
	} else if ( location == DENSE_NATIVE_DESC && !strcmp( "event", el ) ) {
		if ( _papi_hwi_native_name_to_code( attr[1], &native_encoding ) !=
			 PAPI_OK ) {
			printf( "Improper Native name given in XML file for %s\n",
					attr[1] );
			PAPIERROR( "Improper Native name given in XML file for %s\n",
					   attr[1] );
			error = 1;
		}
		_papi_hwi_presets[sparse_index].data->native[native_index] =
			native_encoding;
		native_index++;
		_papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
	} else if ( location && location != ARCH_SEARCH && location != FINISHED ) {
		PAPIERROR( "Poorly-formed Preset XML document." );
		error = 1;
	}
}
Ejemplo n.º 13
0
		static void
createNativeEvents( )
{
		char name[64];
		char sanitized_name[PAPI_MAX_STR_LEN];
		char names[device_count][64];

		int i, nameLen = 0, j;
		int isUnique = 1;

		nvml_native_event_entry_t* entry;
		nvmlReturn_t ret;

		nvml_native_table = (nvml_native_event_entry_t*) papi_malloc( 
						sizeof(nvml_native_event_entry_t) * num_events ); 	
		memset( nvml_native_table, 0x0, sizeof(nvml_native_event_entry_t) * num_events );
		entry = &nvml_native_table[0];

		for (i=0; i < device_count; i++ ) {
				memset( names[i], 0x0, 64 );
				isUnique = 1;
				ret = nvmlDeviceGetName( devices[i], name, 64 );

				for (j=0; j < i; j++ ) 
				{
						if ( 0 == strncmp( name, names[j], 64 ) )
								isUnique = 0;
				}

				if ( isUnique ) {
						nameLen = strlen(name);
						strncpy(sanitized_name, name, PAPI_MAX_STR_LEN );
						for (j=0; j < nameLen; j++)
								if ( ' ' == sanitized_name[j] )
										sanitized_name[j] = '_';



						if ( HAS_FEATURE( features[i], FEATURE_CLOCK_INFO ) ) {
								sprintf( entry->name, "NVML.%s.graphics_clock", sanitized_name );
								strncpy(entry->description,"Graphics clock domain (MHz).", PAPI_MAX_STR_LEN );
								entry->options.clock = NVML_CLOCK_GRAPHICS;
								entry->type = FEATURE_CLOCK_INFO;
								entry++;

								sprintf( entry->name, "NVML.%s.sm_clock", sanitized_name);
								strncpy(entry->description,"SM clock domain (MHz).", PAPI_MAX_STR_LEN);
								entry->options.clock = NVML_CLOCK_SM;
								entry->type = FEATURE_CLOCK_INFO;
								entry++;

								sprintf( entry->name, "NVML.%s.memory_clock", sanitized_name);
								strncpy(entry->description,"Memory clock domain (MHz).", PAPI_MAX_STR_LEN);
								entry->options.clock = NVML_CLOCK_MEM;
								entry->type = FEATURE_CLOCK_INFO;
								entry++;
						}	

						if ( HAS_FEATURE( features[i], FEATURE_ECC_LOCAL_ERRORS ) ) { 
								sprintf(entry->name, "NVML.%s.l1_single_ecc_errors", sanitized_name);
								strncpy(entry->description,"L1 cache single bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_SINGLE_BIT_ECC,
												.which_one = LOCAL_ECC_L1,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.l2_single_ecc_errors", sanitized_name);
								strncpy(entry->description,"L2 cache single bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_SINGLE_BIT_ECC,
												.which_one = LOCAL_ECC_L2,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.memory_single_ecc_errors", sanitized_name);
								strncpy(entry->description,"Device memory single bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_SINGLE_BIT_ECC,
												.which_one = LOCAL_ECC_MEM,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.regfile_single_ecc_errors", sanitized_name);
								strncpy(entry->description,"Register file single bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_SINGLE_BIT_ECC,
												.which_one = LOCAL_ECC_REGFILE,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.1l_double_ecc_errors", sanitized_name);
								strncpy(entry->description,"L1 cache double bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_DOUBLE_BIT_ECC,
												.which_one = LOCAL_ECC_L1,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.l2_double_ecc_errors", sanitized_name);
								strncpy(entry->description,"L2 cache double bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_DOUBLE_BIT_ECC,
												.which_one = LOCAL_ECC_L2,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.memory_double_ecc_errors", sanitized_name);
								strncpy(entry->description,"Device memory double bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_DOUBLE_BIT_ECC,
												.which_one = LOCAL_ECC_MEM,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;

								sprintf(entry->name, "NVML.%s.regfile_double_ecc_errors", sanitized_name);
								strncpy(entry->description,"Register file double bit ECC", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){
										.bits = NVML_DOUBLE_BIT_ECC,
												.which_one = LOCAL_ECC_REGFILE,
								};
								entry->type = FEATURE_ECC_LOCAL_ERRORS;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_FAN_SPEED ) ) {
								sprintf( entry->name, "NVML.%s.fan_speed", sanitized_name);
								strncpy(entry->description,"The fan speed expressed as a percent of the maximum, i.e. full speed is 100%", PAPI_MAX_STR_LEN);
								entry->type = FEATURE_FAN_SPEED;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_MAX_CLOCK ) ) {
								sprintf( entry->name, "NVML.%s.graphics_max_clock", sanitized_name);
								strncpy(entry->description,"Maximal Graphics clock domain (MHz).", PAPI_MAX_STR_LEN);
								entry->options.clock = NVML_CLOCK_GRAPHICS;
								entry->type = FEATURE_MAX_CLOCK;
								entry++;

								sprintf( entry->name, "NVML.%s.sm_max_clock", sanitized_name);
								strncpy(entry->description,"Maximal SM clock domain (MHz).", PAPI_MAX_STR_LEN);
								entry->options.clock = NVML_CLOCK_SM;
								entry->type = FEATURE_MAX_CLOCK;
								entry++;

								sprintf( entry->name, "NVML.%s.memory_max_clock", sanitized_name);
								strncpy(entry->description,"Maximal Memory clock domain (MHz).", PAPI_MAX_STR_LEN);
								entry->options.clock = NVML_CLOCK_MEM;
								entry->type = FEATURE_MAX_CLOCK;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_MEMORY_INFO ) ) {
								sprintf( entry->name, "NVML.%s.total_memory", sanitized_name);
								strncpy(entry->description,"Total installed FB memory (in bytes).", PAPI_MAX_STR_LEN);
								entry->options.which_one = MEMINFO_TOTAL_MEMORY;
								entry->type = FEATURE_MEMORY_INFO;
								entry++;

								sprintf( entry->name, "NVML.%s.unallocated_memory", sanitized_name);
								strncpy(entry->description,"Uncallocated FB memory (in bytes).", PAPI_MAX_STR_LEN);
								entry->options.which_one = MEMINFO_UNALLOCED;
								entry->type = FEATURE_MEMORY_INFO;
								entry++;

								sprintf( entry->name, "NVML.%s.allocated_memory", sanitized_name);
								strncpy(entry->description,	"Allocated FB memory (in bytes). Note that the driver/GPU always sets aside a small amount of memory for bookkeeping.", PAPI_MAX_STR_LEN);
								entry->options.which_one = MEMINFO_ALLOCED;
								entry->type = FEATURE_MEMORY_INFO;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_PERF_STATES ) ) {
								sprintf( entry->name, "NVML.%s.pstate", sanitized_name);
								strncpy(entry->description,"The performance state of the device.", PAPI_MAX_STR_LEN);
								entry->type = FEATURE_PERF_STATES;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_POWER ) ) {
								sprintf( entry->name, "NVML.%s.power", sanitized_name);
								strncpy(entry->description,"Power usage reading for the device, in miliwatts. This is the power draw for the entire board, including GPU, memory, etc.\n The reading is accurate to within a range of +/-5 watts.", PAPI_MAX_STR_LEN);
								entry->type = FEATURE_POWER;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_TEMP ) ) {
								sprintf( entry->name, "NVML.%s.temperature", sanitized_name);
								strncpy(entry->description,"Current temperature readings for the device, in degrees C.", PAPI_MAX_STR_LEN);
								entry->type = FEATURE_TEMP;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_ECC_TOTAL_ERRORS ) ) {
								sprintf( entry->name, "NVML.%s.total_ecc_errors", sanitized_name);
								strncpy(entry->description,"Total single bit errors.", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){ 
										.bits = NVML_SINGLE_BIT_ECC, 
								};
								entry->type = FEATURE_ECC_TOTAL_ERRORS;
								entry++;

								sprintf( entry->name, "NVML.%s.total_ecc_errors", sanitized_name);
								strncpy(entry->description,"Total double bit errors.", PAPI_MAX_STR_LEN);
								entry->options.ecc_opts = (struct local_ecc){ 
										.bits = NVML_DOUBLE_BIT_ECC, 
								};
								entry->type = FEATURE_ECC_TOTAL_ERRORS;
								entry++;
						}

						if ( HAS_FEATURE( features[i], FEATURE_UTILIZATION ) ) {
								sprintf( entry->name, "NVML.%s.gpu_utilization", sanitized_name);
								strncpy(entry->description,"Percent of time over the past second during which one or more kernels was executing on the GPU.", PAPI_MAX_STR_LEN);
								entry->options.which_one = GPU_UTILIZATION;
								entry->type = FEATURE_UTILIZATION;
								entry++;

								sprintf( entry->name, "NVML.%s.memory_utilization", sanitized_name);
								strncpy(entry->description,"Percent of time over the past second during which global (device) memory was being read or written.", PAPI_MAX_STR_LEN);
								entry->options.which_one = MEMORY_UTILIZATION;
								entry->type = FEATURE_UTILIZATION;
								entry++;
						}
						strncpy( names[i], name, 64); 
				}
		}
}
Ejemplo n.º 14
0
/*
 * find all network interfaces listed in /proc/net/dev
 */
static int
generateNetEventList( void )
{
    FILE *fin;
    char line[NET_PROC_MAX_LINE];
    char *retval, *ifname;
    int count = 0;
    struct temp_event *temp;
    struct temp_event *last = NULL;
    int i, j;

    fin = fopen(NET_PROC_FILE, "r");
    if (fin == NULL) {
        SUBDBG("Can't find %s, are you sure the /proc file-system is mounted?\n",
           NET_PROC_FILE);
        return 0;
    }

    /* skip the 2 header lines */
    for (i=0; i<2; i++) {
        retval = fgets (line, NET_PROC_MAX_LINE, fin);
        if (retval == NULL) {
        	fclose(fin);
            SUBDBG("Not enough lines in %s\n", NET_PROC_FILE);
            return 0;
        }
    }

    while ((fgets (line, NET_PROC_MAX_LINE, fin)) == line) {

        /* split the interface name from the 16 counters */
        retval = strstr(line, ":");
        if (retval == NULL) {
            SUBDBG("Wrong line format <%s>\n", line);
            continue;
        }

        *retval = '\0';
        ifname = line;
        while (isspace(*ifname)) { ifname++; }

        for (j=0; j<NET_INTERFACE_COUNTERS; j++) {

            /* keep the interface name around */
            temp = (struct temp_event *)papi_malloc(sizeof(struct temp_event));
            if (!temp) {
                PAPIERROR("out of memory!");
                fclose(fin);
                return PAPI_ENOMEM;
            }
            temp->next = NULL;

            if (root == NULL) {
                root = temp;
            } else if (last) {
                last->next = temp;
            } else {
                free(temp);
                fclose(fin);
                PAPIERROR("This shouldn't be possible\n");
                return PAPI_ESBSTR;
            }
            last = temp;

            snprintf(temp->name, PAPI_MAX_STR_LEN, "%s.%s",
                    ifname, _net_counter_info[j].name);
            snprintf(temp->description, PAPI_MAX_STR_LEN, "%s %s",
                    ifname, _net_counter_info[j].description);

            count++;
        }
    }

    fclose(fin);

    return count;
}
Ejemplo n.º 15
0
static int
mpx_insert_events( MPX_EventSet *mpx_events, int *event_list,
		   int num_events, int domain, int granularity )
{
	int i, retval = 0, num_events_success = 0;
	MasterEvent *mev;
	PAPI_option_t options;
	MasterEvent **head = &mpx_events->mythr->head;

	MPXDBG("Inserting %p %d\n",mpx_events,mpx_events->num_events );

	/* Make sure we don't overrun our buffers */
	if (mpx_events->num_events + num_events > PAPI_MAX_SW_MPX_EVENTS) {
	   return PAPI_ECOUNT;
	}

	/* For each event, see if there is already a corresponding
	 * event in the master set for this thread.  If not, add it.
	 */
	for ( i = 0; i < num_events; i++ ) {

		/* Look for a matching event in the master list */
		for( mev = *head; mev != NULL; mev = mev->next ) {
		   if ( (mev->pi.event_type == event_list[i]) && 
			(mev->pi.domain == domain) &&
			(mev->pi.granularity == granularity ))
				break;
		}

		/* No matching event in the list; add a new one */
		if ( mev == NULL ) {
		   mev = (MasterEvent *) papi_malloc( sizeof ( MasterEvent ) );
		   if ( mev == NULL ) {
		      return PAPI_ENOMEM;
		   }

		   mev->pi.event_type = event_list[i];
		   mev->pi.domain = domain;
		   mev->pi.granularity = granularity;
		   mev->uses = mev->active = 0;
		   mev->prev_total_c = mev->count = mev->cycles = 0;
		   mev->rate_estimate = 0.0;
		   mev->count_estimate = 0;
		   mev->is_a_rate = 0;
		   mev->papi_event = PAPI_NULL;
			
		   retval = PAPI_create_eventset( &( mev->papi_event ) );
		   if ( retval != PAPI_OK ) {
		      MPXDBG( "Event %d could not be counted.\n", 
			      event_list[i] );
		      goto bail;
		   }

		   retval = PAPI_add_event( mev->papi_event, event_list[i] );
		   if ( retval != PAPI_OK ) {
		      MPXDBG( "Event %d could not be counted.\n", 
			      event_list[i] );
		      goto bail;
		   }

		   /* Always count total cycles so we can scale results.
		    * If user just requested cycles, 
		    * don't add that event again. */

		   if ( event_list[i] != SCALE_EVENT ) {
		      retval = PAPI_add_event( mev->papi_event, SCALE_EVENT );
		      if ( retval != PAPI_OK ) {
			 MPXDBG( "Scale event could not be counted "
				 "at the same time.\n" );
			 goto bail;
		      }
		   }
			
		   /* Set the options for the event set */
		   memset( &options, 0x0, sizeof ( options ) );
		   options.domain.eventset = mev->papi_event;
		   options.domain.domain = domain;
		   retval = PAPI_set_opt( PAPI_DOMAIN, &options );
		   if ( retval != PAPI_OK ) {
		      MPXDBG( "PAPI_set_opt(PAPI_DOMAIN, ...) = %d\n", 
			      retval );
		      goto bail;
		   }

		   memset( &options, 0x0, sizeof ( options ) );
		   options.granularity.eventset = mev->papi_event;
		   options.granularity.granularity = granularity;
		   retval = PAPI_set_opt( PAPI_GRANUL, &options );
		   if ( retval != PAPI_OK ) {
		      if ( retval != PAPI_ECMP ) {
			 /* ignore component errors because they typically mean
			    "not supported by the component" */
			 MPXDBG( "PAPI_set_opt(PAPI_GRANUL, ...) = %d\n", 
				 retval );
			 goto bail;
		      }
		   }


		   /* Chain the event set into the 
		    * master list of event sets used in
		    * multiplexing. */

		    mev->next = *head;
		    *head = mev;

		}

		/* If we created a new event set, or we found a matching
		 * eventset already in the list, then add the pointer in
		 * the master list to this threads list. Then we bump the
		 * number of successfully added events. */
	MPXDBG("Inserting now %p %d\n",mpx_events,mpx_events->num_events );

		mpx_events->mev[mpx_events->num_events + num_events_success] = mev;
		mpx_events->mev[mpx_events->num_events + num_events_success]->uses++;
		num_events_success++;

	}

	/* Always be sure the head master event points to the thread */
	if ( *head != NULL ) {
		( *head )->mythr = mpx_events->mythr;
	}
	MPXDBG( "%d of %d events were added.\n", num_events_success, num_events );
	mpx_events->num_events += num_events_success;
	return ( PAPI_OK );

  bail:
	/* If there is a current mev, it is currently not linked into the list
	 * of multiplexing events, so we can just delete that
	 */
	if ( mev && mev->papi_event ) {
	   if (PAPI_cleanup_eventset( mev->papi_event )!=PAPI_OK) {
	     PAPIERROR("Cleanup eventset\n");
	   }
	   if (PAPI_destroy_eventset( &( mev->papi_event )) !=PAPI_OK) {
	     PAPIERROR("Destory eventset\n");
	   }
	}
	if ( mev )
		papi_free( mev );
	mev = NULL;

	/* Decrease the usage count of events */
	for ( i = 0; i < num_events_success; i++ ) {
		mpx_events->mev[mpx_events->num_events + i]->uses--;
	}

	/* Run the garbage collector to remove unused events */
	if ( num_events_success )
		mpx_remove_unused( head );

	return ( retval );
}
Ejemplo n.º 16
0
/* This routine copies values from a dense 'findem' array of events into the sparse
   global _papi_hwi_presets array, which is assumed to be empty at initialization. 
   Multiple dense arrays can be copied into the sparse array, allowing event overloading
   at run-time, or allowing a baseline table to be augmented by a model specific table
   at init time. This method supports adding new events; overriding existing events, or
   deleting deprecated events.
*/
int _papi_hwi_setup_all_presets(hwi_search_t *findem, hwi_dev_notes_t *notes)
{
   int i, j, pnum, preset_index, did_something = 0;

   /* dense array of events is terminated with a 0 preset.
      don't do anything if NULL pointer. This allows just notes to be loaded.
      It's also good defensive programming. 
   */
   if (findem != NULL) 
     {
       for (pnum = 0; (pnum < PAPI_MAX_PRESET_EVENTS) && (findem[pnum].event_code != 0); pnum++) 
	 {
	   /* find the index for the event to be initialized */
	   preset_index = (findem[pnum].event_code & PAPI_PRESET_AND_MASK);
	   
	   /* count and set the number of native terms in this event, these items are contiguous.
	      PAPI_MAX_COUNTER_TERMS is arbitrarily defined in the high level to be a reasonable
	      number of terms to use in a derived event linear expression, currently 8.
	      This wastes space for components with less than 8 counters, but keeps the framework
	      independent of the components.

	      The 'native' field below is an arbitrary opaque identifier that points to information
	      on an actual native event. It is not an event code itself (whatever that might mean).
	      By definition, this value can never == PAPI_NULL.
	      - dkt */

	   INTDBG("Counting number of terms for preset index %d, search map index %d.\n",preset_index,pnum);
	   i = 0;
	   j = 0;
	   while (i < PAPI_MAX_COUNTER_TERMS)
	     {
	       if (findem[pnum].data.native[i] != PAPI_NULL)
		 j++;
	       else if (j)
		 break;
	       i++;
	     }

	   INTDBG("This preset has %d terms.\n",j);
	   _papi_hwi_presets.count[preset_index] = j;
	   
	   /* if the native event array is empty, free the data pointer.
	      this allows existing events to be 'undefined' by overloading with nulls */

	   /* This also makes no sense at all. This code is called at initialization time. 
	      Why would a preset be set up with no events. Hello? Please kill this code. -pjm */
	 
	   if (j == 0) 
	     {
	       INTDBG("WARNING! COUNT == 0 for preset index %d, search map index %d.\n",preset_index,pnum);
	       if (_papi_hwi_presets.data[preset_index] != NULL) 
		 {
		   papi_free(_papi_hwi_presets.data[preset_index]);
		   _papi_hwi_presets.data[preset_index] = NULL;
		 }
	     }
	   /* otherwise malloc a data istructure for the sparse array and copy 
	      the event data into it. Kevin assures me that the data won't 
	      *actually* be duplicated unless it is modified */
	   else 
	     {
	       _papi_hwi_presets.data[preset_index] = papi_malloc(sizeof(hwi_preset_data_t));
	       memcpy(_papi_hwi_presets.data[preset_index],&findem[pnum].data,sizeof(hwi_preset_data_t));
	     }
	   did_something++;
	 }
     }

   /* optional dense array of event notes is terminated with a 0 preset */
   if (notes != NULL) 
     {
       for (pnum = 0; (pnum < PAPI_MAX_PRESET_EVENTS) && (notes[pnum].event_code != 0); pnum++) 
	 {
	   /* strdup the note string into the sparse preset data array */
	   preset_index = (notes[pnum].event_code & PAPI_PRESET_AND_MASK);
	   if (_papi_hwi_presets.dev_note[preset_index] != NULL)
	     papi_free(_papi_hwi_presets.dev_note[preset_index]);
	   _papi_hwi_presets.dev_note[preset_index] = papi_strdup(notes[pnum].dev_note);
	 }
     }
   /* xxxx right now presets are only cpu, component 0 */
   _papi_hwd[0]->cmp_info.num_preset_events += did_something;

   return (did_something ? 0 : PAPI_ESBSTR);
}
Ejemplo n.º 17
0
int
mpx_add_event( MPX_EventSet ** mpx_events, int EventCode, int domain,
			   int granularity )
{
	MPX_EventSet *newset = *mpx_events;
	int retval, alloced_newset = 0;
	Threadlist *t;

	/* Get the global list of threads */

	MPXDBG("Adding %p %#x\n",newset,EventCode);

	_papi_hwi_lock( MULTIPLEX_LOCK );
	t = tlist;

	/* If there are no threads in the list at all, then allocate the new Threadlist */

	if ( t == NULL ) {
	  new_thread:
		t = ( Threadlist * ) papi_malloc( sizeof ( Threadlist ) );
		if ( t == NULL ) {
			_papi_hwi_unlock( MULTIPLEX_LOCK );
			return ( PAPI_ENOMEM );
		}

		/* If we're actually threaded, fill the 
		 * field with the thread_id otherwise
		 * use getpid() as a placeholder. */

		if ( _papi_hwi_thread_id_fn ) {
			MPXDBG( "New thread at %p\n", t );
			t->tid = _papi_hwi_thread_id_fn(  );
		} else {
			MPXDBG( "New process at %p\n", t );
			t->tid = ( unsigned long ) getpid(  );
		}

		/* Fill in the fields */

		t->head = NULL;
		t->cur_event = NULL;
		t->next = tlist;
		tlist = t;
		MPXDBG( "New head is at %p(%lu).\n", tlist,
				( long unsigned ) tlist->tid );
		/* alloced_thread = 1; */
	} else if ( _papi_hwi_thread_id_fn ) {

		/* If we are threaded, AND there exists threads in the list, 
		 *  then try to find our thread in the list. */

		unsigned long tid = _papi_hwi_thread_id_fn(  );

		while ( t ) {
			if ( t->tid == tid ) {
				MPXDBG( "Found thread %#lx\n", t->tid );
				break;
			}
			t = t->next;
		}

		/* Our thread is not in the list, so make a new
		 * thread entry. */

		if ( t == NULL ) {
			MPXDBG( "New thread %lx\n", tid );
			goto new_thread;
		}
	}

	/* Now t & tlist points to our thread, also at the head of the list */

	/* Allocate a the MPX_EventSet if necessary */

	if ( newset == NULL ) {
		newset = mpx_malloc( t );
		if ( newset == NULL ) {
			_papi_hwi_unlock( MULTIPLEX_LOCK );
			return ( PAPI_ENOMEM );
		}
		alloced_newset = 1;
	}

	/* Now we're finished playing with the thread list */

	_papi_hwi_unlock( MULTIPLEX_LOCK );

	/* Removed newset->num_events++, moved to mpx_insert_events() */

	mpx_hold(  );

	/* Create PAPI events (if they don't already exist) and link
	 * the new event set to them, add them to the master list for
	 the thread, reset master event list for this thread */

	retval = mpx_insert_events( newset, &EventCode, 1, 
				    domain, granularity );
	if ( retval != PAPI_OK ) {
		if ( alloced_newset ) {
			papi_free( newset );
			newset = NULL;
		}
	}

	mpx_release(  );

	/* Output the new or existing EventSet */

	*mpx_events = newset;

	return retval;
}