PAPI  5.0.1.0
papi_user_events.c
Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines