// see if the event_name string passed in matches a known event name
// if it does these calls also updates information in event definition tables to remember the event
static int
is_event(char *event_name, int derived_type, hwi_presets_t* results, int token_index) {
	INTDBG("ENTER: event_name: %p (%s), derived_type: %d, results: %p, token_index: %d\n", event_name, event_name, derived_type, results, token_index);

	/* check if its a preset event */
	if ( check_derived_events(event_name, derived_type, results, &_papi_hwi_presets[0], PAPI_MAX_PRESET_EVENTS, token_index) ) {
		INTDBG("EXIT: found preset event\n");
		return 1;
	}

	/* check if its a user defined event */
	if ( check_derived_events(event_name, derived_type, results, user_defined_events, user_defined_events_count, token_index) ) {
		INTDBG("EXIT: found user event\n");
		return 1;
	}

	/* check if its a native event */
	if ( check_native_events(event_name, results) ) {
		INTDBG("EXIT: found native event\n");
		return 1;
	}

	INTDBG("EXIT: event not found\n");
	return 0;
}
void
PRINT_UE(user_defined_event_t* ue)
{
#ifndef DEBUG
  (void)ue; /* clean up unused parameter warning if debugging messages are not used */
#endif
  INTDBG("User Event debug\n");
  INTDBG("\tsymbol=%s\n", ue->symbol);
  INTDBG("\toperation=%s\n", ue->operation);
  INTDBG("\tcount=%d\n", ue->count);
}
// update tokens in formula referring to index "old_index" with tokens referring to index "new_index".
static void
update_ops_string(char **formula, int old_index, int new_index) {
	INTDBG("ENTER:   *formula: %s, old_index: %d, new_index: %d\n", *formula?*formula:"NULL", old_index, new_index);

	int cur_index;
	char *newFormula;
	char *subtoken;
	char *tok_save_ptr=NULL;

	// if formula is null just return
	if (*formula == NULL) {
		INTDBG("EXIT: Null pointer to formula passed in\n");
		return;
	}

	// get some space for the new formula we are going to create
	newFormula = papi_calloc(strlen(*formula) + 20, 1);

	// replace the specified "replace" tokens in the new original formula with the new insertion formula
	newFormula[0] = '\0';
	subtoken = strtok_r(*formula, "|", &tok_save_ptr);
	while ( subtoken != NULL) {
//		INTDBG("subtoken: %s, newFormula: %s\n", subtoken, newFormula);
		char work[10];
		// if this is the token we want to replace with the new token index, do it now
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))) {
			cur_index = atoi(&subtoken[1]);
			// if matches old index, use the new one
			if (cur_index == old_index) {
				sprintf (work, "N%d", new_index);
				strcat (newFormula, work);
			} else if (cur_index > old_index) {
				// current token greater than old index, make it one less than what it was
				sprintf (work, "N%d", cur_index-1);
				strcat (newFormula, work);
			} else {
				// current token less than old index, copy this part of the original formula into the new formula
				strcat(newFormula, subtoken);
			}
		} else {
			// copy this part of the original formula into the new formula
			strcat(newFormula, subtoken);
		}
		strcat (newFormula, "|");
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
	}
	papi_free (*formula);
	*formula = newFormula;

	INTDBG("EXIT: newFormula: %s\n", newFormula);
	return;
}
// pop from stack
static
char pop() {
        if( stacktop < 0 ) {
                INTDBG("EXIT: Stack Underflow converting Algebraic Expression:%d\n", stacktop );
                return '\0';  //***TODO: Figure out how to exit gracefully
        } // end if empty
        return( stack[stacktop--] );
} // end pop
static
int push( char symbol ) {
        if( stacktop >= (PAPI_HUGE_STR_LEN - 1) ) {
                INTDBG("EXIT: Stack Overflow converting Algebraic Expression:%d\n", stacktop );
                return -1;  //***TODO: Figure out how to exit gracefully
  } // end if stacktop>MAX
        stack[++stacktop] = symbol;
        return 0;
} // end push
/* _papi_hwi_derived_string:
   Helper routine to extract a derived string from a derived type
   copies derived type string into derived if found,
   otherwise returns PAPI_EINVAL
*/
int _papi_hwi_derived_string(int type, char *derived, int len) {
   int j;

   for(j = 0; _papi_hwi_derived[j].value != -1; j++) {
      if (_papi_hwi_derived[j].value == type) {
         strncpy(derived, _papi_hwi_derived[j].name, len);
         return(PAPI_OK);
      }
   }
   INTDBG("Invalid derived type %d\n",type);
   return(PAPI_EINVAL);
}
static int
check_native_events(char *target, hwi_presets_t* results)
{
	INTDBG("ENTER: target: %p (%s), results: %p\n", target, target, results);
	int ret;

	// find this native events code
	if ( ( ret = _papi_hwi_native_name_to_code( target, (int *)(&results->code[results->count])) ) != PAPI_OK ) {
		INTDBG("EXIT: returned: 0, call to convert name to event code failed with ret: %d\n", ret);
		return 0;
	}

	// if the code returned was 0, return to show it is not a valid native event
	if ( results->code[results->count] == 0 ) {
		INTDBG( "EXIT: returned: 0, event code not found\n");
		return 0;
	}

	// if this native event is not for component 0, return to show it can not be used in derived events
	// 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
	if ( _papi_hwi_component_index(results->code[results->count]) != 0 ) {
		INTDBG( "EXIT: returned: 0, new event not associated with component 0 (current limitation with derived events)\n");
		return 0;
	}

	//	  found = 1;
	INTDBG("\tFound a native event %s\n", target);
	results->name[results->count++] = papi_strdup(target);

	INTDBG( "EXIT: returned: 1\n");
	return 1;
}
Exemple #8
0
/* _papi_hwi_derived_type:
   Helper routine to extract a derived type from a derived string
   returns type value if found, otherwise returns -1
*/
int
_papi_hwi_derived_type( char *tmp, int *code )
{
	int i = 0;
	while ( _papi_hwi_derived[i].name != NULL ) {
		if ( strcasecmp( tmp, _papi_hwi_derived[i].name ) == 0 ) {
			*code = _papi_hwi_derived[i].value;
			return ( PAPI_OK );
		}
		i++;
	}
	INTDBG( "Invalid derived string %s\n", tmp );
	return ( PAPI_EINVAL );
}
Exemple #9
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, int cidx )
{
    int i, pnum, did_something = 0;
    unsigned int preset_index, j, k;

    /* 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].native[i] != PAPI_NULL ) {
		 j++;
	      }
	      else if ( j ) {
		 break;
	      }
	      i++;
	   }

	   INTDBG( "This preset has %d terms.\n", j );
	   _papi_hwi_presets[preset_index].count = j;
 
           _papi_hwi_presets[preset_index].derived_int = findem[pnum].derived;
	   for(k=0;k<j;k++) {
              _papi_hwi_presets[preset_index].code[k] = 
                     findem[pnum].native[k];
	   } 
	   _papi_hwi_presets[preset_index].postfix=
	                                   strdup(findem[pnum].operation);

	   did_something++;
       }
    }

    _papi_hwd[cidx]->cmp_info.num_preset_events += did_something;

    return ( did_something ? PAPI_OK : PAPI_ESBSTR );
}
Exemple #10
0
int
_linux_get_cpu_info( PAPI_hw_info_t *hwinfo, int *cpuinfo_mhz )
{
	int retval = PAPI_OK;
	unsigned int strSize;
	char maxargs[PAPI_HUGE_STR_LEN], *t, *s;
	float mhz = 0.0;
	FILE *f;
	char cpuinfo_filename[]="/proc/cpuinfo";

	if ( ( f = fopen( cpuinfo_filename, "r" ) ) == NULL ) {
		PAPIERROR( "fopen(/proc/cpuinfo) errno %d", errno );
		return PAPI_ESYS;
	}

	/* All of this information may be overwritten by the component */

	/***********************/
	/* Attempt to find MHz */
	/***********************/
	rewind( f );
	s = search_cpu_info( f, "clock", maxargs );
	if ( !s ) {
		rewind( f );
		s = search_cpu_info( f, "cpu MHz", maxargs );
	}
	if ( s ) {
		sscanf( s + 1, "%f", &mhz );
	}
	*cpuinfo_mhz = mhz;

	/*******************************/
	/* Vendor Name and Vendor Code */
	/*******************************/

	/* First try to read "vendor_id" field */
	/* Which is the most common field      */
	hwinfo->vendor_string[0]=0;
	rewind( f );
	s = search_cpu_info( f, "vendor_id", maxargs );
	strSize = sizeof(hwinfo->vendor_string);
	if ( s && ( t = strchr( s + 2, '\n' ) ) ) {
		*t = '\0';
		if (strlen(s+2) >= strSize-1) {
			s[strSize+1] = '\0';
		}
		strcpy( hwinfo->vendor_string, s + 2 );
	}

	/* If not found, try "vendor" which seems to be Itanium specific */
	if (!hwinfo->vendor_string[0]) {
		rewind( f );
		s = search_cpu_info( f, "vendor", maxargs );
		if ( s && ( t = strchr( s + 2, '\n' ) ) ) {
			*t = '\0';
			if (strlen(s+2) >= strSize-1) {
				s[strSize+1] = '\0';
			}
			strcpy( hwinfo->vendor_string, s + 2 );
		}
	}

	/* "system type" seems to be MIPS and Alpha */
	if (!hwinfo->vendor_string[0]) {
		rewind( f );
		s = search_cpu_info( f, "system type", maxargs );
		if ( s && ( t = strchr( s + 2, '\n' ) ) ) {
			*t = '\0';
			s = strtok( s + 2, " " );
			if (strlen(s) >= strSize-1) {
				s[strSize-1] = '\0';
			}
			strcpy( hwinfo->vendor_string, s );
		}
	}

	/* "platform" indicates Power */
	if (!hwinfo->vendor_string[0]) {

		rewind( f );
		s = search_cpu_info( f, "platform", maxargs );
		if ( s && ( t = strchr( s + 2, '\n' ) ) ) {
			*t = '\0';
			s = strtok( s + 2, " " );
			if ( ( strcasecmp( s, "pSeries" ) == 0 ) ||
				( strcasecmp( s, "PowerNV" ) == 0 ) ||
				( strcasecmp( s, "PowerMac" ) == 0 ) ) {
				strcpy( hwinfo->vendor_string, "IBM" );
			}
		}
	}

	/* "CPU implementer" indicates ARM */
	if (!hwinfo->vendor_string[0]) {

		rewind( f );
		s = search_cpu_info( f, "CPU implementer", maxargs );
		if ( s ) {
			strcpy( hwinfo->vendor_string, "ARM" );
		}
	}


	/* Decode the string to an implementer value */
	if ( strlen( hwinfo->vendor_string ) ) {
		decode_vendor_string( hwinfo->vendor_string, &hwinfo->vendor );
	}

	/**********************************************/
	/* Provide more stepping/model/family numbers */
	/**********************************************/

	if ((hwinfo->vendor==PAPI_VENDOR_INTEL) ||
		(hwinfo->vendor==PAPI_VENDOR_AMD)) {

		decode_cpuinfo_x86(f,hwinfo);
	}

	if (hwinfo->vendor==PAPI_VENDOR_IBM) {

		decode_cpuinfo_power(f,hwinfo);
	}

	if (hwinfo->vendor==PAPI_VENDOR_ARM) {

		decode_cpuinfo_arm(f,hwinfo);
	}




	/* The following members are set using the same methodology */
	/* used in lscpu.                                           */

	/* Total number of CPUs */
	/* The following line assumes totalcpus was initialized to zero! */
	while ( path_exist( _PATH_SYS_SYSTEM "/cpu/cpu%d", hwinfo->totalcpus ) )
		hwinfo->totalcpus++;

	/* Number of threads per core */
	if ( path_exist( _PATH_SYS_CPU0 "/topology/thread_siblings" ) )
		hwinfo->threads =
			path_sibling( _PATH_SYS_CPU0 "/topology/thread_siblings" );

	/* Number of cores per socket */
	if ( path_exist( _PATH_SYS_CPU0 "/topology/core_siblings" ) &&
		 hwinfo->threads > 0 )
		hwinfo->cores =
			path_sibling( _PATH_SYS_CPU0 "/topology/core_siblings" ) /
			hwinfo->threads;

	/* Number of NUMA nodes */
	/* The following line assumes nnodes was initialized to zero! */
	while ( path_exist( _PATH_SYS_SYSTEM "/node/node%d", hwinfo->nnodes ) )
		hwinfo->nnodes++;

	/* Number of CPUs per node */
	hwinfo->ncpu =
		hwinfo->nnodes >
		1 ? hwinfo->totalcpus / hwinfo->nnodes : hwinfo->totalcpus;

	/* Number of sockets */
	if ( hwinfo->threads > 0 && hwinfo->cores > 0 )
		hwinfo->sockets = hwinfo->totalcpus / hwinfo->cores / hwinfo->threads;

#if 0
	int *nodecpu;
	/* cpumap data is not currently part of the _papi_hw_info struct */
        nodecpu = malloc( (unsigned int) hwinfo->nnodes * sizeof(int) );
	if ( nodecpu ) {
	   int i;
	   for ( i = 0; i < hwinfo->nnodes; ++i ) {
	       nodecpu[i] = path_sibling( 
                             _PATH_SYS_SYSTEM "/node/node%d/cpumap", i );
	   }
	} else {
		PAPIERROR( "malloc failed for variable not currently used" );
	}
#endif


	/* Fixup missing Megahertz Value */
	/* This is missing from cpuinfo on ARM and MIPS */
     if (*cpuinfo_mhz < 1.0) {
	rewind( f );

	s = search_cpu_info( f, "BogoMIPS", maxargs );
	if ((!s) || (sscanf( s + 1, "%f", &mhz ) != 1)) {
	   INTDBG("Mhz detection failed. Please edit file %s at line %d.\n",
		     __FILE__,__LINE__);
	}

	if (hwinfo->vendor == PAPI_VENDOR_MIPS) {
	    /* MIPS has 2x clock multiplier */
	    *cpuinfo_mhz = 2*(((int)mhz)+1);

	    /* Also update version info on MIPS */
	    rewind( f );
	    s = search_cpu_info( f, "cpu model", maxargs );
	    s = strstr(s+1," V")+2;
	     strtok(s," ");
	    sscanf(s, "%f ", &hwinfo->revision );
	}
	else {
	    /* In general bogomips is proportional to number of CPUs */
	    if (hwinfo->totalcpus) {
	       if (mhz!=0) *cpuinfo_mhz = mhz / hwinfo->totalcpus;
	    }
	}
     }

    fclose( f );

    return retval;
}
Exemple #11
0
/* infix_to_postfix:
   routine that will be called with parameter:
   char *in characters of infix notation (algebraic formula)
   returns: char * pointer to string of returned postfix */
