// 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; }
/* _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 ); }
/* 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 ); }
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; }
/* 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
// // 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; }
// 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; }
// // 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); }