|
PAPI
5.0.1.0
|
00001 00009 /* TODO: 00010 * Think about how to support components 00011 * Software multiplexing improvments 00012 * Error bounds on multiplexed counts 00013 * 00014 * Keywords for getting info out of hw_info or something like it. 00015 */ 00016 00017 00018 #include <stdio.h> 00019 #include <stdlib.h> 00020 #include <string.h> 00021 #include <ctype.h> 00022 00023 #include "papi.h" 00024 #include "papi_internal.h" 00025 #include "papi_vector.h" /* for _papi__hwd[]. Should we modify the */ 00026 /* code to not depend on component 0? */ 00027 #include "papi_memory.h" 00028 #include "papi_user_events.h" 00029 00030 #ifdef STATIC_USER_EVENTS 00031 #include "papi_static_user_events.h" 00032 #endif 00033 00034 #define CONSTANT_DELIM "#define" 00035 00036 #define SHOW_LOADS 00037 extern unsigned int PAPI_NATIVE_EVENT_SHIFT; 00038 extern unsigned int PAPI_NATIVE_UMASK_SHIFT; 00039 00040 typedef struct def_list { 00041 char name[PAPI_MIN_STR_LEN]; 00042 char value[PAPI_MIN_STR_LEN]; 00043 struct def_list *next; 00044 } list_t; 00045 00046 00047 user_defined_event_t * _papi_user_events = NULL; 00048 unsigned int _papi_user_events_count = 0; 00049 list_t defines; 00050 int first_time = 1; 00051 00052 00053 void 00054 PRINT_UE(user_defined_event_t* ue) 00055 { 00056 #ifndef DEBUG 00057 (void)ue; /* clean up unused parameter warning if debugging messages are not used */ 00058 #endif 00059 INTDBG("User Event debug\n"); 00060 INTDBG("\tsymbol=%s\n", ue->symbol); 00061 INTDBG("\toperation=%s\n", ue->operation); 00062 INTDBG("\tcount=%d\n", ue->count); 00063 } 00064 00065 void 00066 _papi_cleanup_user_events() 00067 { 00068 unsigned int i; 00069 user_defined_event_t *t; 00070 list_t *a,*b; 00071 00072 for ( i = 0; i < _papi_user_events_count; i++ ) { 00073 t = _papi_user_events + i; 00074 00075 if ( t->short_desc != NULL ) 00076 free(t->short_desc); 00077 if ( t->long_desc != NULL ) 00078 free(t->long_desc); 00079 00080 } 00081 00082 if ( _papi_user_events != NULL ) 00083 papi_free( _papi_user_events ); 00084 00085 _papi_user_events = NULL; 00086 _papi_user_events_count = 0; 00087 00088 /* cleanup the defines list too */ 00089 for ( a = defines.next; a != NULL; ) { 00090 b=a->next; 00091 papi_free(a); 00092 a = b; 00093 } 00094 } 00095 00096 void 00097 append_to_global_list(user_defined_event_t *more ) 00098 { 00099 user_defined_event_t* new; 00100 00101 new = papi_malloc(sizeof(user_defined_event_t) * (1 + _papi_user_events_count) ); 00102 if (new == NULL) { 00103 PAPIERROR("Unable to allocate %d bytes of memory.\n", sizeof(user_defined_event_t)*(1+_papi_user_events_count)); 00104 } else { 00105 if (_papi_user_events != NULL) { 00106 memcpy(new, _papi_user_events, _papi_user_events_count*sizeof(user_defined_event_t)); 00107 papi_free(_papi_user_events); 00108 } 00109 00110 memcpy( new + _papi_user_events_count, more, sizeof(user_defined_event_t) ); 00111 00112 _papi_user_events = new; 00113 _papi_user_events_count++; 00114 } 00115 } 00116 00117 int 00118 is_operation(char *op) 00119 { 00120 char first = op[0]; 00121 00122 switch(first) { 00123 case '+': 00124 case '-': 00125 case '*': 00126 case '/': 00127 case '%': 00128 return 1; 00129 default: 00130 return 0; 00131 } 00132 } 00133 00134 00135 /* Trims blank space from both ends of a string (in place). 00136 Returns pointer to new start address */ 00137 static inline char * 00138 trim_string( char *in ) 00139 { 00140 int len, i = 0; 00141 char *start = in; 00142 00143 if ( in == NULL ) 00144 return ( in ); 00145 len = ( int ) strlen( in ); 00146 if ( len == 0 ) 00147 return ( in ); 00148 /* Trim left */ 00149 while ( i < len ) { 00150 if ( isblank( in[i] ) ) { 00151 in[i] = '\0'; 00152 start++; 00153 } else 00154 break; 00155 i++; 00156 } 00157 /* Trim right */ 00158 i = ( int ) strlen( start ) - 1; 00159 while ( i >= 0 ) { 00160 if ( isblank( start[i] ) ) 00161 start[i] = '\0'; 00162 else 00163 break; 00164 i--; 00165 } 00166 return ( start ); 00167 } 00168 00169 /* Calls trim_string to remove blank space; 00170 Removes paired punctuation delimiters from 00171 beginning and end of string. If the same punctuation 00172 appears first and last (quotes, slashes) they are trimmed; 00173 Also checks for the following pairs: () <> {} [] */ 00174 static inline char * 00175 trim_note( char *in ) 00176 { 00177 int len; 00178 char *note, start, end; 00179 00180 note = trim_string( in ); 00181 if ( note != NULL ) { 00182 len = ( int ) strlen( note ); 00183 if ( len > 0 ) { 00184 if ( ispunct( *note ) ) { 00185 start = *note; 00186 end = note[len - 1]; 00187 if ( ( start == end ) 00188 || ( ( start == '(' ) && ( end == ')' ) ) 00189 || ( ( start == '<' ) && ( end == '>' ) ) 00190 || ( ( start == '{' ) && ( end == '}' ) ) 00191 || ( ( start == '[' ) && ( end == ']' ) ) ) { 00192 note[len - 1] = '\0'; 00193 *note = '\0'; 00194 note++; 00195 } 00196 } 00197 } 00198 } 00199 return ( note ); 00200 } 00201 00202 00203 /* parse a single line from either a file or character table 00204 Strip trailing <cr>; return 0 if empty */ 00205 static int 00206 get_event_line( char **place, FILE * table, char **tmp_perfmon_events_table ) 00207 { 00208 int ret = 0; 00209 int i; 00210 char *line = place[0]; 00211 int c = 0; 00212 00213 if ( table ) { 00214 if ( fgets( place[0], USER_EVENT_OPERATION_LEN, table ) ) { 00215 00216 i = strlen( place[0] ); 00217 c = place[0][i-1]; 00218 /* throw away the rest of the line. */ 00219 while ( c != '\n' && c != EOF ) 00220 c = fgetc( table ); 00221 00222 ret = i; 00223 line = place[0]; 00224 00225 for ( i = 0; i < (int)strlen( place[0] ); i++ ) 00226 if ( place[0][i] == '\n' ) 00227 place[0][i] = 0; 00228 } else 00229 ret = 0; 00230 } else { 00231 for ( i = 0; 00232 **tmp_perfmon_events_table && **tmp_perfmon_events_table != '\n' && 00233 i < USER_EVENT_OPERATION_LEN; 00234 i++ ) { 00235 line[i] = **tmp_perfmon_events_table; 00236 ( *tmp_perfmon_events_table )++; 00237 } 00238 if ( **tmp_perfmon_events_table == '\n' ) { 00239 ( *tmp_perfmon_events_table )++; 00240 } 00241 line[i] = '\0'; 00242 ret = **tmp_perfmon_events_table; 00243 } 00244 return ( ret ); 00245 } 00246 00247 int add_define( char *line, list_t* LIST ) { 00248 char *t; 00249 char local_line[USER_EVENT_OPERATION_LEN]; 00250 list_t *temp; 00251 00252 strncpy( local_line, line, USER_EVENT_OPERATION_LEN ); 00253 00254 temp = (list_t*)papi_malloc(sizeof(list_t)); 00255 00256 if ( NULL == temp ) { 00257 PAPIERROR("outof memory" ); 00258 return PAPI_ENOMEM; 00259 } 00260 00261 strtok(local_line, " "); /* throw out the #define */ 00262 00263 /* next token should be the name */ 00264 t = strtok(NULL, " "); 00265 strncpy( temp->name, t, PAPI_MIN_STR_LEN); 00266 00267 /* next token should be the value */ 00268 t = strtok(NULL," "); 00269 t[strlen(t)] = '\0'; 00270 strncpy( temp->value, t, PAPI_MIN_STR_LEN); 00271 00272 temp->next = LIST->next; 00273 LIST->next = temp; 00274 00275 return PAPI_OK; 00276 } 00277 00278 int renumber_ops_string(char *dest, char *src, int start) { 00279 char *saveptr, *subtoken; 00280 char *pass; 00281 char temp[PAPI_MIN_STR_LEN]; 00282 char orig[PAPI_MIN_STR_LEN]; 00283 00284 memcpy(orig, src, PAPI_MIN_STR_LEN); 00285 pass = orig; 00286 00287 while ( (subtoken = strtok_r( pass, "|", &saveptr)) != NULL ) { 00288 pass = NULL; 00289 if ( subtoken[0] == 'N' ) { 00290 sprintf(temp, "N%d|", start++); 00291 strcat(dest, temp); 00292 } else { 00293 strcat(dest, subtoken); 00294 strcat(dest, "|"); 00295 } 00296 } 00297 return start; 00298 } 00299 00300 int is_define(char *t, list_t *next, char *ops) { 00301 int found = 0; 00302 char temp[PAPI_MIN_STR_LEN]; 00303 int len = 0; 00304 00305 /* check if its a predefined constant */ 00306 while( next != (void*) NULL ) { 00307 if ( ! strcmp(t, next->name) ) { 00308 sprintf(temp,"%s|", next->value); 00309 len = strlen(ops) + strlen(temp); 00310 if ( len >= USER_EVENT_OPERATION_LEN ) { 00311 fprintf(stderr,"outa room"); 00312 return -1; 00313 } 00314 00315 strcat(ops,temp); 00316 found = 1; 00317 break; 00318 } 00319 next = next->next; 00320 } 00321 return (found); 00322 } 00323 00324 int 00325 check_native_events(char *target, user_defined_event_t* ue, int* msi) 00326 { 00327 char temp[PAPI_MIN_STR_LEN]; 00328 int found = 0; 00329 int ret; 00330 int magic_string_int = *msi; 00331 int len = 0; 00332 00333 if ( ( ret = _papi_hwi_native_name_to_code( target, &ue->events[ue->count] ) ) == PAPI_OK ) { 00334 if ( ue->events[ue->count] == 0 ) { 00335 INTDBG( "Event %s not found!\n", target); 00336 } else { 00337 found = 1; 00338 sprintf(temp, "N%d|", magic_string_int++); 00339 len = strlen(ue->operation) + strlen(temp); 00340 ue->count++; 00341 #ifdef SHOW_LOADS 00342 INTDBG("\tFound a native event %s\n", target); 00343 #endif 00344 if ( len >= USER_EVENT_OPERATION_LEN ) { 00345 fprintf(stderr,"outa room"); 00346 return -1; 00347 } 00348 strcat(ue->operation, temp); 00349 *msi = magic_string_int; 00350 } 00351 } 00352 00353 return found; 00354 } 00355 00356 int 00357 check_preset_events (char *target, user_defined_event_t* ue, int* msi) 00358 { 00359 char op; 00360 int j = 0; 00361 int k; 00362 int found = 0; 00363 int magic_string_int = *msi; 00364 00365 char temp[PAPI_MIN_STR_LEN]; 00366 00367 /* XXX make sure that we don't overflow the ue->operation buffer */ 00368 int length = PAPI_MIN_STR_LEN; 00369 00370 memset(temp, 0, PAPI_MIN_STR_LEN); 00371 for ( j = 0; ( j < PAPI_MAX_PRESET_EVENTS) && (_papi_hwi_presets[j].symbol != NULL ); j++ ) { 00372 if ( strcasecmp( target, _papi_hwi_presets[j].symbol ) == 0) { 00373 #ifdef SHOW_LOADS 00374 INTDBG("\tFound a match for preset event %s\n", _papi_hwi_presets[j].symbol); 00375 #endif 00376 /* Check that the preset event we're trying to add is actually available on this system */ 00377 if ( _papi_hwi_presets[j].count == 0 ) { 00378 PAPIERROR("NEXTLINE:\t%s is not available on this platform. Skipping event %s\n", 00379 target, ue->symbol); 00380 /* clean up this and ditch this whole line */ 00381 memset(ue, 0, sizeof(user_defined_event_t)); 00382 return -1; 00383 } 00384 00385 length = strlen(ue->operation); 00386 00387 /* Deal with singleton events */ 00388 if (!_papi_hwi_presets[j].derived_int) { 00389 sprintf(temp, "N%d|", magic_string_int++); 00390 length = strlen(ue->operation) + strlen(temp); 00391 if ( length >= USER_EVENT_OPERATION_LEN ) { 00392 fprintf(stderr,"Out of room, the user defined event %s is too large!\n", ue->symbol ); 00393 return -1; 00394 } 00395 strcat(ue->operation, temp); 00396 ue->events[ue->count++] = _papi_hwi_presets[j].code[0]; 00397 } else { 00398 op = '-'; 00399 switch ( _papi_hwi_presets[j].derived_int ) { 00400 case DERIVED_ADD: 00401 case DERIVED_ADD_PS: 00402 op = '+'; 00403 case DERIVED_SUB: 00404 for ( k = 0; k < (int) _papi_hwi_presets[j].count; k++) { 00405 ue->events[ue->count++] = _papi_hwi_presets[j].code[k]; 00406 if (k%2) 00407 sprintf(temp, "N%d|%c|", magic_string_int++, op); 00408 else 00409 sprintf(temp, "N%d|", magic_string_int++); 00410 00411 length = strlen(ue->operation) + strlen(temp); 00412 if ( USER_EVENT_OPERATION_LEN <= length ) { 00413 PAPIERROR("The user defined event %s has to may operands in its definition.\n", ue->symbol ); 00414 return -1; 00415 } 00416 strcat(ue->operation, temp); 00417 } 00418 break; 00419 00420 case DERIVED_POSTFIX: 00421 for ( k = 0; k < (int)_papi_hwi_presets[j].count; k++ ) { 00422 ue->events[ue->count++] = _papi_hwi_presets[j].code[k]; 00423 } 00424 /* so we need to go through the ops string and renumber the N's 00425 as we place it in our ue ops string */ 00426 magic_string_int = renumber_ops_string(temp, 00427 _papi_hwi_presets[j].postfix, magic_string_int); 00428 length = strlen( temp ) + strlen( ue->operation ); 00429 if ( length >= USER_EVENT_OPERATION_LEN ) { 00430 PAPIERROR( "User Event %s's expression is too long.", ue->symbol ); 00431 return -1; 00432 } 00433 strcat(ue->operation, temp); 00434 default: 00435 break; 00436 } /* /switch */ 00437 } /* /derived */ 00438 found = 1; 00439 break; 00440 } /* /symbol match */ 00441 00442 } /* end while(preset events) */ 00443 00444 *msi = magic_string_int; 00445 return found; 00446 } 00447 00448 int 00449 check_user_events(char *target, user_defined_event_t* ue, int* msi, user_defined_event_t* search, int search_size) 00450 { 00451 char temp[PAPI_MIN_STR_LEN]; 00452 int j = 0; 00453 int k = 0; 00454 int found = 0; 00455 int magic_string_int = *msi; 00456 int len = 0; 00457 00458 memset(temp, 0, PAPI_MIN_STR_LEN); 00459 for (j=0; j < search_size; j++) { 00460 if ( strcasecmp( target, search[j].symbol) == 0 ) { 00461 #ifdef SHOW_LOADS 00462 INTDBG("\tFount a match for user event %s at search[%d]\n", search[j].symbol, j ); 00463 #endif 00464 00465 for ( k = 0; k < (int)search[j].count; k++ ) { 00466 ue->events[ue->count++] = search[j].events[k]; 00467 } 00468 00469 /* so we need to go through the ops string and renumber the N's 00470 as we place it in our ue ops string */ 00471 magic_string_int = renumber_ops_string(temp, 00472 search[j].operation, magic_string_int); 00473 00474 len = strlen( temp ) + strlen( ue->operation ); 00475 if ( len >= USER_EVENT_OPERATION_LEN ) { 00476 PAPIERROR( "User Event %s is trying to use an invalid expression, its too long.", ue->symbol ); 00477 return -1; 00478 } 00479 strcat(ue->operation, temp); 00480 found = 1; 00481 } 00482 } 00483 00484 *msi = magic_string_int; 00485 return found; 00486 } 00487 00488 /* 00489 * name, expr (events to lookup later)... 00490 * 00491 * Do we keep rpn? Probably... 00492 * but DATA_CACHE_MISSES|INSTRUCTION_CACHE_MISSES|+ is servicable... 00493 * 00494 * Do we keep the csv format? 00495 * N0|N1|+|n2|* == (n0+n1)*n2 ?? 00496 * if not, we do have to still create the string 00497 * so that add_events can parse it... 00498 * 00499 * Ok, how do we denote where the event lives (and if there are more than one, what do we do) 00500 * COMP_NAME:EVENT_NAME ? 00501 * COMP_NAME:SUB_OPT:EVENT_NAME ? 00502 * CPU:0:L3_CACHE_FILLS ? 00503 */ 00504 00505 static int 00506 load_user_event_table( char *file_name) 00507 { 00508 char *line; 00509 char temp[PAPI_MIN_STR_LEN]; 00510 char *t; 00511 char **ptr = NULL; 00512 int i; 00513 int insert = 0; 00514 int size = 0; 00515 int tokens = 0; 00516 int found = 0; 00517 int error; 00518 int oops; 00519 int len = 0; 00520 int magic_string_int; 00521 FILE* table = NULL; 00522 user_defined_event_t *foo; 00523 00524 00525 if ( file_name == NULL ) { 00526 #ifndef STATIC_USER_EVENTS 00527 PAPIERROR( "Cowardly refusing to load events file NULL\n" ); 00528 return ( PAPI_EBUG ); 00529 #else 00530 /* Only parse the static events once! */ 00531 if ( !first_time ) { 00532 PAPIERROR("Cowardly refusing to load events file NULL\n" ); 00533 return ( PAPI_EBUG ); 00534 } 00535 00536 INTDBG("Loading events from papi_static_user_events.h\n"); 00537 ptr = &user_events_table; 00538 table = NULL; 00539 00540 #endif 00541 } else { 00542 table = fopen(file_name, "r"); 00543 00544 if ( !table ) { 00545 PAPIERROR( "The user events file '%s' does not exist; bailing!", file_name ); 00546 return ( PAPI_EBUG ); 00547 } 00548 00549 } 00550 00551 line = (char*) malloc( USER_EVENT_OPERATION_LEN + 1 ); 00552 /* Main parse loop */ 00553 while (get_event_line(&line, table, ptr) > 0 ) { 00554 error=1; 00555 i=0; 00556 magic_string_int = 0; 00557 len = 0; 00558 00559 t = trim_string( strtok(line, ",")); 00560 if ( (t==NULL) || (strlen(t) == 0) ) 00561 continue; 00562 00563 foo = ( user_defined_event_t *) papi_malloc(sizeof(user_defined_event_t)); 00564 memset( foo, 0x0, sizeof(user_defined_event_t) ); 00565 00566 /* Deal with comments and constants */ 00567 if (t[0] == '#') { 00568 if ( 0 == strncmp("define",t+1,6) ) { 00569 if ( PAPI_OK != (oops = add_define( t , &defines ) ) ) { 00570 papi_free(foo); 00571 if (table) 00572 fclose(table); 00573 return oops; 00574 } 00575 continue; 00576 } 00577 goto nextline; 00578 } 00579 00580 strncpy(foo->symbol, t, PAPI_MIN_STR_LEN); 00581 #ifdef SHOW_LOADS 00582 INTDBG("Found a user event named %s\n", foo->symbol ); 00583 #endif 00584 /* This segment handles the postfix operation string 00585 * converting it from OPERAND1|OPERAND2|+ 00586 * to the papi internal N1|N2|+ : OPERAND1:OPERAND2 00587 * with some basic sanity checking of the operands */ 00588 00589 do { 00590 memset(temp, 0, sizeof(temp)); 00591 found = 0; 00592 t = trim_string(strtok(NULL, "|")); 00593 if ( (t==NULL) || (strlen(t) == 0) ) 00594 break; 00595 00596 if ( is_operation(t) ) { 00597 #ifdef SHOW_LOADS 00598 INTDBG("\tFound operation %c\n", t[0]); 00599 #endif 00600 sprintf(temp, "%c|", t[0]); 00601 len = strlen(foo->operation) + strlen(temp); 00602 if ( len >= USER_EVENT_OPERATION_LEN ) { 00603 PAPIERROR("User Event %s's expression is too long.", foo->symbol ); 00604 goto nextline; 00605 } 00606 strcat(foo->operation, temp); 00607 tokens--; 00608 } else if ( isdigit(t[0]) ) { 00609 /* its a number, the read time parser handlers those */ 00610 sprintf(temp,"%s|", t); 00611 len = strlen( foo->operation ) + strlen( temp ); 00612 if ( len >= USER_EVENT_OPERATION_LEN ) { 00613 PAPIERROR("Invalid event specification %s's expression is too long.", foo->symbol); 00614 goto nextline; 00615 } 00616 strcat(foo->operation, temp); 00617 tokens++; 00618 #ifdef SHOW_LOADS 00619 INTDBG("\tFound number %s\n", t); 00620 #endif 00621 } else if (is_define(t, defines.next, foo->operation)) { 00622 tokens++; 00623 #ifdef SHOW_LOADS 00624 INTDBG("\tFound a predefined thing %s\n", t); 00625 #endif 00626 } else { 00627 /* check if its a native event */ 00628 if ( check_native_events(t, foo, &magic_string_int) ) { 00629 found = 1; 00630 } 00631 00632 /* so its not a native event, is it a preset? */ 00633 if ( !found ) { 00634 found = check_preset_events(t, foo, &magic_string_int); 00635 } /* end preset check */ 00636 00637 /* its not native nor preset is it a UE that we've already seen? */ 00638 /* look through _papi_user_events */ 00639 if ( !found ) { 00640 found = check_user_events(t, foo, &magic_string_int, 00641 _papi_user_events, _papi_user_events_count); 00642 } 00643 00644 /* and the current array of parsed events from this file */ 00645 if ( !found ) { 00646 if (insert > 0) 00647 found = check_user_events(t, foo, &magic_string_int, foo, insert); 00648 } 00649 00650 if ( !found ) { 00651 INTDBG("HELP!!! UNABLE TO FIND SYMBOL %s\n", t); 00652 PAPIERROR("NEXTLIN:\tSymbol lookup failure, I have no clue what %s is, perhaps you have a bad ops string?\n", t); 00653 goto nextline; 00654 } else { 00655 tokens++; 00656 } 00657 } /* END native, preset, user defined event lookups */ 00658 00659 } while( (int)foo->count < _papi_hwd[0]->cmp_info.num_mpx_cntrs ); 00660 00661 if ( _papi_hwd[0]->cmp_info.num_mpx_cntrs - (int)foo->count < tokens ) { 00662 INTDBG("Event %s is attempting to use too many terms in its expression.\n", foo->symbol ); 00663 goto nextline; 00664 } 00665 00666 /* refine what we mean here, if we exaust the number of counters, do we still allow constants */ 00667 while ( tokens > 1 ) { 00668 t = trim_string(strtok(NULL, "|")); 00669 if ( t == NULL ) { 00670 INTDBG("INVALID event specification (%s)\n", foo->symbol); 00671 goto nextline; 00672 } 00673 if ( is_operation(t) ) { 00674 sprintf(temp,"%c|", t[0]); 00675 /* TODO */ 00676 len = strlen(temp) + strlen(foo->operation); 00677 if ( len >= USER_EVENT_OPERATION_LEN ) { 00678 PAPIERROR("User Event %s contains too many operations.", foo->symbol ); 00679 goto nextline; 00680 } 00681 strcat(foo->operation, temp); 00682 tokens--; 00683 } else { 00684 PAPIERROR("INVALID event specification, %s is attempting to use too many events\n", foo->symbol); 00685 goto nextline; 00686 } 00687 } 00688 00689 append_to_global_list( foo ); 00690 #ifdef SHOW_LOADS 00691 PRINT_UE(foo); 00692 #endif 00693 00694 insert++; 00695 size++; 00696 error = 0; 00697 nextline: 00698 tokens = 0; 00699 papi_free(foo); 00700 } /* End main parse loop */ 00701 if (table) 00702 fclose(table); 00703 00704 free(line); 00705 return insert; 00706 } 00707 00708 int 00709 _papi_user_defined_events_setup(char *name) 00710 { 00711 int retval; 00712 00713 if ( first_time ) { 00714 _papi_user_events_count = 0; 00715 defines.next = NULL; 00716 } 00717 00718 retval = load_user_event_table( name ); 00719 00720 if (retval < 0) 00721 return( retval ); 00722 00723 first_time = 0; 00724 return( PAPI_OK ); 00725 } 00726