Blame src/papi_preset.c

Packit Service a1973e
/* 
Packit Service a1973e
* File:    papi_preset.c
Packit Service a1973e
* Author:  Haihang You
Packit Service a1973e
*          you@cs.utk.edu
Packit Service a1973e
* Mods:    Brian Sheely
Packit Service a1973e
*          bsheely@eecs.utk.edu
Packit Service a1973e
* Author:  Vince Weaver
Packit Service a1973e
*          vweaver1 @ eecs.utk.edu
Packit Service a1973e
*          Merge of the libpfm3/libpfm4/pmapi-ppc64_events preset code
Packit Service a1973e
*/
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
#include <string.h>
Packit Service a1973e
#include <ctype.h>
Packit Service a1973e
#include <errno.h>
Packit Service a1973e
Packit Service a1973e
#include "papi.h"
Packit Service a1973e
#include "papi_internal.h"
Packit Service a1973e
#include "papi_vector.h"
Packit Service a1973e
#include "papi_memory.h"
Packit Service a1973e
#include "papi_preset.h"
Packit Service a1973e
#include "extras.h"
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
// A place to put user defined events
Packit Service a1973e
extern hwi_presets_t user_defined_events[];
Packit Service a1973e
extern int user_defined_events_count;
Packit Service a1973e
Packit Service a1973e
static int papi_load_derived_events (char *pmu_str, int pmu_type, int cidx, int preset_flag);
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
/* This routine copies values from a dense 'findem' array of events
Packit Service a1973e
   into the sparse global _papi_hwi_presets array, which is assumed
Packit Service a1973e
   to be empty at initialization.
Packit Service a1973e
Packit Service a1973e
   Multiple dense arrays can be copied into the sparse array, allowing
Packit Service a1973e
   event overloading at run-time, or allowing a baseline table to be
Packit Service a1973e
   augmented by a model specific table at init time.
Packit Service a1973e
Packit Service a1973e
   This method supports adding new events; overriding existing events, or
Packit Service a1973e
   deleting deprecated events.
Packit Service a1973e
*/
Packit Service a1973e
int
Packit Service a1973e
_papi_hwi_setup_all_presets( hwi_search_t * findem, int cidx )
Packit Service a1973e
{
Packit Service a1973e
    int i, pnum, did_something = 0;
Packit Service a1973e
    unsigned int preset_index, j, k;
Packit Service a1973e
Packit Service a1973e
    /* dense array of events is terminated with a 0 preset.
Packit Service a1973e
       don't do anything if NULL pointer. This allows just notes to be loaded.
Packit Service a1973e
       It's also good defensive programming.
Packit Service a1973e
     */
Packit Service a1973e
    if ( findem != NULL ) {
Packit Service a1973e
       for ( pnum = 0; ( pnum < PAPI_MAX_PRESET_EVENTS ) &&
Packit Service a1973e
			  ( findem[pnum].event_code != 0 ); pnum++ ) {
Packit Service a1973e
	   /* find the index for the event to be initialized */
Packit Service a1973e
	   preset_index = ( findem[pnum].event_code & PAPI_PRESET_AND_MASK );
Packit Service a1973e
	   /* count and set the number of native terms in this event, 
Packit Service a1973e
              these items are contiguous.
Packit Service a1973e
Packit Service a1973e
	      PAPI_EVENTS_IN_DERIVED_EVENT is arbitrarily defined in the high 
Packit Service a1973e
              level to be a reasonable number of terms to use in a derived 
Packit Service a1973e
              event linear expression, currently 8.
Packit Service a1973e
Packit Service a1973e
	      This wastes space for components with less than 8 counters, 
Packit Service a1973e
              but keeps the framework independent of the components.
Packit Service a1973e
Packit Service a1973e
	      The 'native' field below is an arbitrary opaque identifier 
Packit Service a1973e
              that points to information on an actual native event. 
Packit Service a1973e
              It is not an event code itself (whatever that might mean).
Packit Service a1973e
	      By definition, this value can never == PAPI_NULL.
Packit Service a1973e
	      - dkt */
Packit Service a1973e
Packit Service a1973e
	   INTDBG( "Counting number of terms for preset index %d, "
Packit Service a1973e
                   "search map index %d.\n", preset_index, pnum );
Packit Service a1973e
	   i = 0;
Packit Service a1973e
	   j = 0;
Packit Service a1973e
	   while ( i < PAPI_EVENTS_IN_DERIVED_EVENT ) {
Packit Service a1973e
	      if ( findem[pnum].native[i] != PAPI_NULL ) {
Packit Service a1973e
		 j++;
Packit Service a1973e
	      }
Packit Service a1973e
	      else if ( j ) {
Packit Service a1973e
		 break;
Packit Service a1973e
	      }
Packit Service a1973e
	      i++;
Packit Service a1973e
	   }
Packit Service a1973e
Packit Service a1973e
	   INTDBG( "This preset has %d terms.\n", j );
Packit Service a1973e
	   _papi_hwi_presets[preset_index].count = j;
Packit Service a1973e
 
Packit Service a1973e
           _papi_hwi_presets[preset_index].derived_int = findem[pnum].derived;
Packit Service a1973e
	   for(k=0;k
Packit Service a1973e
              _papi_hwi_presets[preset_index].code[k] =
Packit Service a1973e
                     findem[pnum].native[k];
Packit Service a1973e
	   }
Packit Service a1973e
	   /* preset code list must be PAPI_NULL terminated */
Packit Service a1973e
	   if (k
Packit Service a1973e
              _papi_hwi_presets[preset_index].code[k] = PAPI_NULL;
Packit Service a1973e
	   }
Packit Service a1973e
Packit Service a1973e
	   _papi_hwi_presets[preset_index].postfix=
Packit Service a1973e
	                                   papi_strdup(findem[pnum].operation);
Packit Service a1973e
Packit Service a1973e
	   did_something++;
Packit Service a1973e
       }
Packit Service a1973e
    }
Packit Service a1973e
Packit Service a1973e
    _papi_hwd[cidx]->cmp_info.num_preset_events += did_something;
Packit Service a1973e
Packit Service a1973e
    return ( did_something ? PAPI_OK : PAPI_ENOEVNT );
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
int
Packit Service a1973e
_papi_hwi_cleanup_all_presets( void )
Packit Service a1973e
{
Packit Service a1973e
        int preset_index,cidx;
Packit Service a1973e
	unsigned int j;
Packit Service a1973e
Packit Service a1973e
	for ( preset_index = 0; preset_index < PAPI_MAX_PRESET_EVENTS;
Packit Service a1973e
		  preset_index++ ) {
Packit Service a1973e
	    if ( _papi_hwi_presets[preset_index].postfix != NULL ) {
Packit Service a1973e
	       papi_free( _papi_hwi_presets[preset_index].postfix );
Packit Service a1973e
	       _papi_hwi_presets[preset_index].postfix = NULL;
Packit Service a1973e
	    }
Packit Service a1973e
	    if ( _papi_hwi_presets[preset_index].note != NULL ) {
Packit Service a1973e
	       papi_free( _papi_hwi_presets[preset_index].note );
Packit Service a1973e
	       _papi_hwi_presets[preset_index].note = NULL;
Packit Service a1973e
	    }
Packit Service a1973e
	    for(j=0; j<_papi_hwi_presets[preset_index].count;j++) {
Packit Service a1973e
	       papi_free(_papi_hwi_presets[preset_index].name[j]);
Packit Service a1973e
	    }
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	for(cidx=0;cidx
Packit Service a1973e
	   _papi_hwd[cidx]->cmp_info.num_preset_events = 0;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
#if defined(ITANIUM2) || defined(ITANIUM3)
Packit Service a1973e
	/* NOTE: This memory may need to be freed for BG/P builds as well */
Packit Service a1973e
	if ( preset_search_map != NULL ) {
Packit Service a1973e
		papi_free( preset_search_map );
Packit Service a1973e
		preset_search_map = NULL;
Packit Service a1973e
	}
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
	return PAPI_OK;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
#define PAPI_EVENT_FILE "papi_events.csv"
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
/*  Trims blank space from both ends of a string (in place).
Packit Service a1973e
    Returns pointer to new start address */
Packit Service a1973e
static inline char *
Packit Service a1973e
trim_string( char *in )
Packit Service a1973e
{
Packit Service a1973e
	int len, i = 0;
Packit Service a1973e
	char *start = in;
Packit Service a1973e
Packit Service a1973e
	if ( in == NULL )
Packit Service a1973e
		return ( in );
Packit Service a1973e
	len = ( int ) strlen( in );
Packit Service a1973e
	if ( len == 0 )
Packit Service a1973e
		return ( in );
Packit Service a1973e
Packit Service a1973e
	/* Trim left */
Packit Service a1973e
	while ( i < len ) {
Packit Service a1973e
		if ( isblank( in[i] ) ) {
Packit Service a1973e
			in[i] = '\0';
Packit Service a1973e
			start++;
Packit Service a1973e
		} else
Packit Service a1973e
			break;
Packit Service a1973e
		i++;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	/* Trim right */
Packit Service a1973e
	i = ( int ) strlen( start ) - 1;
Packit Service a1973e
	while ( i >= 0 ) {
Packit Service a1973e
		if ( isblank( start[i] ) )
Packit Service a1973e
			start[i] = '\0';
Packit Service a1973e
		else
Packit Service a1973e
			break;
Packit Service a1973e
		i--;
Packit Service a1973e
	}
Packit Service a1973e
	return ( start );
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
/*  Calls trim_string to remove blank space;
Packit Service a1973e
    Removes paired punctuation delimiters from
Packit Service a1973e
    beginning and end of string. If the same punctuation
Packit Service a1973e
    appears first and last (quotes, slashes) they are trimmed;
Packit Service a1973e
    Also checks for the following pairs: () <> {} [] */
Packit Service a1973e
static inline char *
Packit Service a1973e
trim_note( char *in )
Packit Service a1973e
{
Packit Service a1973e
	int len;
Packit Service a1973e
	char *note, start, end;
Packit Service a1973e
Packit Service a1973e
	note = trim_string( in );
Packit Service a1973e
	if ( note != NULL ) {
Packit Service a1973e
                len = ( int ) strlen( note );
Packit Service a1973e
		if ( len > 0 ) {
Packit Service a1973e
			if ( ispunct( *note ) ) {
Packit Service a1973e
				start = *note;
Packit Service a1973e
				end = note[len - 1];
Packit Service a1973e
				if ( ( start == end )
Packit Service a1973e
					 || ( ( start == '(' ) && ( end == ')' ) )
Packit Service a1973e
					 || ( ( start == '<' ) && ( end == '>' ) )
Packit Service a1973e
					 || ( ( start == '{' ) && ( end == '}' ) )
Packit Service a1973e
					 || ( ( start == '[' ) && ( end == ']' ) ) ) {
Packit Service a1973e
					note[len - 1] = '\0';
Packit Service a1973e
					*note = '\0';
Packit Service a1973e
					note++;
Packit Service a1973e
				}
Packit Service a1973e
			}
Packit Service a1973e
		}
Packit Service a1973e
	}
Packit Service a1973e
	return note;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static inline int
Packit Service a1973e
find_event_index(hwi_presets_t *array, int size, char *tmp) {
Packit Service a1973e
	SUBDBG("ENTER: array: %p, size: %d, tmp: %s\n", array, size, tmp);
Packit Service a1973e
	int i;
Packit Service a1973e
	for (i = 0; i < size; i++) {
Packit Service a1973e
		if (array[i].symbol == NULL) {
Packit Service a1973e
			array[i].symbol = papi_strdup(tmp);
Packit Service a1973e
			SUBDBG("EXIT: i: %d\n", i);
Packit Service a1973e
			return i;
Packit Service a1973e
		}
Packit Service a1973e
		if (strcasecmp(tmp, array[i].symbol) == 0) {
Packit Service a1973e
			SUBDBG("EXIT: i: %d\n", i);
Packit Service a1973e
			return i;
Packit Service a1973e
		}
Packit Service a1973e
	}
Packit Service a1973e
	SUBDBG("EXIT: PAPI_EINVAL\n");
Packit Service a1973e
	return PAPI_EINVAL;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* Look for an event file 'name' in a couple common locations.
Packit Service a1973e
   Return a valid file handle if found */
Packit Service a1973e
static FILE *
Packit Service a1973e
open_event_table( char *name )
Packit Service a1973e
{
Packit Service a1973e
	FILE *table;
Packit Service a1973e
Packit Service a1973e
	SUBDBG( "Opening %s\n", name );
Packit Service a1973e
	table = fopen( name, "r" );
Packit Service a1973e
	if ( table == NULL ) {
Packit Service a1973e
		SUBDBG( "Open %s failed, trying ./%s.\n", 
Packit Service a1973e
			name, PAPI_EVENT_FILE );
Packit Service a1973e
		sprintf( name, "%s", PAPI_EVENT_FILE );
Packit Service a1973e
		table = fopen( name, "r" );
Packit Service a1973e
	}
Packit Service a1973e
	if ( table == NULL ) {
Packit Service a1973e
		SUBDBG( "Open ./%s failed, trying ../%s.\n", 
Packit Service a1973e
			name, PAPI_EVENT_FILE );
Packit Service a1973e
		sprintf( name, "../%s", PAPI_EVENT_FILE );
Packit Service a1973e
		table = fopen( name, "r" );
Packit Service a1973e
	}
Packit Service a1973e
	if ( table ) {
Packit Service a1973e
		SUBDBG( "Open %s succeeded.\n", name );
Packit Service a1973e
	}
Packit Service a1973e
	return table;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* parse a single line from either a file or character table
Packit Service a1973e
   Strip trailing <cr>; return 0 if empty */
Packit Service a1973e
static int
Packit Service a1973e
get_event_line( char *line, FILE * table, char **tmp_perfmon_events_table )
Packit Service a1973e
{
Packit Service a1973e
	int i;
Packit Service a1973e
Packit Service a1973e
	if ( table ) {
Packit Service a1973e
	    if ( fgets( line, LINE_MAX, table ) == NULL)
Packit Service a1973e
		return 0;
Packit Service a1973e
Packit Service a1973e
	    i = ( int ) strlen( line );
Packit Service a1973e
	    if (i == 0)
Packit Service a1973e
		return 0;
Packit Service a1973e
	    if ( line[i-1] == '\n' )
Packit Service a1973e
		line[i-1] = '\0';
Packit Service a1973e
	    return 1;
Packit Service a1973e
	} else {
Packit Service a1973e
		for ( i = 0;
Packit Service a1973e
			  **tmp_perfmon_events_table && **tmp_perfmon_events_table != '\n';
Packit Service a1973e
			  i++, ( *tmp_perfmon_events_table )++ )
Packit Service a1973e
			line[i] = **tmp_perfmon_events_table;
Packit Service a1973e
		if (i == 0)
Packit Service a1973e
		    return 0;
Packit Service a1973e
		if ( **tmp_perfmon_events_table && **tmp_perfmon_events_table == '\n' ) {
Packit Service a1973e
		    ( *tmp_perfmon_events_table )++;
Packit Service a1973e
		}
Packit Service a1973e
		line[i] = '\0';
Packit Service a1973e
		return 1;
Packit Service a1973e
	}
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
// update tokens in formula referring to index "old_index" with tokens referring to index "new_index".
Packit Service a1973e
static void
Packit Service a1973e
update_ops_string(char **formula, int old_index, int new_index) {
Packit Service a1973e
	INTDBG("ENTER:   *formula: %s, old_index: %d, new_index: %d\n", *formula?*formula:"NULL", old_index, new_index);
Packit Service a1973e
Packit Service a1973e
	int cur_index;
Packit Service a1973e
	char *newFormula;
Packit Service a1973e
	char *subtoken;
Packit Service a1973e
	char *tok_save_ptr=NULL;
Packit Service a1973e
Packit Service a1973e
	// if formula is null just return
Packit Service a1973e
	if (*formula == NULL) {
Packit Service a1973e
		INTDBG("EXIT: Null pointer to formula passed in\n");
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// get some space for the new formula we are going to create
Packit Service a1973e
	newFormula = papi_calloc(strlen(*formula) + 20, 1);
Packit Service a1973e
Packit Service a1973e
	// replace the specified "replace" tokens in the new original formula with the new insertion formula
Packit Service a1973e
	newFormula[0] = '\0';
Packit Service a1973e
	subtoken = strtok_r(*formula, "|", &tok_save_ptr);
Packit Service a1973e
	while ( subtoken != NULL) {
Packit Service a1973e
//		INTDBG("subtoken: %s, newFormula: %s\n", subtoken, newFormula);
Packit Service a1973e
		char work[10];
Packit Service a1973e
		// if this is the token we want to replace with the new token index, do it now
Packit Service a1973e
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))) {
Packit Service a1973e
			cur_index = atoi(&subtoken[1]);
Packit Service a1973e
			// if matches old index, use the new one
Packit Service a1973e
			if (cur_index == old_index) {
Packit Service a1973e
				sprintf (work, "N%d", new_index);
Packit Service a1973e
				strcat (newFormula, work);
Packit Service a1973e
			} else if (cur_index > old_index) {
Packit Service a1973e
				// current token greater than old index, make it one less than what it was
Packit Service a1973e
				sprintf (work, "N%d", cur_index-1);
Packit Service a1973e
				strcat (newFormula, work);
Packit Service a1973e
			} else {
Packit Service a1973e
				// current token less than old index, copy this part of the original formula into the new formula
Packit Service a1973e
				strcat(newFormula, subtoken);
Packit Service a1973e
			}
Packit Service a1973e
		} else {
Packit Service a1973e
			// copy this part of the original formula into the new formula
Packit Service a1973e
			strcat(newFormula, subtoken);
Packit Service a1973e
		}
Packit Service a1973e
		strcat (newFormula, "|");
Packit Service a1973e
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
Packit Service a1973e
	}
Packit Service a1973e
	papi_free (*formula);
Packit Service a1973e
	*formula = newFormula;
Packit Service a1973e
Packit Service a1973e
	INTDBG("EXIT: newFormula: %s\n", newFormula);
Packit Service a1973e
	return;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
//
Packit Service a1973e
// Handle creating a new derived event of type DERIVED_ADD.  This may create a new formula
Packit Service a1973e
// which can be used to compute the results of the new event from the events it depends on.
Packit Service a1973e
// This code is also responsible for making sure that all the needed native events are in the
Packit Service a1973e
// new events native event list and that the formula's referenced to this array are correct.
Packit Service a1973e
//
Packit Service a1973e
static void
Packit Service a1973e
ops_string_append(hwi_presets_t *results, hwi_presets_t *depends_on, int addition) {
Packit Service a1973e
	INTDBG("ENTER: results: %p, depends_on: %p, addition %d\n", results, depends_on, addition);
Packit Service a1973e
Packit Service a1973e
	int i;
Packit Service a1973e
	int second_event = 0;
Packit Service a1973e
	char newFormula[PAPI_MIN_STR_LEN] = "";
Packit Service a1973e
	char work[20];
Packit Service a1973e
Packit Service a1973e
	// if our results already have a formula, start with what was collected so far
Packit Service a1973e
	// this should only happens when processing the second event of a new derived add
Packit Service a1973e
	if (results->postfix != NULL) {
Packit Service a1973e
		INTDBG("Event %s has existing formula %s\n", results->symbol, results->postfix);
Packit Service a1973e
		// get the existing formula
Packit Service a1973e
		strncat(newFormula, results->postfix, sizeof(newFormula)-1);
Packit Service a1973e
		newFormula[sizeof(newFormula)-1] = '\0';
Packit Service a1973e
		second_event = 1;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// process based on what kind of event the one we depend on is
Packit Service a1973e
	switch (depends_on->derived_int) {
Packit Service a1973e
		case DERIVED_POSTFIX: {
Packit Service a1973e
			// the event we depend on has a formula, append it our new events formula
Packit Service a1973e
Packit Service a1973e
			// if event we depend on does not have a formula, report error
Packit Service a1973e
			if (depends_on->postfix == NULL) {
Packit Service a1973e
				INTDBG("Event %s is of type DERIVED_POSTFIX but is missing operation string\n", depends_on->symbol);
Packit Service a1973e
				return;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			// may need to renumber the native event index values in the depends on event formula before putting it into new derived event
Packit Service a1973e
			char *temp = papi_strdup(depends_on->postfix);
Packit Service a1973e
Packit Service a1973e
			// If this is not the first event of the new derived add, need to adjust native event index values in formula.
Packit Service a1973e
			// At this time we assume that all the native events in the second events formula are unique for the new event
Packit Service a1973e
			// and just bump the indexes by the number of events already known to the new event.  Later when we add the events
Packit Service a1973e
			// to the native event list for this new derived event, we will check to see if the native events are already known
Packit Service a1973e
			// to the new derived event and if so adjust the indexes again.
Packit Service a1973e
			if (second_event) {
Packit Service a1973e
				for ( i=depends_on->count-1 ; i>=0 ; i--) {
Packit Service a1973e
					update_ops_string(&temp, i, results->count + i);
Packit Service a1973e
				}
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			// append the existing formula from the event we depend on (but get rid of last '|' character)
Packit Service a1973e
			strncat(newFormula, temp, sizeof(newFormula)-1);
Packit Service a1973e
			newFormula[sizeof(newFormula)-1] = '\0';
Packit Service a1973e
			papi_free (temp);
Packit Service a1973e
			break;
Packit Service a1973e
		}
Packit Service a1973e
		case DERIVED_ADD: {
Packit Service a1973e
			// the event we depend on has no formula, create a formula for our new event to add together the depends_on native event values
Packit Service a1973e
Packit Service a1973e
			// build a formula for this add event
Packit Service a1973e
			sprintf(work, "N%d|N%d|+|", results->count, results->count + 1);
Packit Service a1973e
			strcat(newFormula, work);
Packit Service a1973e
			break;
Packit Service a1973e
		}
Packit Service a1973e
		case DERIVED_SUB: {
Packit Service a1973e
			// the event we depend on has no formula, create a formula for our new event to subtract the depends_on native event values
Packit Service a1973e
Packit Service a1973e
			// build a formula for this subtract event
Packit Service a1973e
			sprintf(work, "N%d|N%d|-|", results->count, results->count + 1);
Packit Service a1973e
			strcat(newFormula, work);
Packit Service a1973e
			break;
Packit Service a1973e
		}
Packit Service a1973e
		case NOT_DERIVED: {
Packit Service a1973e
			// the event we depend on has no formula and is itself only based on one native event, create a formula for our new event to include this native event
Packit Service a1973e
Packit Service a1973e
			// build a formula for this subtract event
Packit Service a1973e
			sprintf(work, "N%d|", results->count);
Packit Service a1973e
			strcat(newFormula, work);
Packit Service a1973e
			break;
Packit Service a1973e
		}
Packit Service a1973e
		default: {
Packit Service a1973e
			// the event we depend on has unsupported derived type, put out some debug and give up
Packit Service a1973e
			INTDBG("Event %s depends on event %s which has an unsupported derived type of %d\n", results->symbol, depends_on->symbol, depends_on->derived_int);
Packit Service a1973e
			return;
Packit Service a1973e
		}
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// if this was the second event, append to the formula an operation to add or subtract the results of the two events
Packit Service a1973e
	if (second_event) {
Packit Service a1973e
		if (addition != 0) {
Packit Service a1973e
			strcat(newFormula, "+|");
Packit Service a1973e
		} else {
Packit Service a1973e
			strcat(newFormula, "-|");
Packit Service a1973e
		}
Packit Service a1973e
		// also change the new derived events type to show it has a formula now
Packit Service a1973e
		results->derived_int = DERIVED_POSTFIX;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// we need to free the existing space (created by malloc and we need to create a new one)
Packit Service a1973e
	papi_free (results->postfix);
Packit Service a1973e
	results->postfix = papi_strdup(newFormula);
Packit Service a1973e
	INTDBG("EXIT: newFormula: %s\n", newFormula);
Packit Service a1973e
	return;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
// merge the 'insertion' formula into the 'original' formula replacing the
Packit Service a1973e
// 'replaces' token in the 'original' formula.
Packit Service a1973e
static void
Packit Service a1973e
ops_string_merge(char **original, char *insertion, int replaces, int start_index) {
Packit Service a1973e
	INTDBG("ENTER: original: %p, *original: %s, insertion: %s, replaces: %d, start_index: %d\n", original, *original, insertion, replaces, start_index);
Packit Service a1973e
Packit Service a1973e
	int orig_len=0;
Packit Service a1973e
	int ins_len=0;
Packit Service a1973e
	char *subtoken;
Packit Service a1973e
	char *workBuf;
Packit Service a1973e
	char *workPtr;
Packit Service a1973e
	char *tok_save_ptr=NULL;
Packit Service a1973e
	char *newOriginal;
Packit Service a1973e
	char *newInsertion;
Packit Service a1973e
	char *newFormula;
Packit Service a1973e
	int insert_events;
Packit Service a1973e
Packit Service a1973e
	if (*original != NULL) {
Packit Service a1973e
		orig_len = strlen(*original);
Packit Service a1973e
	}
Packit Service a1973e
	if (insertion != NULL) {
Packit Service a1973e
		ins_len = strlen(insertion);
Packit Service a1973e
	}
Packit Service a1973e
	newFormula = papi_calloc (orig_len + ins_len + 40, 1);
Packit Service a1973e
Packit Service a1973e
	// if insertion formula is not provided, then the original formula remains basically unchanged.
Packit Service a1973e
	if (insertion == NULL) {
Packit Service a1973e
		// if the original formula has a leading '|' then get rid of it
Packit Service a1973e
		workPtr = *original;
Packit Service a1973e
		if (workPtr[0] == '|') {
Packit Service a1973e
			strcpy(newFormula, &workPtr[1]);
Packit Service a1973e
		} else {
Packit Service a1973e
			strcpy(newFormula, workPtr);
Packit Service a1973e
		}
Packit Service a1973e
		// formula fields are always malloced space so free the previous one
Packit Service a1973e
		papi_free (*original);
Packit Service a1973e
		*original = newFormula;
Packit Service a1973e
		INTDBG("EXIT: newFormula: %s\n", *original);
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// renumber the token numbers in the insertion formula
Packit Service a1973e
	// also count how many native events are used in this formula
Packit Service a1973e
	insert_events = 0;
Packit Service a1973e
	newInsertion = papi_calloc(ins_len+20, 1);
Packit Service a1973e
	workBuf = papi_calloc(ins_len+10, 1);
Packit Service a1973e
	workPtr = papi_strdup(insertion);
Packit Service a1973e
	subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
Packit Service a1973e
	while ( subtoken != NULL) {
Packit Service a1973e
//		INTDBG("subtoken: %s, newInsertion: %s\n", subtoken, newInsertion);
Packit Service a1973e
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))) {
Packit Service a1973e
			insert_events++;
Packit Service a1973e
			int val = atoi(&subtoken[1]);
Packit Service a1973e
			val += start_index;
Packit Service a1973e
			subtoken[1] = '\0';
Packit Service a1973e
			sprintf (workBuf, "N%d", val);
Packit Service a1973e
		} else {
Packit Service a1973e
			strcpy(workBuf, subtoken);
Packit Service a1973e
		}
Packit Service a1973e
		strcat (newInsertion, workBuf);
Packit Service a1973e
		strcat (newInsertion, "|");
Packit Service a1973e
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
Packit Service a1973e
	}
Packit Service a1973e
	papi_free (workBuf);
Packit Service a1973e
	papi_free (workPtr);
Packit Service a1973e
	INTDBG("newInsertion: %s\n", newInsertion);
Packit Service a1973e
Packit Service a1973e
	// if original formula is not provided, then the updated insertion formula becomes the new formula
Packit Service a1973e
	// but we still had to renumber the native event tokens in case another native event was put into the list first
Packit Service a1973e
	if (*original == NULL) {
Packit Service a1973e
		*original = papi_strdup(newInsertion);
Packit Service a1973e
		INTDBG("EXIT: newFormula: %s\n", newInsertion);
Packit Service a1973e
		papi_free (newInsertion);
Packit Service a1973e
		papi_free (newFormula);
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// if token to replace not valid, return null  (do we also need to check an upper bound ???)
Packit Service a1973e
	if ((replaces < 0)) {
Packit Service a1973e
		papi_free (newInsertion);
Packit Service a1973e
		papi_free (newFormula);
Packit Service a1973e
		INTDBG("EXIT: Invalid value for token in original formula to be replaced\n");
Packit Service a1973e
		return;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// renumber the token numbers in the original formula
Packit Service a1973e
	// tokens with an index greater than the replaces token need to be incremented by number of events in insertion formula-1
Packit Service a1973e
	newOriginal = papi_calloc (orig_len+20, 1);
Packit Service a1973e
	workBuf = papi_calloc(orig_len+10, 1);
Packit Service a1973e
	workPtr = papi_strdup(*original);
Packit Service a1973e
Packit Service a1973e
	subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
Packit Service a1973e
	while ( subtoken != NULL) {
Packit Service a1973e
//		INTDBG("subtoken: %s, newOriginal: %s\n", subtoken, newOriginal);
Packit Service a1973e
		// prime the work area with the next token, then see if we need to change it
Packit Service a1973e
		strcpy(workBuf, subtoken);
Packit Service a1973e
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))) {
Packit Service a1973e
			int val = atoi(&subtoken[1]);
Packit Service a1973e
			if (val > replaces) {
Packit Service a1973e
				val += insert_events-1;
Packit Service a1973e
				subtoken[1] = '\0';
Packit Service a1973e
				sprintf (workBuf, "N%d", val);
Packit Service a1973e
			}
Packit Service a1973e
		}
Packit Service a1973e
		// put the work buffer into the new original formula
Packit Service a1973e
		strcat (newOriginal, workBuf);
Packit Service a1973e
		strcat (newOriginal, "|");
Packit Service a1973e
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
Packit Service a1973e
	}
Packit Service a1973e
	papi_free (workBuf);
Packit Service a1973e
	papi_free (workPtr);
Packit Service a1973e
	INTDBG("newOriginal: %s\n", newOriginal);
Packit Service a1973e
Packit Service a1973e
	// replace the specified "replace" tokens in the new original formula with the new insertion formula
Packit Service a1973e
	newFormula[0] = '\0';
Packit Service a1973e
	workPtr = newOriginal;
Packit Service a1973e
	subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
Packit Service a1973e
	while ( subtoken != NULL) {
Packit Service a1973e
//		INTDBG("subtoken: %s, newFormula: %s\n", subtoken, newFormula);
Packit Service a1973e
		// if this is the token we want to replace with the insertion string, do it now
Packit Service a1973e
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))  &&  (replaces == atoi(&subtoken[1]))) {
Packit Service a1973e
			// copy updated insertion string into the original string (replacing this token)
Packit Service a1973e
			strcat(newFormula, newInsertion);
Packit Service a1973e
		} else {
Packit Service a1973e
			// copy this part of the original formula into the new formula
Packit Service a1973e
			strcat(newFormula, subtoken);
Packit Service a1973e
			strcat(newFormula, "|");
Packit Service a1973e
		}
Packit Service a1973e
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
Packit Service a1973e
	}
Packit Service a1973e
	papi_free (newInsertion);
Packit Service a1973e
	papi_free (workPtr);
Packit Service a1973e
Packit Service a1973e
	// formula fields are always malloced space so free the previous one
Packit Service a1973e
	papi_free (*original);
Packit Service a1973e
	*original = newFormula;
Packit Service a1973e
	INTDBG("EXIT: newFormula: %s\n", newFormula);
Packit Service a1973e
	return;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
//
Packit Service a1973e
//  Check to see if an event the new derived event being created depends on is known.  We check both preset and user defined derived events here.
Packit Service a1973e
//  If it is a known derived event then we set the new event being defined to include the necessary native events and formula to compute its
Packit Service a1973e
//  derived value and use it in the correct context of the new derived event being created.  Depending on the inputs, the operations strings (formulas)
Packit Service a1973e
//  to be used by the new derived event may need to be created and/or adjusted to reference the correct native event indexes for the new derived event.
Packit Service a1973e
//  The formulas processed by this code must be reverse polish notation (RPN) or postfix format and they must contain place holders (like N0, N1) which
Packit Service a1973e
//  identify indexes into the native event array used to compute the new derived events final value.
Packit Service a1973e
//
Packit Service a1973e
//  Arguments:
Packit Service a1973e
//    target:  event we are looking for
Packit Service a1973e
//    derived_type:  type of derived event being created (add, subtract, postfix)
Packit Service a1973e
//    results:  where to build the new preset event being defined.
Packit Service a1973e
//    search: table of known existing preset or user events the new derived event is allowed to use (points to a table of either preset or user events).
Packit Service a1973e
//    search_size:  number of entries in the search table.
Packit Service a1973e
//
Packit Service a1973e
static int
Packit Service a1973e
check_derived_events(char *target, int derived_type, hwi_presets_t* results, hwi_presets_t * search, int search_size, int token_index)
Packit Service a1973e
{
Packit Service a1973e
	INTDBG("ENTER: target: %p (%s), results: %p, search: %p, search_size: %d, token_index: %d\n", target, target, results, search, search_size, token_index);
Packit Service a1973e
	unsigned int i;
Packit Service a1973e
	int j;
Packit Service a1973e
	int k;
Packit Service a1973e
	int found = 0;
Packit Service a1973e
Packit Service a1973e
	for (j=0; j < search_size; j++) {
Packit Service a1973e
		//	INTDBG("search[%d].symbol: %s, looking for: %s\n", j, search[j].symbol, target);
Packit Service a1973e
		if (search[j].symbol == NULL) {
Packit Service a1973e
			INTDBG("EXIT: returned: 0\n");
Packit Service a1973e
			return 0;
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		// if not the event we depend on, just look at next
Packit Service a1973e
		if ( strcasecmp( target, search[j].symbol) != 0 ) {
Packit Service a1973e
			continue;
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		INTDBG("Found a match\n");
Packit Service a1973e
Packit Service a1973e
		// derived formulas need to be adjusted based on what kind of derived event we are processing
Packit Service a1973e
		// the derived type passed to this function is the type of the new event being defined (not the events it is based on)
Packit Service a1973e
		// when we get here the formula must be in reverse polish notation (RPN) format
Packit Service a1973e
		switch (derived_type) {
Packit Service a1973e
			case DERIVED_POSTFIX: {
Packit Service a1973e
				// go create a formula to merge the second formula into a spot identified by one of the tokens in
Packit Service a1973e
				// the first formula.
Packit Service a1973e
				ops_string_merge(&(results->postfix), search[j].postfix, token_index, results->count);
Packit Service a1973e
				break;
Packit Service a1973e
			}
Packit Service a1973e
			case DERIVED_ADD: {
Packit Service a1973e
				// the new derived event adds two things together, go handle this target events role in the add
Packit Service a1973e
				ops_string_append(results, &search[j], 1);
Packit Service a1973e
				break;
Packit Service a1973e
			}
Packit Service a1973e
			case DERIVED_SUB: {
Packit Service a1973e
				// go create a formula to subtract the value generated by the second formula from the value generated by the first formula.
Packit Service a1973e
				ops_string_append(results, &search[j], 0);
Packit Service a1973e
				break;
Packit Service a1973e
			}
Packit Service a1973e
				default: {
Packit Service a1973e
				INTDBG("Derived type: %d, not currently handled\n", derived_type);
Packit Service a1973e
				break;
Packit Service a1973e
			}
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		// copy event name and code used by the derived event into the results table (place where new derived event is getting created)
Packit Service a1973e
		for ( k = 0; k < (int)search[j].count; k++ ) {
Packit Service a1973e
//			INTDBG("search[%d]: %p, name[%d]: %s, code[%d]: %#x\n", j, &search[j], k, search[j].name[k], k, search[j].code[k]);
Packit Service a1973e
			// if this event is already in the list, just update the formula so that references to this event point to the existing one
Packit Service a1973e
			for (i=0 ; i < results->count ; i++) {
Packit Service a1973e
				if (results->code[i] == search[j].code[k]) {
Packit Service a1973e
					INTDBG("event: %s, code: %#x, already in results at index: %d\n", search[j].name[k], search[j].code[k], i);
Packit Service a1973e
					// replace all tokens in the formula that refer to index "results->count + found" with a token that refers to index "i".
Packit Service a1973e
					// the index "results->count + found" identifies the index used in the formula for the event we just determined is a duplicate
Packit Service a1973e
					update_ops_string(&(results->postfix), results->count + found, i);
Packit Service a1973e
					found++;
Packit Service a1973e
					break;
Packit Service a1973e
				}
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			// if we did not find a match, copy native event info into results array
Packit Service a1973e
			if (found == 0) {
Packit Service a1973e
				// not a duplicate, go ahead and copy into results and bump number of native events in results
Packit Service a1973e
				if (search[j].name[k]) {
Packit Service a1973e
					results->name[results->count] = papi_strdup(search[j].name[k]);
Packit Service a1973e
				} else {
Packit Service a1973e
					results->name[results->count] = papi_strdup(target);
Packit Service a1973e
				}
Packit Service a1973e
				results->code[results->count] = search[j].code[k];
Packit Service a1973e
				INTDBG("results: %p, name[%d]: %s, code[%d]: %#x\n", results, results->count, results->name[results->count], results->count, results->code[results->count]);
Packit Service a1973e
Packit Service a1973e
				results->count++;
Packit Service a1973e
			}
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		INTDBG("EXIT: returned: 1\n");
Packit Service a1973e
		return 1;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	INTDBG("EXIT: returned: 0\n");
Packit Service a1973e
	return 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
static int
Packit Service a1973e
check_native_events(char *target, hwi_presets_t* results)
Packit Service a1973e
{
Packit Service a1973e
	INTDBG("ENTER: target: %p (%s), results: %p\n", target, target, results);
Packit Service a1973e
	int ret;
Packit Service a1973e
Packit Service a1973e
	// find this native events code
Packit Service a1973e
	if ( ( ret = _papi_hwi_native_name_to_code( target, (int *)(&results->code[results->count])) ) != PAPI_OK ) {
Packit Service a1973e
		INTDBG("EXIT: returned: 0, call to convert name to event code failed with ret: %d\n", ret);
Packit Service a1973e
		return 0;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// if the code returned was 0, return to show it is not a valid native event
Packit Service a1973e
	if ( results->code[results->count] == 0 ) {
Packit Service a1973e
		INTDBG( "EXIT: returned: 0, event code not found\n");
Packit Service a1973e
		return 0;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// if this native event is not for component 0, return to show it can not be used in derived events
Packit Service a1973e
	// it should be possible to create derived events for other components as long as all events in the derived event are associated with the same component
Packit Service a1973e
	if ( _papi_hwi_component_index(results->code[results->count]) != 0 ) {
Packit Service a1973e
		INTDBG( "EXIT: returned: 0, new event not associated with component 0 (current limitation with derived events)\n");
Packit Service a1973e
		return 0;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	//	  found = 1;
Packit Service a1973e
	INTDBG("\tFound a native event %s\n", target);
Packit Service a1973e
	results->name[results->count++] = papi_strdup(target);
Packit Service a1973e
Packit Service a1973e
	INTDBG( "EXIT: returned: 1\n");
Packit Service a1973e
	return 1;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
// see if the event_name string passed in matches a known event name
Packit Service a1973e
// if it does these calls also updates information in event definition tables to remember the event
Packit Service a1973e
static int
Packit Service a1973e
is_event(char *event_name, int derived_type, hwi_presets_t* results, int token_index) {
Packit Service a1973e
	INTDBG("ENTER: event_name: %p (%s), derived_type: %d, results: %p, token_index: %d\n", event_name, event_name, derived_type, results, token_index);
Packit Service a1973e
Packit Service a1973e
	/* check if its a preset event */
Packit Service a1973e
	if ( check_derived_events(event_name, derived_type, results, &_papi_hwi_presets[0], PAPI_MAX_PRESET_EVENTS, token_index) ) {
Packit Service a1973e
		INTDBG("EXIT: found preset event\n");
Packit Service a1973e
		return 1;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	/* check if its a user defined event */
Packit Service a1973e
	if ( check_derived_events(event_name, derived_type, results, user_defined_events, user_defined_events_count, token_index) ) {
Packit Service a1973e
		INTDBG("EXIT: found user event\n");
Packit Service a1973e
		return 1;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	/* check if its a native event */
Packit Service a1973e
	if ( check_native_events(event_name, results) ) {
Packit Service a1973e
		INTDBG("EXIT: found native event\n");
Packit Service a1973e
		return 1;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	INTDBG("EXIT: event not found\n");
Packit Service a1973e
	return 0;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* Static version of the events file. */
Packit Service a1973e
#if defined(STATIC_PAPI_EVENTS_TABLE)
Packit Service a1973e
#include "papi_events_table.h"
Packit Service a1973e
#else
Packit Service a1973e
static char *papi_events_table = NULL;
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
int _papi_load_preset_table(char *pmu_str, int pmu_type, int cidx) {
Packit Service a1973e
	SUBDBG("ENTER: pmu_str: %s, pmu_type: %d, cidx: %d\n", pmu_str, pmu_type, cidx);
Packit Service a1973e
Packit Service a1973e
	int retval;
Packit Service a1973e
Packit Service a1973e
	// go load papi preset events (last argument tells function if we are loading presets or user events)
Packit Service a1973e
	retval = papi_load_derived_events(pmu_str, pmu_type, cidx, 1);
Packit Service a1973e
	if (retval != PAPI_OK) {
Packit Service a1973e
		SUBDBG("EXIT: retval: %d\n", retval);
Packit Service a1973e
		return retval;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// go load the user defined event definitions if any are defined
Packit Service a1973e
	retval = papi_load_derived_events(pmu_str, pmu_type, cidx, 0);
Packit Service a1973e
Packit Service a1973e
	SUBDBG("EXIT: retval: %d\n", retval);
Packit Service a1973e
	return retval;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
// global variables
Packit Service a1973e
static char stack[2*PAPI_HUGE_STR_LEN]; // stack
Packit Service a1973e
static int stacktop = -1; // stack length
Packit Service a1973e
Packit Service a1973e
// priority: This function returns the priority of the operator
Packit Service a1973e
static
Packit Service a1973e
int priority( char symbol ) {
Packit Service a1973e
        switch( symbol ) {
Packit Service a1973e
        case '@':
Packit Service a1973e
                return -1;
Packit Service a1973e
        case '(':
Packit Service a1973e
                return 0;
Packit Service a1973e
	case '+':
Packit Service a1973e
	case '-':
Packit Service a1973e
                return 1;
Packit Service a1973e
	case '*':
Packit Service a1973e
	case '/':
Packit Service a1973e
	case '%':
Packit Service a1973e
		return 2;
Packit Service a1973e
	default :
Packit Service a1973e
		return 0;
Packit Service a1973e
	} // end switch symbol
Packit Service a1973e
} // end priority
Packit Service a1973e
Packit Service a1973e
static
Packit Service a1973e
int push( char symbol ) {
Packit Service a1973e
  if (stacktop >= 2*PAPI_HUGE_STR_LEN - 1) {
Packit Service a1973e
    INTDBG("stack overflow converting algebraic expression (%d,%c)\n", stacktop,symbol );
Packit Service a1973e
    return -1;  //***TODO: Figure out how to exit gracefully
Packit Service a1973e
  } // end if stacktop>MAX
Packit Service a1973e
  stack[++stacktop] = symbol;
Packit Service a1973e
  return 0;
Packit Service a1973e
} // end push
Packit Service a1973e
Packit Service a1973e
// pop from stack
Packit Service a1973e
static
Packit Service a1973e
char pop() {
Packit Service a1973e
  if( stacktop < 0 ) {
Packit Service a1973e
    INTDBG("stack underflow converting algebraic expression\n" );
Packit Service a1973e
    return '\0';  //***TODO: Figure out how to exit gracefully
Packit Service a1973e
  } // end if empty
Packit Service a1973e
  return( stack[stacktop--] );
Packit Service a1973e
} // end pop
Packit Service a1973e
Packit Service a1973e
/* infix_to_postfix:
Packit Service a1973e
   routine that will be called with parameter:
Packit Service a1973e
   char *in characters of infix notation (algebraic formula)
Packit Service a1973e
   returns: char * pointer to string of returned postfix */
Packit Service a1973e
static char *
Packit Service a1973e
infix_to_postfix( char *infix ) {
Packit Service a1973e
	INTDBG("ENTER: in: %s, size: %zu\n", infix, strlen(infix));
Packit Service a1973e
	static char postfix[2*PAPI_HUGE_STR_LEN];	// output
Packit Service a1973e
        unsigned int index;
Packit Service a1973e
        int postfixlen;
Packit Service a1973e
        char token;
Packit Service a1973e
        if ( strlen(infix) > PAPI_HUGE_STR_LEN ) 
Packit Service a1973e
            PAPIERROR("A infix string (probably in user-defined presets) is too big (max allowed %d): %s", PAPI_HUGE_STR_LEN, infix );
Packit Service a1973e
Packit Service a1973e
        // initialize stack
Packit Service a1973e
	memset(stack, 0, 2*PAPI_HUGE_STR_LEN);
Packit Service a1973e
	stacktop = -1; 
Packit Service a1973e
	push('#'); 
Packit Service a1973e
        stacktop = 0; // after initialization of stack to #
Packit Service a1973e
        /* initialize output string */
Packit Service a1973e
	memset(postfix,0,2*PAPI_HUGE_STR_LEN);
Packit Service a1973e
        postfixlen = 0;
Packit Service a1973e
Packit Service a1973e
	for( index=0; index
Packit Service a1973e
                token = infix[index];
Packit Service a1973e
                INTDBG("INTDBG: in: %s, length: %zu, index: %d token %c\n", infix, strlen( infix ), index, token);
Packit Service a1973e
		switch( token ) {
Packit Service a1973e
		case '(':
Packit Service a1973e
			push( token );
Packit Service a1973e
			break;
Packit Service a1973e
		case ')':
Packit Service a1973e
                        if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
Packit Service a1973e
                        while ( stack[stacktop] != '(' ) {
Packit Service a1973e
                                postfix[postfixlen++] = pop();
Packit Service a1973e
                                postfix[postfixlen++] = '|';
Packit Service a1973e
                        }
Packit Service a1973e
                        token = pop();  /* pop the '(' character */
Packit Service a1973e
			break;
Packit Service a1973e
		case '+':
Packit Service a1973e
		case '-':
Packit Service a1973e
		case '*':
Packit Service a1973e
		case '/':
Packit Service a1973e
		case '%':
Packit Service a1973e
		case '^':       /* if an operator */
Packit Service a1973e
                        if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
Packit Service a1973e
                        while ( priority(stack[stacktop]) > priority(token) ) {
Packit Service a1973e
                                postfix[postfixlen++] = pop();
Packit Service a1973e
                                postfix[postfixlen++] = '|';
Packit Service a1973e
                        }
Packit Service a1973e
                        push( token ); /* save current operator */
Packit Service a1973e
                        break;
Packit Service a1973e
		default: // if alphanumeric character which is not parenthesis or an operator
Packit Service a1973e
                        postfix[postfixlen++] = token;
Packit Service a1973e
			break;
Packit Service a1973e
		} // end switch symbol
Packit Service a1973e
	} // end while
Packit Service a1973e
Packit Service a1973e
        /* Write any remaining operators */
Packit Service a1973e
        if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
Packit Service a1973e
        while ( stacktop>0 ) {
Packit Service a1973e
                postfix[postfixlen++] = pop();
Packit Service a1973e
                postfix[postfixlen++] = '|';
Packit Service a1973e
        }
Packit Service a1973e
        postfix[postfixlen++] = '\0';
Packit Service a1973e
	stacktop = -1; 
Packit Service a1973e
Packit Service a1973e
	INTDBG("EXIT: postfix: %s, size: %zu\n", postfix, strlen(postfix));
Packit Service a1973e
	return (postfix);
Packit Service a1973e
} // end infix_to_postfix
Packit Service a1973e
Packit Service a1973e
/*
Packit Service a1973e
 * This function will load event definitions from either a file or an in memory table.  It is used to load both preset events
Packit Service a1973e
 * which are defined by the PAPI development team and delivered with the product and user defined events which can be defined
Packit Service a1973e
 * by papi users and provided to papi to be processed at library initialization.  Both the preset events and user defined events
Packit Service a1973e
 * support the same event definition syntax.
Packit Service a1973e
 *
Packit Service a1973e
 * Event definition file syntax:
Packit Service a1973e
 * see PAPI_derived_event_files(1) man page.
Packit Service a1973e
 *
Packit Service a1973e
 * Blank lines are ignored
Packit Service a1973e
 * Lines that begin with '#' are comments.
Packit Service a1973e
 * Lines that begin with 'CPU' identify a pmu name and have the following effect.
Packit Service a1973e
 *      If this pmu name does not match the pmu_str passed in, it is ignored and we get the next input line.
Packit Service a1973e
 *      If this pmu name matches the pmu_str passed in, we set a 'process events' flag.
Packit Service a1973e
 *      Multiple consecutive 'CPU' lines may be provided and if any of them match the pmu_str passed in, we set a 'process events' flag.
Packit Service a1973e
 *      When a 'CPU' line is found following event definition lines, it turns off the 'process events' flag and then does the above checks.
Packit Service a1973e
 * Lines that begin with 'PRESET' or 'EVENT' specify an event definition and are processed as follows.
Packit Service a1973e
 *      If the 'process events' flag is not set, the line is ignored and we get the next input line.
Packit Service a1973e
 *      If the 'process events' flag is set, the event is processed and the event information is put into the next slot in the results array.
Packit Service a1973e
 *
Packit Service a1973e
 * There are three possible sources of input for preset event definitions.  The code will first look for the environment variable
Packit Service a1973e
 * "PAPI_CSV_EVENT_FILE".  If found its value will be used as the pathname of where to get the preset information.  If not found,
Packit Service a1973e
 * the code will look for a built in table containing preset events.  If the built in table was not created during the build of
Packit Service a1973e
 * PAPI then the code will build a pathname of the form "PAPI_DATADIR/PAPI_EVENT_FILE".  Each of these are build variables, the
Packit Service a1973e
 * PAPI_DATADIR variable can be given a value during the configure of PAPI at build time, and the PAPI_EVENT_FILE variable has a
Packit Service a1973e
 * hard coded value of "papi_events.csv".
Packit Service a1973e
 *
Packit Service a1973e
 * There is only one way to define user events.  The code will look for an environment variable "PAPI_USER_EVENTS_FILE".  If found
Packit Service a1973e
 * its value will be used as the pathname of a file which contains user event definitions.  The events defined in this file will be
Packit Service a1973e
 * added to the ones known by PAPI when the call to PAPI_library_init is done.
Packit Service a1973e
 *
Packit Service a1973e
 * TODO:
Packit Service a1973e
 * Look into restoring the ability to specify a user defined event file with a call to PAPI_set_opt(PAPI_USER_EVENTS_FILE).
Packit Service a1973e
 * This needs to figure out how to pass a pmu name (could use default pmu from component 0) to this function.
Packit Service a1973e
 *
Packit Service a1973e
 * Currently code elsewhere in PAPI limits the events which preset and user events can depend on to those events which are known to component 0.  This possibly could
Packit Service a1973e
 * be relaxed to allow events from different components.  But since all the events used by any derived event must be added to the same eventset, it will always be a
Packit Service a1973e
 * requirement that all events used by a given derived event must be from the same component.
Packit Service a1973e
 *
Packit Service a1973e
 */
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
static int
Packit Service a1973e
papi_load_derived_events (char *pmu_str, int pmu_type, int cidx, int preset_flag) {
Packit Service a1973e
	SUBDBG( "ENTER: pmu_str: %s, pmu_type: %d, cidx: %d, preset_flag: %d\n", pmu_str, pmu_type, cidx, preset_flag);
Packit Service a1973e
Packit Service a1973e
	char pmu_name[PAPI_MIN_STR_LEN];
Packit Service a1973e
	char line[LINE_MAX];
Packit Service a1973e
	char name[PATH_MAX] = "builtin papi_events_table";
Packit Service a1973e
	char *event_file_path=NULL;
Packit Service a1973e
	char *event_table_ptr=NULL;
Packit Service a1973e
	int event_type_bits = 0;
Packit Service a1973e
	char *tmpn;
Packit Service a1973e
	char *tok_save_ptr=NULL;
Packit Service a1973e
	FILE *event_file = NULL;
Packit Service a1973e
	hwi_presets_t *results=NULL;
Packit Service a1973e
	int result_size = 0;
Packit Service a1973e
	int *event_count = NULL;
Packit Service a1973e
	int invalid_event;
Packit Service a1973e
	int line_no = 0;  /* count of lines read from event definition input */
Packit Service a1973e
	int derived = 0;
Packit Service a1973e
	int res_idx = 0;  /* index into results array for where to store next event */
Packit Service a1973e
	int preset = 0;
Packit Service a1973e
	int get_events = 0; /* only process derived events after CPU type they apply to is identified      */
Packit Service a1973e
	int found_events = 0; /* flag to track if event definitions (PRESETS) are found since last CPU declaration */
Packit Service a1973e
#ifdef PAPI_DATADIR
Packit Service a1973e
		char path[PATH_MAX];
Packit Service a1973e
#endif
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
	if (preset_flag) {
Packit Service a1973e
		/* try the environment variable first */
Packit Service a1973e
		if ((tmpn = getenv("PAPI_CSV_EVENT_FILE")) && (strlen(tmpn) > 0)) {
Packit Service a1973e
			event_file_path = tmpn;
Packit Service a1973e
		}
Packit Service a1973e
		/* if no valid environment variable, look for built-in table */
Packit Service a1973e
		else if (papi_events_table) {
Packit Service a1973e
			event_table_ptr = papi_events_table;
Packit Service a1973e
		}
Packit Service a1973e
		/* if no env var and no built-in, search for default file */
Packit Service a1973e
		else {
Packit Service a1973e
#ifdef PAPI_DATADIR
Packit Service a1973e
			sprintf( path, "%s/%s", PAPI_DATADIR, PAPI_EVENT_FILE );
Packit Service a1973e
			event_file_path = path;
Packit Service a1973e
#else
Packit Service a1973e
			event_file_path = PAPI_EVENT_FILE;
Packit Service a1973e
#endif
Packit Service a1973e
		}
Packit Service a1973e
		event_type_bits = PAPI_PRESET_MASK;
Packit Service a1973e
		results = &_papi_hwi_presets[0];
Packit Service a1973e
		result_size = PAPI_MAX_PRESET_EVENTS;
Packit Service a1973e
		event_count = &_papi_hwd[cidx]->cmp_info.num_preset_events;
Packit Service a1973e
	} else {
Packit Service a1973e
		if ((event_file_path = getenv( "PAPI_USER_EVENTS_FILE" )) == NULL ) {
Packit Service a1973e
			SUBDBG("EXIT: User event definition file not provided.\n");
Packit Service a1973e
			return PAPI_OK;
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		event_type_bits = PAPI_UE_MASK;
Packit Service a1973e
		results = &user_defined_events[0];
Packit Service a1973e
		result_size = PAPI_MAX_USER_EVENTS;
Packit Service a1973e
		event_count = &user_defined_events_count;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	// if we have an event file pathname, open it and read event definitions from the file
Packit Service a1973e
	if (event_file_path != NULL) {
Packit Service a1973e
		if ((event_file = open_event_table(event_file_path)) == NULL) {
Packit Service a1973e
			// if file open fails, return an error
Packit Service a1973e
			SUBDBG("EXIT: Event file open failed.\n");
Packit Service a1973e
			return PAPI_ESYS;
Packit Service a1973e
		}
Packit Service a1973e
		strncpy(name, event_file_path, sizeof(name)-1);
Packit Service a1973e
		name[sizeof(name)-1] = '\0';
Packit Service a1973e
	} else if (event_table_ptr == NULL) {
Packit Service a1973e
		// if we do not have a path name or table pointer, return an error
Packit Service a1973e
		SUBDBG("EXIT: Both event_file_path and event_table_ptr are NULL.\n");
Packit Service a1973e
		return PAPI_ESYS;
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	/* copy the pmu identifier, stripping commas if found */
Packit Service a1973e
	tmpn = pmu_name;
Packit Service a1973e
	while (*pmu_str) {
Packit Service a1973e
		if (*pmu_str != ',')
Packit Service a1973e
			*tmpn++ = *pmu_str;
Packit Service a1973e
		pmu_str++;
Packit Service a1973e
	}
Packit Service a1973e
	*tmpn = '\0';
Packit Service a1973e
Packit Service a1973e
	/* at this point we have either a valid file pointer or built-in table pointer */
Packit Service a1973e
	while (get_event_line(line, event_file, &event_table_ptr)) {
Packit Service a1973e
		char *t;
Packit Service a1973e
		int i;
Packit Service a1973e
Packit Service a1973e
		// increment number of lines we have read
Packit Service a1973e
		line_no++;
Packit Service a1973e
Packit Service a1973e
		t = trim_string(strtok_r(line, ",", &tok_save_ptr));
Packit Service a1973e
Packit Service a1973e
		/* Skip blank lines */
Packit Service a1973e
		if ((t == NULL) || (strlen(t) == 0))
Packit Service a1973e
			continue;
Packit Service a1973e
Packit Service a1973e
		/* Skip comments */
Packit Service a1973e
		if (t[0] == '#') {
Packit Service a1973e
			continue;
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		if (strcasecmp(t, "CPU") == 0) {
Packit Service a1973e
			if (get_events != 0 && found_events != 0) {
Packit Service a1973e
				SUBDBG( "Ending event scanning at line %d of %s.\n", line_no, name);
Packit Service a1973e
				get_events = 0;
Packit Service a1973e
				found_events = 0;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
			if ((t == NULL) || (strlen(t) == 0)) {
Packit Service a1973e
				PAPIERROR("Expected name after CPU token at line %d of %s -- ignoring", line_no, name);
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			if (strcasecmp(t, pmu_name) == 0) {
Packit Service a1973e
				int type;
Packit Service a1973e
Packit Service a1973e
				SUBDBG( "Process events for PMU %s found at line %d of %s.\n", t, line_no, name);
Packit Service a1973e
Packit Service a1973e
				t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
				if ((t == NULL) || (strlen(t) == 0)) {
Packit Service a1973e
					SUBDBG("No additional qualifier found, matching on string.\n");
Packit Service a1973e
					get_events = 1;
Packit Service a1973e
				} else if ((sscanf(t, "%d", &type) == 1) && (type == pmu_type)) {
Packit Service a1973e
					SUBDBG( "Found CPU %s type %d at line %d of %s.\n", pmu_name, type, line_no, name);
Packit Service a1973e
					get_events = 1;
Packit Service a1973e
				} else {
Packit Service a1973e
					SUBDBG( "Additional qualifier match failed %d vs %d.\n", pmu_type, type);
Packit Service a1973e
				}
Packit Service a1973e
			}
Packit Service a1973e
			continue;
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		if ((strcasecmp(t, "PRESET") == 0)  || (strcasecmp(t, "EVENT") == 0)) {
Packit Service a1973e
Packit Service a1973e
			if (get_events == 0)
Packit Service a1973e
				continue;
Packit Service a1973e
Packit Service a1973e
			found_events = 1;
Packit Service a1973e
			t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
Packit Service a1973e
			if ((t == NULL) || (strlen(t) == 0)) {
Packit Service a1973e
				PAPIERROR("Expected name after PRESET token at line %d of %s -- ignoring", line_no, name);
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			SUBDBG( "Examining event %s\n", t);
Packit Service a1973e
Packit Service a1973e
			// see if this event already exists in the results array, if not already known it sets up event in unused entry
Packit Service a1973e
			if ((res_idx = find_event_index (results, result_size, t)) < 0) {
Packit Service a1973e
				PAPIERROR("No room left for event %s -- ignoring", t);
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			// add the proper event bits (preset or user defined bits)
Packit Service a1973e
			preset = res_idx | event_type_bits;
Packit Service a1973e
			(void) preset;
Packit Service a1973e
Packit Service a1973e
			SUBDBG( "Use event code: %#x for %s\n", preset, t);
Packit Service a1973e
Packit Service a1973e
			t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
			if ((t == NULL) || (strlen(t) == 0)) {
Packit Service a1973e
				// got an error, make this entry unused
Packit Service a1973e
				papi_free (results[res_idx].symbol);
Packit Service a1973e
				results[res_idx].symbol = NULL;
Packit Service a1973e
				PAPIERROR("Expected derived type after PRESET token at line %d of %s -- ignoring", line_no, name);
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			if (_papi_hwi_derived_type(t, &derived) != PAPI_OK) {
Packit Service a1973e
				// got an error, make this entry unused
Packit Service a1973e
				papi_free (results[res_idx].symbol);
Packit Service a1973e
				results[res_idx].symbol = NULL;
Packit Service a1973e
				PAPIERROR("Invalid derived name %s after PRESET token at line %d of %s -- ignoring", t, line_no, name);
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			/****************************************/
Packit Service a1973e
			/* Have an event, let's start assigning */
Packit Service a1973e
			/****************************************/
Packit Service a1973e
Packit Service a1973e
			SUBDBG( "Adding event: %s, code: %#x, derived: %d results[%d]: %p.\n", t, preset, derived, res_idx, &results[res_idx]);
Packit Service a1973e
Packit Service a1973e
			/* results[res_idx].event_code = preset; */
Packit Service a1973e
			results[res_idx].derived_int = derived;
Packit Service a1973e
Packit Service a1973e
			/* Derived support starts here */
Packit Service a1973e
			/* Special handling for postfix and infix */
Packit Service a1973e
			if ((derived == DERIVED_POSTFIX)  || (derived == DERIVED_INFIX)) {
Packit Service a1973e
				t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
				if ((t == NULL) || (strlen(t) == 0)) {
Packit Service a1973e
					// got an error, make this entry unused
Packit Service a1973e
					papi_free (results[res_idx].symbol);
Packit Service a1973e
					results[res_idx].symbol = NULL;
Packit Service a1973e
					PAPIERROR("Expected Operation string after derived type DERIVED_POSTFIX or DERIVED_INFIX at line %d of %s -- ignoring", line_no, name);
Packit Service a1973e
					continue;
Packit Service a1973e
				}
Packit Service a1973e
Packit Service a1973e
				// if it is an algebraic formula, we need to convert it to postfix
Packit Service a1973e
				if (derived == DERIVED_INFIX) {
Packit Service a1973e
					SUBDBG( "Converting InFix operations %s\n", t);
Packit Service a1973e
					t = infix_to_postfix( t );
Packit Service a1973e
					results[res_idx].derived_int = DERIVED_POSTFIX;
Packit Service a1973e
				}
Packit Service a1973e
Packit Service a1973e
				SUBDBG( "Saving PostFix operations %s\n", t);
Packit Service a1973e
				results[res_idx].postfix = papi_strdup(t);
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			/* All derived terms collected here */
Packit Service a1973e
			i = 0;
Packit Service a1973e
			invalid_event = 0;
Packit Service a1973e
			results[res_idx].count = 0;
Packit Service a1973e
			do {
Packit Service a1973e
				t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
				if ((t == NULL) || (strlen(t) == 0))
Packit Service a1973e
					break;
Packit Service a1973e
				if (strcasecmp(t, "NOTE") == 0)
Packit Service a1973e
					break;
Packit Service a1973e
				if (strcasecmp(t, "LDESC") == 0)
Packit Service a1973e
					break;
Packit Service a1973e
				if (strcasecmp(t, "SDESC") == 0)
Packit Service a1973e
					break;
Packit Service a1973e
Packit Service a1973e
				SUBDBG( "Adding term (%d) %s to derived event %#x, current native event count: %d.\n", i, t, preset, results[res_idx].count);
Packit Service a1973e
Packit Service a1973e
				// show that we do not have an event code yet (the component may create one and update this info)
Packit Service a1973e
				// this also clears any values left over from a previous call
Packit Service a1973e
				_papi_hwi_set_papi_event_code(-1, -1);
Packit Service a1973e
Packit Service a1973e
				// make sure that this term in the derived event is a valid event name
Packit Service a1973e
				// this call replaces preset and user event names with the equivalent native events in our results table
Packit Service a1973e
				// it also updates formulas for derived events so that they refer to the correct native event index
Packit Service a1973e
				if (is_event(t, results[res_idx].derived_int, &results[res_idx], i) == 0) {
Packit Service a1973e
					invalid_event = 1;
Packit Service a1973e
					PAPIERROR("Missing event %s, used in derived event %s", t, results[res_idx].symbol);
Packit Service a1973e
					break;
Packit Service a1973e
				}
Packit Service a1973e
Packit Service a1973e
				i++;
Packit Service a1973e
			} while (results[res_idx].count < PAPI_EVENTS_IN_DERIVED_EVENT);
Packit Service a1973e
Packit Service a1973e
			/* preset code list must be PAPI_NULL terminated */
Packit Service a1973e
			if (i < PAPI_EVENTS_IN_DERIVED_EVENT) {
Packit Service a1973e
				results[res_idx].code[results[res_idx].count] = PAPI_NULL;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			if (invalid_event) {
Packit Service a1973e
				// got an error, make this entry unused
Packit Service a1973e
			        // preset table is statically allocated, user defined is dynamic
Packit Service a1973e
			        if (!preset_flag) papi_free (results[res_idx].symbol);
Packit Service a1973e
				results[res_idx].symbol = NULL;
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			/* End of derived support */
Packit Service a1973e
Packit Service a1973e
			// if we did not find any terms to base this derived event on, report error
Packit Service a1973e
			if (i == 0) {
Packit Service a1973e
				// got an error, make this entry unused
Packit Service a1973e
			  if (!preset_flag) papi_free (results[res_idx].symbol);
Packit Service a1973e
				results[res_idx].symbol = NULL;
Packit Service a1973e
				PAPIERROR("Expected PFM event after DERIVED token at line %d of %s -- ignoring", line_no, name);
Packit Service a1973e
				continue;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			if (i == PAPI_EVENTS_IN_DERIVED_EVENT) {
Packit Service a1973e
				t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			// if something was provided following the list of events to be used by the operation, process it
Packit Service a1973e
			if ( t!= NULL  && strlen(t) > 0 ) {
Packit Service a1973e
				do {
Packit Service a1973e
					// save the field name
Packit Service a1973e
					char *fptr = papi_strdup(t);
Packit Service a1973e
Packit Service a1973e
					// get the value to be used with this field
Packit Service a1973e
					t = trim_note(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
					if ( t== NULL  || strlen(t) == 0 ) {
Packit Service a1973e
						papi_free(fptr);
Packit Service a1973e
						break;
Packit Service a1973e
					}
Packit Service a1973e
Packit Service a1973e
					// Handle optional short descriptions, long descriptions and notes
Packit Service a1973e
					if (strcasecmp(fptr, "SDESC") == 0) {
Packit Service a1973e
						results[res_idx].short_descr = papi_strdup(t);
Packit Service a1973e
					}
Packit Service a1973e
					if (strcasecmp(fptr, "LDESC") == 0) {
Packit Service a1973e
						results[res_idx].long_descr = papi_strdup(t);
Packit Service a1973e
					}
Packit Service a1973e
					if (strcasecmp(fptr, "NOTE") == 0) {
Packit Service a1973e
						results[res_idx].note = papi_strdup(t);
Packit Service a1973e
					}
Packit Service a1973e
Packit Service a1973e
					SUBDBG( "Found %s (%s) on line %d\n", fptr, t, line_no);
Packit Service a1973e
					papi_free (fptr);
Packit Service a1973e
Packit Service a1973e
					// look for another field name
Packit Service a1973e
					t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
Packit Service a1973e
					if ( t== NULL  || strlen(t) == 0 ) {
Packit Service a1973e
						break;
Packit Service a1973e
					}
Packit Service a1973e
				} while (t != NULL);
Packit Service a1973e
			}
Packit Service a1973e
			(*event_count)++;
Packit Service a1973e
			continue;
Packit Service a1973e
		}
Packit Service a1973e
Packit Service a1973e
		PAPIERROR("Unrecognized token %s at line %d of %s -- ignoring", t, line_no, name);
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	if (event_file) {
Packit Service a1973e
		fclose(event_file);
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	SUBDBG("EXIT: Done processing derived event file.\n");
Packit Service a1973e
	return PAPI_OK;
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
/* The following code is proof of principle for reading preset events from an
Packit Service a1973e
   xml file. It has been tested and works for pentium3. It relys on the expat
Packit Service a1973e
   library and is invoked by adding
Packit Service a1973e
   XMLFLAG		= -DXML
Packit Service a1973e
   to the Makefile. It is presently hardcoded to look for "./papi_events.xml"
Packit Service a1973e
*/
Packit Service a1973e
#ifdef XML
Packit Service a1973e
Packit Service a1973e
#define BUFFSIZE 8192
Packit Service a1973e
#define SPARSE_BEGIN 0
Packit Service a1973e
#define SPARSE_EVENT_SEARCH 1
Packit Service a1973e
#define SPARSE_EVENT 2
Packit Service a1973e
#define SPARSE_DESC 3
Packit Service a1973e
#define ARCH_SEARCH 4
Packit Service a1973e
#define DENSE_EVENT_SEARCH 5
Packit Service a1973e
#define DENSE_NATIVE_SEARCH 6
Packit Service a1973e
#define DENSE_NATIVE_DESC 7
Packit Service a1973e
#define FINISHED 8
Packit Service a1973e
Packit Service a1973e
char buffer[BUFFSIZE], *xml_arch;
Packit Service a1973e
int location = SPARSE_BEGIN, sparse_index = 0, native_index, error = 0;
Packit Service a1973e
Packit Service a1973e
/* The function below, _xml_start(), is a hook into expat's XML
Packit Service a1973e
 * parser.  _xml_start() defines how the parser handles the
Packit Service a1973e
 * opening tags in PAPI's XML file.  This function can be understood
Packit Service a1973e
 * more easily if you follow along with its logic while looking at
Packit Service a1973e
 * papi_events.xml.  The location variable is a global telling us
Packit Service a1973e
 * where we are in the XML file.  Have we found our architecture's
Packit Service a1973e
 * events yet?  Are we looking at an event definition?...etc.
Packit Service a1973e
 */
Packit Service a1973e
static void
Packit Service a1973e
_xml_start( void *data, const char *el, const char **attr )
Packit Service a1973e
{
Packit Service a1973e
	int native_encoding;
Packit Service a1973e
Packit Service a1973e
	if ( location == SPARSE_BEGIN && !strcmp( "papistdevents", el ) ) {
Packit Service a1973e
		location = SPARSE_EVENT_SEARCH;
Packit Service a1973e
	} else if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
Packit Service a1973e
		_papi_hwi_presets[sparse_index].info.symbol = papi_strdup( attr[1] );
Packit Service a1973e
//      strcpy(_papi_hwi_presets.info[sparse_index].symbol, attr[1]);
Packit Service a1973e
		location = SPARSE_EVENT;
Packit Service a1973e
	} else if ( location == SPARSE_EVENT && !strcmp( "desc", el ) ) {
Packit Service a1973e
		location = SPARSE_DESC;
Packit Service a1973e
	} else if ( location == ARCH_SEARCH && !strcmp( "availevents", el ) &&
Packit Service a1973e
				!strcmp( xml_arch, attr[1] ) ) {
Packit Service a1973e
		location = DENSE_EVENT_SEARCH;
Packit Service a1973e
	} else if ( location == DENSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
Packit Service a1973e
		if ( !strcmp( "PAPI_NULL", attr[1] ) ) {
Packit Service a1973e
			location = FINISHED;
Packit Service a1973e
			return;
Packit Service a1973e
		} else if ( PAPI_event_name_to_code( ( char * ) attr[1], &sparse_index )
Packit Service a1973e
					!= PAPI_OK ) {
Packit Service a1973e
			PAPIERROR( "Improper Preset name given in XML file for %s.",
Packit Service a1973e
					   attr[1] );
Packit Service a1973e
			error = 1;
Packit Service a1973e
		}
Packit Service a1973e
		sparse_index &= PAPI_PRESET_AND_MASK;
Packit Service a1973e
Packit Service a1973e
		/* allocate and initialize data space for this event */
Packit Service a1973e
		papi_valid_free( _papi_hwi_presets[sparse_index].data );
Packit Service a1973e
		_papi_hwi_presets[sparse_index].data =
Packit Service a1973e
			papi_malloc( sizeof ( hwi_preset_data_t ) );
Packit Service a1973e
		native_index = 0;
Packit Service a1973e
		_papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
Packit Service a1973e
		_papi_hwi_presets[sparse_index].data->operation[0] = '\0';
Packit Service a1973e
Packit Service a1973e
Packit Service a1973e
		if ( attr[2] ) {	 /* derived event */
Packit Service a1973e
			_papi_hwi_presets[sparse_index].data->derived =
Packit Service a1973e
				_papi_hwi_derived_type( ( char * ) attr[3] );
Packit Service a1973e
			/* where does DERIVED POSTSCRIPT get encoded?? */
Packit Service a1973e
			if ( _papi_hwi_presets[sparse_index].data->derived == -1 ) {
Packit Service a1973e
				PAPIERROR( "No derived type match for %s in Preset XML file.",
Packit Service a1973e
						   attr[3] );
Packit Service a1973e
				error = 1;
Packit Service a1973e
			}
Packit Service a1973e
Packit Service a1973e
			if ( attr[5] ) {
Packit Service a1973e
				_papi_hwi_presets[sparse_index].count = atoi( attr[5] );
Packit Service a1973e
			} else {
Packit Service a1973e
				PAPIERROR( "No count given for %s in Preset XML file.",
Packit Service a1973e
						   attr[1] );
Packit Service a1973e
				error = 1;
Packit Service a1973e
			}
Packit Service a1973e
		} else {
Packit Service a1973e
			_papi_hwi_presets[sparse_index].data->derived = NOT_DERIVED;
Packit Service a1973e
			_papi_hwi_presets[sparse_index].count = 1;
Packit Service a1973e
		}
Packit Service a1973e
		location = DENSE_NATIVE_SEARCH;
Packit Service a1973e
	} else if ( location == DENSE_NATIVE_SEARCH && !strcmp( "native", el ) ) {
Packit Service a1973e
		location = DENSE_NATIVE_DESC;
Packit Service a1973e
	} else if ( location == DENSE_NATIVE_DESC && !strcmp( "event", el ) ) {
Packit Service a1973e
		if ( _papi_hwi_native_name_to_code( attr[1], &native_encoding ) !=
Packit Service a1973e
			 PAPI_OK ) {
Packit Service a1973e
			printf( "Improper Native name given in XML file for %s\n",
Packit Service a1973e
					attr[1] );
Packit Service a1973e
			PAPIERROR( "Improper Native name given in XML file for %s",
Packit Service a1973e
					   attr[1] );
Packit Service a1973e
			error = 1;
Packit Service a1973e
		}
Packit Service a1973e
		_papi_hwi_presets[sparse_index].data->native[native_index] =
Packit Service a1973e
			native_encoding;
Packit Service a1973e
		native_index++;
Packit Service a1973e
		_papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
Packit Service a1973e
	} else if ( location && location != ARCH_SEARCH && location != FINISHED ) {
Packit Service a1973e
		PAPIERROR( "Poorly-formed Preset XML document." );
Packit Service a1973e
		error = 1;
Packit Service a1973e
	}
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* The function below, _xml_end(), is a hook into expat's XML
Packit Service a1973e
 * parser.  _xml_end() defines how the parser handles the
Packit Service a1973e
 * end tags in PAPI's XML file.
Packit Service a1973e
 */
Packit Service a1973e
static void
Packit Service a1973e
_xml_end( void *data, const char *el )
Packit Service a1973e
{
Packit Service a1973e
	int i;
Packit Service a1973e
Packit Service a1973e
	if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papistdevents", el ) ) {
Packit Service a1973e
		for ( i = sparse_index; i < PAPI_MAX_PRESET_EVENTS; i++ ) {
Packit Service a1973e
			_papi_hwi_presets[i].info.symbol = NULL;
Packit Service a1973e
			_papi_hwi_presets[i].info.long_descr = NULL;
Packit Service a1973e
			_papi_hwi_presets[i].info.short_descr = NULL;
Packit Service a1973e
		}
Packit Service a1973e
		location = ARCH_SEARCH;
Packit Service a1973e
	} else if ( location == DENSE_NATIVE_DESC && !strcmp( "native", el ) ) {
Packit Service a1973e
		location = DENSE_EVENT_SEARCH;
Packit Service a1973e
	} else if ( location == DENSE_EVENT_SEARCH && !strcmp( "availevents", el ) ) {
Packit Service a1973e
		location = FINISHED;
Packit Service a1973e
	}
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
/* The function below, _xml_content(), is a hook into expat's XML
Packit Service a1973e
 * parser.  _xml_content() defines how the parser handles the
Packit Service a1973e
 * text between tags in PAPI's XML file.  The information between
Packit Service a1973e
 * tags is usally text for event descriptions.
Packit Service a1973e
 */
Packit Service a1973e
static void
Packit Service a1973e
_xml_content( void *data, const char *el, const int len )
Packit Service a1973e
{
Packit Service a1973e
	int i;
Packit Service a1973e
	if ( location == SPARSE_DESC ) {
Packit Service a1973e
		_papi_hwi_presets[sparse_index].info.long_descr =
Packit Service a1973e
			papi_malloc( len + 1 );
Packit Service a1973e
		for ( i = 0; i < len; i++ )
Packit Service a1973e
			_papi_hwi_presets[sparse_index].info.long_descr[i] = el[i];
Packit Service a1973e
		_papi_hwi_presets[sparse_index].info.long_descr[len] = '\0';
Packit Service a1973e
		/* the XML data currently doesn't contain a short description */
Packit Service a1973e
		_papi_hwi_presets[sparse_index].info.short_descr = NULL;
Packit Service a1973e
		sparse_index++;
Packit Service a1973e
		_papi_hwi_presets[sparse_index].data = NULL;
Packit Service a1973e
		location = SPARSE_EVENT_SEARCH;
Packit Service a1973e
	}
Packit Service a1973e
}
Packit Service a1973e
Packit Service a1973e
int
Packit Service a1973e
_xml_papi_hwi_setup_all_presets( char *arch, hwi_dev_notes_t * notes )
Packit Service a1973e
{
Packit Service a1973e
	int done = 0;
Packit Service a1973e
	FILE *fp = fopen( "./papi_events.xml", "r" );
Packit Service a1973e
	XML_Parser p = XML_ParserCreate( NULL );
Packit Service a1973e
Packit Service a1973e
	if ( !p ) {
Packit Service a1973e
		PAPIERROR( "Couldn't allocate memory for XML parser." );
Packit Service a1973e
		fclose(fp);
Packit Service a1973e
		return ( PAPI_ESYS );
Packit Service a1973e
	}
Packit Service a1973e
	XML_SetElementHandler( p, _xml_start, _xml_end );
Packit Service a1973e
	XML_SetCharacterDataHandler( p, _xml_content );
Packit Service a1973e
	if ( fp == NULL ) {
Packit Service a1973e
		PAPIERROR( "Error opening Preset XML file." );
Packit Service a1973e
		fclose(fp);
Packit Service a1973e
		return ( PAPI_ESYS );
Packit Service a1973e
	}
Packit Service a1973e
Packit Service a1973e
	xml_arch = arch;
Packit Service a1973e
Packit Service a1973e
	do {
Packit Service a1973e
		int len;
Packit Service a1973e
		void *buffer = XML_GetBuffer( p, BUFFSIZE );
Packit Service a1973e
Packit Service a1973e
		if ( buffer == NULL ) {
Packit Service a1973e
			PAPIERROR( "Couldn't allocate memory for XML buffer." );
Packit Service a1973e
			fclose(fp);
Packit Service a1973e
			return ( PAPI_ESYS );
Packit Service a1973e
		}
Packit Service a1973e
		len = fread( buffer, 1, BUFFSIZE, fp );
Packit Service a1973e
		if ( ferror( fp ) ) {
Packit Service a1973e
			PAPIERROR( "XML read error." );
Packit Service a1973e
			fclose(fp);
Packit Service a1973e
			return ( PAPI_ESYS );
Packit Service a1973e
		}
Packit Service a1973e
		done = feof( fp );
Packit Service a1973e
		if ( !XML_ParseBuffer( p, len, len == 0 ) ) {
Packit Service a1973e
			PAPIERROR( "Parse error at line %d:\n%s",
Packit Service a1973e
					   XML_GetCurrentLineNumber( p ),
Packit Service a1973e
					   XML_ErrorString( XML_GetErrorCode( p ) ) );
Packit Service a1973e
			fclose(fp);
Packit Service a1973e
			return ( PAPI_ESYS );
Packit Service a1973e
		}
Packit Service a1973e
		if ( error ) {
Packit Service a1973e
			fclose(fp);
Packit Service a1973e
			return ( PAPI_ESYS );
Packit Service a1973e
		}
Packit Service a1973e
	} while ( !done );
Packit Service a1973e
	XML_ParserFree( p );
Packit Service a1973e
	fclose( fp );
Packit Service a1973e
	return ( PAPI_OK );
Packit Service a1973e
}
Packit Service a1973e
#endif