static char *
infix_to_postfix( char *infix ) {
	INTDBG("ENTER: in: %s, size: %zu\n", infix, strlen(infix));
	static char postfix[2*PAPI_HUGE_STR_LEN];	// output
        unsigned int index;
        int postfixlen;
        char token;
        if ( strlen(infix) > PAPI_HUGE_STR_LEN ) 
            PAPIERROR("A infix string (probably in user-defined presets) is too big (max allowed %d): %s", PAPI_HUGE_STR_LEN, infix );

        // initialize stack
	memset( &stack, 0, 2*PAPI_HUGE_STR_LEN );
	stacktop = -1; 
	push('#');
        /* initialize output string */
	memset(&postfix,0,2*PAPI_HUGE_STR_LEN);
        postfixlen = 0;

	for( index=0; index<strlen(infix); index++ ) {
                token = infix[index];
                INTDBG("INTDBG: in: %s, length: %zu, index: %d token %c\n", infix, strlen( infix ), index, token);
		switch( token ) {
		case '(':
			push( token );
			break;
		case ')':
                        if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
                        while ( stack[stacktop] != '(' ) {
                                postfix[postfixlen++] = pop();
                                postfix[postfixlen++] = '|';
                        }
                        token = pop();  /* pop the '(' character */
			break;
		case '+':
		case '-':
		case '*':
		case '/':
		case '%':
		case '^':       /* if an operator */
                        if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
                        while ( priority(stack[stacktop]) > priority(token) ) {
                                postfix[postfixlen++] = pop();
                                postfix[postfixlen++] = '|';
                        }
                        push( token ); /* save current operator */
                        break;
		default: // if alphanumeric character which is not parenthesis or an operator
                        postfix[postfixlen++] = token;
			break;
		} // end switch symbol
	} // end while

        /* Write any remaining operators */
        if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
        while ( stacktop>0 ) {
                postfix[postfixlen++] = pop();
                postfix[postfixlen++] = '|';
        }
        postfix[postfixlen++] = '\0';
	stacktop = -1; 

	INTDBG("EXIT: postfix: %s, size: %zu\n", postfix, strlen(postfix));
	return (postfix);
} // end infix_to_postfix
Exemple #12
0
//
//  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.
//  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
//  derived value and use it in the correct context of the new derived event being created.  Depending on the inputs, the operations strings (formulas)
//  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.
//  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
//  identify indexes into the native event array used to compute the new derived events final value.
//
//  Arguments:
//    target:  event we are looking for
//    derived_type:  type of derived event being created (add, subtract, postfix)
//    results:  where to build the new preset event being defined.
//    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).
//    search_size:  number of entries in the search table.
//
static int
check_derived_events(char *target, int derived_type, hwi_presets_t* results, hwi_presets_t * search, int search_size, int token_index)
{
	INTDBG("ENTER: target: %p (%s), results: %p, search: %p, search_size: %d, token_index: %d\n", target, target, results, search, search_size, token_index);
	unsigned int i;
	int j;
	int k;
	int found = 0;

	for (j=0; j < search_size; j++) {
		//	INTDBG("search[%d].symbol: %s, looking for: %s\n", j, search[j].symbol, target);
		if (search[j].symbol == NULL) {
			INTDBG("EXIT: returned: 0\n");
			return 0;
		}

		// if not the event we depend on, just look at next
		if ( strcasecmp( target, search[j].symbol) != 0 ) {
			continue;
		}

		INTDBG("Found a match\n");

		// derived formulas need to be adjusted based on what kind of derived event we are processing
		// the derived type passed to this function is the type of the new event being defined (not the events it is based on)
		// when we get here the formula must be in reverse polish notation (RPN) format
		switch (derived_type) {
			case DERIVED_POSTFIX: {
				// go create a formula to merge the second formula into a spot identified by one of the tokens in
				// the first formula.
				ops_string_merge(&(results->postfix), search[j].postfix, token_index, results->count);
				break;
			}
			case DERIVED_ADD: {
				// the new derived event adds two things together, go handle this target events role in the add
				ops_string_append(results, &search[j], 1);
				break;
			}
			case DERIVED_SUB: {
				// go create a formula to subtract the value generated by the second formula from the value generated by the first formula.
				ops_string_append(results, &search[j], 0);
				break;
			}
				default: {
				INTDBG("Derived type: %d, not currently handled\n", derived_type);
				break;
			}
		}

		// copy event name and code used by the derived event into the results table (place where new derived event is getting created)
		for ( k = 0; k < (int)search[j].count; k++ ) {
//			INTDBG("search[%d]: %p, name[%d]: %s, code[%d]: %#x\n", j, &search[j], k, search[j].name[k], k, search[j].code[k]);
			// if this event is already in the list, just update the formula so that references to this event point to the existing one
			for (i=0 ; i < results->count ; i++) {
				if (results->code[i] == search[j].code[k]) {
					INTDBG("event: %s, code: %#x, already in results at index: %d\n", search[j].name[k], search[j].code[k], i);
					// replace all tokens in the formula that refer to index "results->count + found" with a token that refers to index "i".
					// the index "results->count + found" identifies the index used in the formula for the event we just determined is a duplicate
					update_ops_string(&(results->postfix), results->count + found, i);
					found++;
					break;
				}
			}

			// if we did not find a match, copy native event info into results array
			if (found == 0) {
				// not a duplicate, go ahead and copy into results and bump number of native events in results
				if (search[j].name[k]) {
					results->name[results->count] = papi_strdup(search[j].name[k]);
				} else {
					results->name[results->count] = papi_strdup(target);
				}
				results->code[results->count] = search[j].code[k];
				INTDBG("results: %p, name[%d]: %s, code[%d]: %#x\n", results, results->count, results->name[results->count], results->count, results->code[results->count]);

				results->count++;
			}
		}

		INTDBG("EXIT: returned: 1\n");
		return 1;
	}

	INTDBG("EXIT: returned: 0\n");
	return 0;
}
Exemple #13
0
// merge the 'insertion' formula into the 'original' formula replacing the
// 'replaces' token in the 'original' formula.
static void
ops_string_merge(char **original, char *insertion, int replaces, int start_index) {
	INTDBG("ENTER: original: %p, *original: %s, insertion: %s, replaces: %d, start_index: %d\n", original, *original, insertion, replaces, start_index);

	int orig_len=0;
	int ins_len=0;
	char *subtoken;
	char *workBuf;
	char *workPtr;
	char *tok_save_ptr=NULL;
	char *newOriginal;
	char *newInsertion;
	char *newFormula;
	int insert_events;

	if (*original != NULL) {
		orig_len = strlen(*original);
	}
	if (insertion != NULL) {
		ins_len = strlen(insertion);
	}
	newFormula = papi_calloc (orig_len + ins_len + 40, 1);

	// if insertion formula is not provided, then the original formula remains basically unchanged.
	if (insertion == NULL) {
		// if the original formula has a leading '|' then get rid of it
		workPtr = *original;
		if (workPtr[0] == '|') {
			strcpy(newFormula, &workPtr[1]);
		} else {
			strcpy(newFormula, workPtr);
		}
		// formula fields are always malloced space so free the previous one
		papi_free (*original);
		*original = newFormula;
		INTDBG("EXIT: newFormula: %s\n", *original);
		return;
	}

	// renumber the token numbers in the insertion formula
	// also count how many native events are used in this formula
	insert_events = 0;
	newInsertion = papi_calloc(ins_len+20, 1);
	workBuf = papi_calloc(ins_len+10, 1);
	workPtr = papi_strdup(insertion);
	subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
	while ( subtoken != NULL) {
//		INTDBG("subtoken: %s, newInsertion: %s\n", subtoken, newInsertion);
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))) {
			insert_events++;
			int val = atoi(&subtoken[1]);
			val += start_index;
			subtoken[1] = '\0';
			sprintf (workBuf, "N%d", val);
		} else {
			strcpy(workBuf, subtoken);
		}
		strcat (newInsertion, workBuf);
		strcat (newInsertion, "|");
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
	}
	papi_free (workBuf);
	papi_free (workPtr);
	INTDBG("newInsertion: %s\n", newInsertion);

	// if original formula is not provided, then the updated insertion formula becomes the new formula
	// but we still had to renumber the native event tokens in case another native event was put into the list first
	if (*original == NULL) {
		*original = papi_strdup(newInsertion);
		INTDBG("EXIT: newFormula: %s\n", newInsertion);
		papi_free (newInsertion);
		papi_free (newFormula);
		return;
	}

	// if token to replace not valid, return null  (do we also need to check an upper bound ???)
	if ((replaces < 0)) {
		papi_free (newInsertion);
		papi_free (newFormula);
		INTDBG("EXIT: Invalid value for token in original formula to be replaced\n");
		return;
	}

	// renumber the token numbers in the original formula
	// tokens with an index greater than the replaces token need to be incremented by number of events in insertion formula-1
	newOriginal = papi_calloc (orig_len+20, 1);
	workBuf = papi_calloc(orig_len+10, 1);
	workPtr = papi_strdup(*original);

	subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
	while ( subtoken != NULL) {
//		INTDBG("subtoken: %s, newOriginal: %s\n", subtoken, newOriginal);
		// prime the work area with the next token, then see if we need to change it
		strcpy(workBuf, subtoken);
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))) {
			int val = atoi(&subtoken[1]);
			if (val > replaces) {
				val += insert_events-1;
				subtoken[1] = '\0';
				sprintf (workBuf, "N%d", val);
			}
		}
		// put the work buffer into the new original formula
		strcat (newOriginal, workBuf);
		strcat (newOriginal, "|");
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
	}
	papi_free (workBuf);
	papi_free (workPtr);
	INTDBG("newOriginal: %s\n", newOriginal);

	// replace the specified "replace" tokens in the new original formula with the new insertion formula
	newFormula[0] = '\0';
	workPtr = newOriginal;
	subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
	while ( subtoken != NULL) {
//		INTDBG("subtoken: %s, newFormula: %s\n", subtoken, newFormula);
		// if this is the token we want to replace with the insertion string, do it now
		if ((subtoken[0] == 'N')  &&  (isdigit(subtoken[1]))  &&  (replaces == atoi(&subtoken[1]))) {
			// copy updated insertion string into the original string (replacing this token)
			strcat(newFormula, newInsertion);
		} else {
			// copy this part of the original formula into the new formula
			strcat(newFormula, subtoken);
			strcat(newFormula, "|");
		}
		subtoken = strtok_r(NULL, "|", &tok_save_ptr);
	}
	papi_free (newInsertion);
	papi_free (workPtr);

	// formula fields are always malloced space so free the previous one
	papi_free (*original);
	*original = newFormula;
	INTDBG("EXIT: newFormula: %s\n", newFormula);
	return;
}
Exemple #14
0
//
// Handle creating a new derived event of type DERIVED_ADD.  This may create a new formula
// which can be used to compute the results of the new event from the events it depends on.
// This code is also responsible for making sure that all the needed native events are in the
// new events native event list and that the formula's referenced to this array are correct.
//
static void
ops_string_append(hwi_presets_t *results, hwi_presets_t *depends_on, int addition) {
	INTDBG("ENTER: results: %p, depends_on: %p, addition %d\n", results, depends_on, addition);

	int i;
	int second_event = 0;
	char newFormula[PAPI_MIN_STR_LEN] = "";
	char work[20];

	// if our results already have a formula, start with what was collected so far
	// this should only happens when processing the second event of a new derived add
	if (results->postfix != NULL) {
		INTDBG("Event %s has existing formula %s\n", results->symbol, results->postfix);
		// get the existing formula
		strncat(newFormula, results->postfix, sizeof(newFormula)-1);
		newFormula[sizeof(newFormula)-1] = '\0';
		second_event = 1;
	}

	// process based on what kind of event the one we depend on is
	switch (depends_on->derived_int) {
		case DERIVED_POSTFIX: {
			// the event we depend on has a formula, append it our new events formula

			// if event we depend on does not have a formula, report error
			if (depends_on->postfix == NULL) {
				INTDBG("Event %s is of type DERIVED_POSTFIX but is missing operation string\n", depends_on->symbol);
				return;
			}

			// may need to renumber the native event index values in the depends on event formula before putting it into new derived event
			char *temp = papi_strdup(depends_on->postfix);

			// If this is not the first event of the new derived add, need to adjust native event index values in formula.
			// At this time we assume that all the native events in the second events formula are unique for the new event
			// and just bump the indexes by the number of events already known to the new event.  Later when we add the events
			// to the native event list for this new derived event, we will check to see if the native events are already known
			// to the new derived event and if so adjust the indexes again.
			if (second_event) {
				for ( i=depends_on->count-1 ; i>=0 ; i--) {
					update_ops_string(&temp, i, results->count + i);
				}
			}

			// append the existing formula from the event we depend on (but get rid of last '|' character)
			strncat(newFormula, temp, sizeof(newFormula)-1);
			newFormula[sizeof(newFormula)-1] = '\0';
			papi_free (temp);
			break;
		}
		case DERIVED_ADD: {
			// the event we depend on has no formula, create a formula for our new event to add together the depends_on native event values

			// build a formula for this add event
			sprintf(work, "N%d|N%d|+|", results->count, results->count + 1);
			strcat(newFormula, work);
			break;
		}
		case DERIVED_SUB: {
			// the event we depend on has no formula, create a formula for our new event to subtract the depends_on native event values

			// build a formula for this subtract event
			sprintf(work, "N%d|N%d|-|", results->count, results->count + 1);
			strcat(newFormula, work);
			break;
		}
		case NOT_DERIVED: {
			// 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

			// build a formula for this subtract event
			sprintf(work, "N%d|", results->count);
			strcat(newFormula, work);
			break;
		}
		default: {
			// the event we depend on has unsupported derived type, put out some debug and give up
			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);
			return;
		}
	}

	// if this was the second event, append to the formula an operation to add or subtract the results of the two events
	if (second_event) {
		if (addition != 0) {
			strcat(newFormula, "+|");
		} else {
			strcat(newFormula, "-|");
		}
		// also change the new derived events type to show it has a formula now
		results->derived_int = DERIVED_POSTFIX;
	}

	// we need to free the existing space (created by malloc and we need to create a new one)
	papi_free (results->postfix);
	results->postfix = papi_strdup(newFormula);
	INTDBG("EXIT: newFormula: %s\n", newFormula);
	return;
}
/* 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);
}