PAPI  5.4.1.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
papi_preset.c
Go to the documentation of this file.
1 /*
2 * File: papi_preset.c
3 * Author: Haihang You
4 * you@cs.utk.edu
5 * Mods: Brian Sheely
6 * bsheely@eecs.utk.edu
7 * Author: Vince Weaver
8 * vweaver1 @ eecs.utk.edu
9 * Merge of the libpfm3/libpfm4/pmapi-ppc64_events preset code
10 */
11 
12 
13 #include <string.h>
14 #include <ctype.h>
15 #include <errno.h>
16 
17 #include "papi.h"
18 #include "papi_internal.h"
19 #include "papi_vector.h"
20 #include "papi_memory.h"
21 #include "papi_preset.h"
22 #include "extras.h"
23 
24 
25 // A place to put user defined events
27 extern int user_defined_events_count;
28 
29 static int papi_load_derived_events (char *pmu_str, int pmu_type, int cidx, int preset_flag);
30 
31 
32 /* This routine copies values from a dense 'findem' array of events
33  into the sparse global _papi_hwi_presets array, which is assumed
34  to be empty at initialization.
35 
36  Multiple dense arrays can be copied into the sparse array, allowing
37  event overloading at run-time, or allowing a baseline table to be
38  augmented by a model specific table at init time.
39 
40  This method supports adding new events; overriding existing events, or
41  deleting deprecated events.
42 */
43 int
45 {
46  int i, pnum, did_something = 0;
47  unsigned int preset_index, j, k;
48 
49  /* dense array of events is terminated with a 0 preset.
50  don't do anything if NULL pointer. This allows just notes to be loaded.
51  It's also good defensive programming.
52  */
53  if ( findem != NULL ) {
54  for ( pnum = 0; ( pnum < PAPI_MAX_PRESET_EVENTS ) &&
55  ( findem[pnum].event_code != 0 ); pnum++ ) {
56  /* find the index for the event to be initialized */
57  preset_index = ( findem[pnum].event_code & PAPI_PRESET_AND_MASK );
58  /* count and set the number of native terms in this event,
59  these items are contiguous.
60 
61  PAPI_EVENTS_IN_DERIVED_EVENT is arbitrarily defined in the high
62  level to be a reasonable number of terms to use in a derived
63  event linear expression, currently 8.
64 
65  This wastes space for components with less than 8 counters,
66  but keeps the framework independent of the components.
67 
68  The 'native' field below is an arbitrary opaque identifier
69  that points to information on an actual native event.
70  It is not an event code itself (whatever that might mean).
71  By definition, this value can never == PAPI_NULL.
72  - dkt */
73 
74  INTDBG( "Counting number of terms for preset index %d, "
75  "search map index %d.\n", preset_index, pnum );
76  i = 0;
77  j = 0;
78  while ( i < PAPI_EVENTS_IN_DERIVED_EVENT ) {
79  if ( findem[pnum].native[i] != PAPI_NULL ) {
80  j++;
81  }
82  else if ( j ) {
83  break;
84  }
85  i++;
86  }
87 
88  INTDBG( "This preset has %d terms.\n", j );
89  _papi_hwi_presets[preset_index].count = j;
90 
91  _papi_hwi_presets[preset_index].derived_int = findem[pnum].derived;
92  for(k=0;k<j;k++) {
93  _papi_hwi_presets[preset_index].code[k] =
94  findem[pnum].native[k];
95  }
96  /* preset code list must be PAPI_NULL terminated */
98  _papi_hwi_presets[preset_index].code[k] = PAPI_NULL;
99  }
100 
101  _papi_hwi_presets[preset_index].postfix=
102  papi_strdup(findem[pnum].operation);
103 
104  did_something++;
105  }
106  }
107 
108  _papi_hwd[cidx]->cmp_info.num_preset_events += did_something;
109 
110  return ( did_something ? PAPI_OK : PAPI_ENOEVNT );
111 }
112 
113 int
115 {
116  int preset_index,cidx;
117  unsigned int j;
118 
119  for ( preset_index = 0; preset_index < PAPI_MAX_PRESET_EVENTS;
120  preset_index++ ) {
121  if ( _papi_hwi_presets[preset_index].postfix != NULL ) {
122  papi_free( _papi_hwi_presets[preset_index].postfix );
123  _papi_hwi_presets[preset_index].postfix = NULL;
124  }
125  if ( _papi_hwi_presets[preset_index].note != NULL ) {
126  papi_free( _papi_hwi_presets[preset_index].note );
127  _papi_hwi_presets[preset_index].note = NULL;
128  }
129  for(j=0; j<_papi_hwi_presets[preset_index].count;j++) {
130  papi_free(_papi_hwi_presets[preset_index].name[j]);
131  }
132  }
133 
134  for(cidx=0;cidx<papi_num_components;cidx++) {
136  }
137 
138 #if defined(ITANIUM2) || defined(ITANIUM3)
139  /* NOTE: This memory may need to be freed for BG/P builds as well */
140  if ( preset_search_map != NULL ) {
142  preset_search_map = NULL;
143  }
144 #endif
145 
146  return PAPI_OK;
147 }
148 
149 
150 
151 #define PAPI_EVENT_FILE "papi_events.csv"
152 
153 
154 /* Trims blank space from both ends of a string (in place).
155  Returns pointer to new start address */
156 static inline char *
157 trim_string( char *in )
158 {
159  int len, i = 0;
160  char *start = in;
161 
162  if ( in == NULL )
163  return ( in );
164  len = ( int ) strlen( in );
165  if ( len == 0 )
166  return ( in );
167 
168  /* Trim left */
169  while ( i < len ) {
170  if ( isblank( in[i] ) ) {
171  in[i] = '\0';
172  start++;
173  } else
174  break;
175  i++;
176  }
177 
178  /* Trim right */
179  i = ( int ) strlen( start ) - 1;
180  while ( i >= 0 ) {
181  if ( isblank( start[i] ) )
182  start[i] = '\0';
183  else
184  break;
185  i--;
186  }
187  return ( start );
188 }
189 
190 
191 /* Calls trim_string to remove blank space;
192  Removes paired punctuation delimiters from
193  beginning and end of string. If the same punctuation
194  appears first and last (quotes, slashes) they are trimmed;
195  Also checks for the following pairs: () <> {} [] */
196 static inline char *
197 trim_note( char *in )
198 {
199  int len;
200  char *note, start, end;
201 
202  note = trim_string( in );
203  if ( note != NULL ) {
204  len = ( int ) strlen( note );
205  if ( len > 0 ) {
206  if ( ispunct( *note ) ) {
207  start = *note;
208  end = note[len - 1];
209  if ( ( start == end )
210  || ( ( start == '(' ) && ( end == ')' ) )
211  || ( ( start == '<' ) && ( end == '>' ) )
212  || ( ( start == '{' ) && ( end == '}' ) )
213  || ( ( start == '[' ) && ( end == ']' ) ) ) {
214  note[len - 1] = '\0';
215  *note = '\0';
216  note++;
217  }
218  }
219  }
220  }
221  return note;
222 }
223 
224 static inline int
225 find_event_index(hwi_presets_t *array, int size, char *tmp) {
226  SUBDBG("ENTER: array: %p, size: %d, tmp: %s\n", array, size, tmp);
227  int i;
228  for (i = 0; i < size; i++) {
229  if (array[i].symbol == NULL) {
230  array[i].symbol = papi_strdup(tmp);
231  SUBDBG("EXIT: i: %d\n", i);
232  return i;
233  }
234  if (strcasecmp(tmp, array[i].symbol) == 0) {
235  SUBDBG("EXIT: i: %d\n", i);
236  return i;
237  }
238  }
239  SUBDBG("EXIT: PAPI_EINVAL\n");
240  return PAPI_EINVAL;
241 }
242 
243 /* Look for an event file 'name' in a couple common locations.
244  Return a valid file handle if found */
245 static FILE *
247 {
248  FILE *table;
249 
250  SUBDBG( "Opening %s\n", name );
251  table = fopen( name, "r" );
252  if ( table == NULL ) {
253  SUBDBG( "Open %s failed, trying ./%s.\n",
254  name, PAPI_EVENT_FILE );
255  sprintf( name, "%s", PAPI_EVENT_FILE );
256  table = fopen( name, "r" );
257  }
258  if ( table == NULL ) {
259  SUBDBG( "Open ./%s failed, trying ../%s.\n",
260  name, PAPI_EVENT_FILE );
261  sprintf( name, "../%s", PAPI_EVENT_FILE );
262  table = fopen( name, "r" );
263  }
264  if ( table ) {
265  SUBDBG( "Open %s succeeded.\n", name );
266  }
267  return table;
268 }
269 
270 /* parse a single line from either a file or character table
271  Strip trailing <cr>; return 0 if empty */
272 static int
273 get_event_line( char *line, FILE * table, char **tmp_perfmon_events_table )
274 {
275  int i;
276 
277  if ( table ) {
278  if ( fgets( line, LINE_MAX, table ) == NULL)
279  return 0;
280 
281  i = ( int ) strlen( line );
282  if (i == 0)
283  return 0;
284  if ( line[i-1] == '\n' )
285  line[i-1] = '\0';
286  return 1;
287  } else {
288  for ( i = 0;
289  **tmp_perfmon_events_table && **tmp_perfmon_events_table != '\n';
290  i++, ( *tmp_perfmon_events_table )++ )
291  line[i] = **tmp_perfmon_events_table;
292  if (i == 0)
293  return 0;
294  if ( **tmp_perfmon_events_table && **tmp_perfmon_events_table == '\n' ) {
295  ( *tmp_perfmon_events_table )++;
296  }
297  line[i] = '\0';
298  return 1;
299  }
300 }
301 
302 // update tokens in formula referring to index "old_index" with tokens referring to index "new_index".
303 static void
304 update_ops_string(char **formula, int old_index, int new_index) {
305  INTDBG("ENTER: *formula: %s, old_index: %d, new_index: %d\n", *formula?*formula:"NULL", old_index, new_index);
306 
307  int cur_index;
308  char *newFormula;
309  char *subtoken;
310  char *tok_save_ptr=NULL;
311 
312  // if formula is null just return
313  if (*formula == NULL) {
314  INTDBG("EXIT: Null pointer to formula passed in\n");
315  return;
316  }
317 
318  // get some space for the new formula we are going to create
319  newFormula = papi_calloc(strlen(*formula) + 20, 1);
320 
321  // replace the specified "replace" tokens in the new original formula with the new insertion formula
322  newFormula[0] = '\0';
323  subtoken = strtok_r(*formula, "|", &tok_save_ptr);
324  while ( subtoken != NULL) {
325 // INTDBG("subtoken: %s, newFormula: %s\n", subtoken, newFormula);
326  char work[10];
327  // if this is the token we want to replace with the new token index, do it now
328  if ((subtoken[0] == 'N') && (isdigit(subtoken[1]))) {
329  cur_index = atoi(&subtoken[1]);
330  // if matches old index, use the new one
331  if (cur_index == old_index) {
332  sprintf (work, "N%d", new_index);
333  strcat (newFormula, work);
334  } else if (cur_index > old_index) {
335  // current token greater than old index, make it one less than what it was
336  sprintf (work, "N%d", cur_index-1);
337  strcat (newFormula, work);
338  } else {
339  // current token less than old index, copy this part of the original formula into the new formula
340  strcat(newFormula, subtoken);
341  }
342  } else {
343  // copy this part of the original formula into the new formula
344  strcat(newFormula, subtoken);
345  }
346  strcat (newFormula, "|");
347  subtoken = strtok_r(NULL, "|", &tok_save_ptr);
348  }
349  papi_free (*formula);
350  *formula = newFormula;
351 
352  INTDBG("EXIT: newFormula: %s\n", newFormula);
353  return;
354 }
355 
356 //
357 // Handle creating a new derived event of type DERIVED_ADD. This may create a new formula
358 // which can be used to compute the results of the new event from the events it depends on.
359 // This code is also responsible for making sure that all the needed native events are in the
360 // new events native event list and that the formula's referenced to this array are correct.
361 //
362 static void
363 ops_string_append(hwi_presets_t *results, hwi_presets_t *depends_on, int addition) {
364  INTDBG("ENTER: results: %p, depends_on: %p, addition %d\n", results, depends_on, addition);
365 
366  int i;
367  int second_event = 0;
368  char newFormula[PAPI_MIN_STR_LEN] = "";
369  char work[20];
370 
371  // if our results already have a formula, start with what was collected so far
372  // this should only happens when processing the second event of a new derived add
373  if (results->postfix != NULL) {
374  INTDBG("Event %s has existing formula %s\n", results->symbol, results->postfix);
375  // get the existing formula
376  strncat(newFormula, results->postfix, sizeof(newFormula)-1);
377  newFormula[sizeof(newFormula)-1] = '\0';
378  second_event = 1;
379  }
380 
381  // process based on what kind of event the one we depend on is
382  switch (depends_on->derived_int) {
383  case DERIVED_POSTFIX: {
384  // the event we depend on has a formula, append it our new events formula
385 
386  // if event we depend on does not have a formula, report error
387  if (depends_on->postfix == NULL) {
388  INTDBG("Event %s is of type DERIVED_POSTFIX but is missing operation string\n", depends_on->symbol);
389  return;
390  }
391 
392  // may need to renumber the native event index values in the depends on event formula before putting it into new derived event
393  char *temp = papi_strdup(depends_on->postfix);
394 
395  // If this is not the first event of the new derived add, need to adjust native event index values in formula.
396  // At this time we assume that all the native events in the second events formula are unique for the new event
397  // and just bump the indexes by the number of events already known to the new event. Later when we add the events
398  // to the native event list for this new derived event, we will check to see if the native events are already known
399  // to the new derived event and if so adjust the indexes again.
400  if (second_event) {
401  for ( i=depends_on->count-1 ; i>=0 ; i--) {
402  update_ops_string(&temp, i, results->count + i);
403  }
404  }
405 
406  // append the existing formula from the event we depend on (but get rid of last '|' character)
407  strncat(newFormula, temp, sizeof(newFormula)-1);
408  newFormula[sizeof(newFormula)-1] = '\0';
409  papi_free (temp);
410  break;
411  }
412  case DERIVED_ADD: {
413  // the event we depend on has no formula, create a formula for our new event to add together the depends_on native event values
414 
415  // build a formula for this add event
416  sprintf(work, "N%d|N%d|+|", results->count, results->count + 1);
417  strcat(newFormula, work);
418  break;
419  }
420  case DERIVED_SUB: {
421  // the event we depend on has no formula, create a formula for our new event to subtract the depends_on native event values
422 
423  // build a formula for this subtract event
424  sprintf(work, "N%d|N%d|-|", results->count, results->count + 1);
425  strcat(newFormula, work);
426  break;
427  }
428  case NOT_DERIVED: {
429  // 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
430 
431  // build a formula for this subtract event
432  sprintf(work, "N%d|", results->count);
433  strcat(newFormula, work);
434  break;
435  }
436  default: {
437  // the event we depend on has unsupported derived type, put out some debug and give up
438  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);
439  return;
440  }
441  }
442 
443  // if this was the second event, append to the formula an operation to add or subtract the results of the two events
444  if (second_event) {
445  if (addition != 0) {
446  strcat(newFormula, "+|");
447  } else {
448  strcat(newFormula, "-|");
449  }
450  // also change the new derived events type to show it has a formula now
451  results->derived_int = DERIVED_POSTFIX;
452  }
453 
454  // we need to free the existing space (created by malloc and we need to create a new one)
455  papi_free (results->postfix);
456  results->postfix = papi_strdup(newFormula);
457  INTDBG("EXIT: newFormula: %s\n", newFormula);
458  return;
459 }
460 
461 // merge the 'insertion' formula into the 'original' formula replacing the
462 // 'replaces' token in the 'original' formula.
463 static void
464 ops_string_merge(char **original, char *insertion, int replaces, int start_index) {
465  INTDBG("ENTER: original: %p, *original: %s, insertion: %s, replaces: %d, start_index: %d\n", original, *original, insertion, replaces, start_index);
466 
467  int orig_len=0;
468  int ins_len=0;
469  char *subtoken;
470  char *workBuf;
471  char *workPtr;
472  char *tok_save_ptr=NULL;
473  char *newOriginal;
474  char *newInsertion;
475  char *newFormula;
476  int insert_events;
477 
478  if (*original != NULL) {
479  orig_len = strlen(*original);
480  }
481  if (insertion != NULL) {
482  ins_len = strlen(insertion);
483  }
484  newFormula = papi_calloc (orig_len + ins_len + 40, 1);
485 
486  // if insertion formula is not provided, then the original formula remains basically unchanged.
487  if (insertion == NULL) {
488  // if the original formula has a leading '|' then get rid of it
489  workPtr = *original;
490  if (workPtr[0] == '|') {
491  strcpy(newFormula, &workPtr[1]);
492  } else {
493  strcpy(newFormula, workPtr);
494  }
495  // formula fields are always malloced space so free the previous one
496  papi_free (*original);
497  *original = newFormula;
498  INTDBG("EXIT: newFormula: %s\n", *original);
499  return;
500  }
501 
502  // renumber the token numbers in the insertion formula
503  // also count how many native events are used in this formula
504  insert_events = 0;
505  newInsertion = papi_calloc(ins_len+20, 1);
506  workBuf = papi_calloc(ins_len+10, 1);
507  workPtr = papi_strdup(insertion);
508  subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
509  while ( subtoken != NULL) {
510 // INTDBG("subtoken: %s, newInsertion: %s\n", subtoken, newInsertion);
511  if ((subtoken[0] == 'N') && (isdigit(subtoken[1]))) {
512  insert_events++;
513  int val = atoi(&subtoken[1]);
514  val += start_index;
515  subtoken[1] = '\0';
516  sprintf (workBuf, "N%d", val);
517  } else {
518  strcpy(workBuf, subtoken);
519  }
520  strcat (newInsertion, workBuf);
521  strcat (newInsertion, "|");
522  subtoken = strtok_r(NULL, "|", &tok_save_ptr);
523  }
524  papi_free (workBuf);
525  papi_free (workPtr);
526  INTDBG("newInsertion: %s\n", newInsertion);
527 
528  // if original formula is not provided, then the updated insertion formula becomes the new formula
529  // but we still had to renumber the native event tokens in case another native event was put into the list first
530  if (*original == NULL) {
531  *original = papi_strdup(newInsertion);
532  INTDBG("EXIT: newFormula: %s\n", newInsertion);
533  papi_free (newInsertion);
534  papi_free (newFormula);
535  return;
536  }
537 
538  // if token to replace not valid, return null (do we also need to check an upper bound ???)
539  if ((replaces < 0)) {
540  papi_free (newInsertion);
541  papi_free (newFormula);
542  INTDBG("EXIT: Invalid value for token in original formula to be replaced\n");
543  return;
544  }
545 
546  // renumber the token numbers in the original formula
547  // tokens with an index greater than the replaces token need to be incremented by number of events in insertion formula-1
548  newOriginal = papi_calloc (orig_len+20, 1);
549  workBuf = papi_calloc(orig_len+10, 1);
550  workPtr = papi_strdup(*original);
551 
552  subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
553  while ( subtoken != NULL) {
554 // INTDBG("subtoken: %s, newOriginal: %s\n", subtoken, newOriginal);
555  // prime the work area with the next token, then see if we need to change it
556  strcpy(workBuf, subtoken);
557  if ((subtoken[0] == 'N') && (isdigit(subtoken[1]))) {
558  int val = atoi(&subtoken[1]);
559  if (val > replaces) {
560  val += insert_events-1;
561  subtoken[1] = '\0';
562  sprintf (workBuf, "N%d", val);
563  }
564  }
565  // put the work buffer into the new original formula
566  strcat (newOriginal, workBuf);
567  strcat (newOriginal, "|");
568  subtoken = strtok_r(NULL, "|", &tok_save_ptr);
569  }
570  papi_free (workBuf);
571  papi_free (workPtr);
572  INTDBG("newOriginal: %s\n", newOriginal);
573 
574  // replace the specified "replace" tokens in the new original formula with the new insertion formula
575  newFormula[0] = '\0';
576  workPtr = newOriginal;
577  subtoken = strtok_r(workPtr, "|", &tok_save_ptr);
578  while ( subtoken != NULL) {
579 // INTDBG("subtoken: %s, newFormula: %s\n", subtoken, newFormula);
580  // if this is the token we want to replace with the insertion string, do it now
581  if ((subtoken[0] == 'N') && (isdigit(subtoken[1])) && (replaces == atoi(&subtoken[1]))) {
582  // copy updated insertion string into the original string (replacing this token)
583  strcat(newFormula, newInsertion);
584  } else {
585  // copy this part of the original formula into the new formula
586  strcat(newFormula, subtoken);
587  strcat(newFormula, "|");
588  }
589  subtoken = strtok_r(NULL, "|", &tok_save_ptr);
590  }
591  papi_free (newInsertion);
592  papi_free (workPtr);
593 
594  // formula fields are always malloced space so free the previous one
595  papi_free (*original);
596  *original = newFormula;
597  INTDBG("EXIT: newFormula: %s\n", newFormula);
598  return;
599 }
600 
601 //
602 // 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.
603 // 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
604 // derived value and use it in the correct context of the new derived event being created. Depending on the inputs, the operations strings (formulas)
605 // 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.
606 // 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
607 // identify indexes into the native event array used to compute the new derived events final value.
608 //
609 // Arguments:
610 // target: event we are looking for
611 // derived_type: type of derived event being created (add, subtract, postfix)
612 // results: where to build the new preset event being defined.
613 // 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).
614 // search_size: number of entries in the search table.
615 //
616 static int
617 check_derived_events(char *target, int derived_type, hwi_presets_t* results, hwi_presets_t * search, int search_size, int token_index)
618 {
619  INTDBG("ENTER: target: %p (%s), results: %p, search: %p, search_size: %d, token_index: %d\n", target, target, results, search, search_size, token_index);
620  unsigned int i;
621  int j;
622  int k;
623  int found = 0;
624 
625  for (j=0; j < search_size; j++) {
626  // INTDBG("search[%d].symbol: %s, looking for: %s\n", j, search[j].symbol, target);
627  if (search[j].symbol == NULL) {
628  INTDBG("EXIT: returned: 0\n");
629  return 0;
630  }
631 
632  // if not the event we depend on, just look at next
633  if ( strcasecmp( target, search[j].symbol) != 0 ) {
634  continue;
635  }
636 
637  INTDBG("Found a match\n");
638 
639  // derived formulas need to be adjusted based on what kind of derived event we are processing
640  // the derived type passed to this function is the type of the new event being defined (not the events it is based on)
641  // when we get here the formula must be in reverse polish notation (RPN) format
642  switch (derived_type) {
643  case DERIVED_POSTFIX: {
644  // go create a formula to merge the second formula into a spot identified by one of the tokens in
645  // the first formula.
646  ops_string_merge(&(results->postfix), search[j].postfix, token_index, results->count);
647  break;
648  }
649  case DERIVED_ADD: {
650  // the new derived event adds two things together, go handle this target events role in the add
651  ops_string_append(results, &search[j], 1);
652  break;
653  }
654  case DERIVED_SUB: {
655  // go create a formula to subtract the value generated by the second formula from the value generated by the first formula.
656  ops_string_append(results, &search[j], 0);
657  break;
658  }
659  default: {
660  INTDBG("Derived type: %d, not currently handled\n", derived_type);
661  break;
662  }
663  }
664 
665  // copy event name and code used by the derived event into the results table (place where new derived event is getting created)
666  for ( k = 0; k < (int)search[j].count; k++ ) {
667 // INTDBG("search[%d]: %p, name[%d]: %s, code[%d]: %#x\n", j, &search[j], k, search[j].name[k], k, search[j].code[k]);
668  // if this event is already in the list, just update the formula so that references to this event point to the existing one
669  for (i=0 ; i < results->count ; i++) {
670  if (results->code[i] == search[j].code[k]) {
671  INTDBG("event: %s, code: %#x, already in results at index: %d\n", search[j].name[k], search[j].code[k], i);
672  // replace all tokens in the formula that refer to index "results->count + found" with a token that refers to index "i".
673  // the index "results->count + found" identifies the index used in the formula for the event we just determined is a duplicate
674  update_ops_string(&(results->postfix), results->count + found, i);
675  found++;
676  break;
677  }
678  }
679 
680  // if we did not find a match, copy native event info into results array
681  if (found == 0) {
682  // not a duplicate, go ahead and copy into results and bump number of native events in results
683  if (search[j].name[k]) {
684  results->name[results->count] = papi_strdup(search[j].name[k]);
685  } else {
686  results->name[results->count] = papi_strdup(target);
687  }
688  results->code[results->count] = search[j].code[k];
689  INTDBG("results: %p, name[%d]: %s, code[%d]: %#x\n", results, results->count, results->name[results->count], results->count, results->code[results->count]);
690 
691  results->count++;
692  }
693  }
694 
695  INTDBG("EXIT: returned: 1\n");
696  return 1;
697  }
698 
699  INTDBG("EXIT: returned: 0\n");
700  return 0;
701 }
702 
703 static int
704 check_native_events(char *target, hwi_presets_t* results)
705 {
706  INTDBG("ENTER: target: %p (%s), results: %p\n", target, target, results);
707  int ret;
708 
709  // find this native events code
710  if ( ( ret = _papi_hwi_native_name_to_code( target, (int *)(&results->code[results->count])) ) != PAPI_OK ) {
711  INTDBG("EXIT: returned: 0, call to convert name to event code failed with ret: %d\n", ret);
712  return 0;
713  }
714 
715  // if the code returned was 0, return to show it is not a valid native event
716  if ( results->code[results->count] == 0 ) {
717  INTDBG( "EXIT: returned: 0, event code not found\n");
718  return 0;
719  }
720 
721  // if this native event is not for component 0, return to show it can not be used in derived events
722  // 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
723  if ( _papi_hwi_component_index(results->code[results->count]) != 0 ) {
724  INTDBG( "EXIT: returned: 0, new event not associated with component 0 (current limitation with derived events)\n");
725  return 0;
726  }
727 
728  // found = 1;
729  INTDBG("\tFound a native event %s\n", target);
730  results->name[results->count++] = papi_strdup(target);
731 
732  INTDBG( "EXIT: returned: 1\n");
733  return 1;
734 }
735 
736 // see if the event_name string passed in matches a known event name
737 // if it does these calls also updates information in event definition tables to remember the event
738 static int
739 is_event(char *event_name, int derived_type, hwi_presets_t* results, int token_index) {
740  INTDBG("ENTER: event_name: %p (%s), derived_type: %d, results: %p, token_index: %d\n", event_name, event_name, derived_type, results, token_index);
741 
742  /* check if its a preset event */
743  if ( check_derived_events(event_name, derived_type, results, &_papi_hwi_presets[0], PAPI_MAX_PRESET_EVENTS, token_index) ) {
744  INTDBG("EXIT: found preset event\n");
745  return 1;
746  }
747 
748  /* check if its a user defined event */
749  if ( check_derived_events(event_name, derived_type, results, user_defined_events, user_defined_events_count, token_index) ) {
750  INTDBG("EXIT: found user event\n");
751  return 1;
752  }
753 
754  /* check if its a native event */
755  if ( check_native_events(event_name, results) ) {
756  INTDBG("EXIT: found native event\n");
757  return 1;
758  }
759 
760  INTDBG("EXIT: event not found\n");
761  return 0;
762 }
763 
764 /* Static version of the events file. */
765 #if defined(STATIC_PAPI_EVENTS_TABLE)
766 #include "papi_events_table.h"
767 #else
768 static char *papi_events_table = NULL;
769 #endif
770 
771 int _papi_load_preset_table(char *pmu_str, int pmu_type, int cidx) {
772  SUBDBG("ENTER: pmu_str: %s, pmu_type: %d, cidx: %d\n", pmu_str, pmu_type, cidx);
773 
774  int retval;
775 
776  // go load papi preset events (last argument tells function if we are loading presets or user events)
777  retval = papi_load_derived_events(pmu_str, pmu_type, cidx, 1);
778  if (retval != PAPI_OK) {
779  SUBDBG("EXIT: retval: %d\n", retval);
780  return retval;
781  }
782 
783  // go load the user defined event definitions if any are defined
784  retval = papi_load_derived_events(pmu_str, pmu_type, cidx, 0);
785 
786  SUBDBG("EXIT: retval: %d\n", retval);
787  return retval;
788 }
789 
790 // global variables
791 #define STACK_MAX 400 // size of stack
792 static char *stack[STACK_MAX]; // stack
793 static char *sptr; // stack pointer
794 static int top = -1; // stack length
795 
796 // isitsym: This function returns true if the character is a symbol
797 static
798 int isitsym( char symbol ) {
799  switch( symbol ) {
800  case '(':
801  case ')':
802  case '+':
803  case '-':
804  case '*':
805  case '/':
806  case '%':
807  return 1;
808  default :
809  return 0;
810  } // end switch symbol
811 } // end isitsym
812 
813 // priority: This function returns the priority of the operator
814 static
815 int priority( char symbol ) {
816  switch( symbol ) {
817  case '(':
818  return 0;
819  case '+':
820  case '-':
821  return 1;
822  case '*':
823  case '/':
824  case '%':
825  return 2;
826  default :
827  return 0;
828  } // end switch symbol
829 } // end priority
830 
831 static
832 int push( char *symbol ) {
833  if( top >= (STACK_MAX - 1) ) {
834  INTDBG("EXIT: Stack Overflow converting Algebraic Expression:%d\n", top );
835  return -1; //***TODO: Figure out how to exit gracefully
836  } // end if top>MAX
837  stack[++top] = papi_malloc(sizeof(char));
838  stack[top] = symbol;
839  return 0;
840 } // end push
841 
842 // pop from stack
843 static
844 char *pop() {
845  if( top < 0 ) {
846  INTDBG("EXIT: Stack Underflow converting Algebraic Expression:%d\n", top );
847  return NULL; //***TODO: Figure out how to exit gracefully
848  } // end if empty
849  sptr = stack[top--];
850  return( sptr );
851 } // end pop
852 
853 // free pointers from stack
854 void
856  int i;
857  for( i = 0; i < STACK_MAX; i++ ) {
858  if ( stack[i] != NULL )
859  papi_free(stack[i]);
860  else
861  break;
862  } // end for stack max
863 } // end freestack
864 
865 // gettoken: get next token from the infix string
866 static int
867 gettoken( char *infix, char *token, unsigned int *index ) {
868  INTDBG("ENTER: infix: %s, token: %s, index: %d\n", infix, token, *index);
869  int i = 0;
870  int j = *index;
871  if ( tolower(infix[j]) >= 'a' && tolower(infix[j] <= 'z') ) {
872  token[i] = infix[j];
873  while ( !isitsym(infix[++j]) && ( infix[j] != '\0' ) )
874  token[++i] = infix[j];
875  *index = j;
876  INTDBG("EXIT: infix: %s, token: %s, index: %d\n", infix, token, *index);
877  return 1;
878  } // end if starts with character
879  if ( infix[j] == '"' ) {
880  while ( !isitsym(infix[++j]) && ( infix[j] != '"' ) )
881  token[i++] = infix[j];
882  *index = j+1;
883  INTDBG("EXIT: infix: %s, token: %s, index: %d\n", infix, token, *index);
884  return 1;
885  } // end if starts with double quote
886  if ( tolower(infix[j]) >= '0' && tolower(infix[j] <= '9') ) {
887  token[i] = infix[j];
888  while ( !isitsym(infix[++j]) && ( tolower(infix[j]) >= '0' &&
889  tolower(infix[j] <= '9') ) && ( infix[j] != '\0' ) )
890  token[++i] = infix[j];
891  *index = j;
892  INTDBG("EXIT: infix: %s, token: %s, index: %d\n", infix, token, *index);
893  return 1;
894  } // end if starts with number
895  if ( isitsym(infix[j]) ) {
896  token[i] = infix[j];
897  *index = ++j;
898  INTDBG("EXIT: infix: %s, token: %s, index: %d\n", infix, token, *index);
899  return 1;
900  } // end if it is a special character
901  INTDBG("EXIT: infix: %s, token: %s, index: %d\n", infix, token, *index);
902  return 0; // error
903 } // end gettoken
904 
905 /* infix_to_postfix:
906  routine that will be called with parameter:
907  char *in characters of infix notation (algebraic formula)
908  returns: char * pointer to string of returned postfix */
909 static char *
910 infix_to_postfix( char *in ) {
911  INTDBG("ENTER: in: %s, size: %zu\n", in, strlen(in));
912  static char postfix[PAPI_HUGE_STR_LEN]; // output
913  unsigned int *index = papi_malloc(sizeof(int));
914  char *ptr = &in[0];
915 
916  *index = 0;
917  memset(&postfix,0,PAPI_HUGE_STR_LEN);
918  memset(&stack,0,STACK_MAX);
919  top = -1; // initialize stack
920 
921  while( *index < strlen( in ) ) {
922  INTDBG("INTDBG: in: %s, length: %zu, index: %d\n", in, strlen( in ), *index);
923  char next[PAPI_MIN_STR_LEN];
924  char *token = papi_malloc(PAPI_MIN_STR_LEN);
925  memset(next,0,PAPI_MIN_STR_LEN);
926  memset(token,0,PAPI_MIN_STR_LEN);
927  gettoken(ptr, token, index);
928  INTDBG("INTDBG: token: %s|\n", token);
929  switch( token[0] ) {
930  case '(':
931  push(&token[0]);
932  break;
933  case ')':
934  do {
935  char *tmpstr;
936  tmpstr = pop();
937  if ( strlen(tmpstr) < PAPI_MIN_STR_LEN )
938  strcpy(next, tmpstr);
939  if ( next[0] != '(' ) {
940  if ( (strlen(postfix) + strlen(next)) < (PAPI_HUGE_STR_LEN - 1) ) {
941  strcat(postfix, next);
942  strcat(postfix, "|");
943  } // end if enough space
944  } // end if not (
945  else
946  break;
947  } while( 1 ); // TODO: Might be a problem
948  break;
949  case '+':
950  case '-':
951  case '*':
952  case '/':
953  case '%':
954  case '^':
955  if ( top >= 0 ) {
956  while( priority(stack[top][0]) >= priority(token[0]) ) {
957  char *tmpstr;
958  tmpstr = pop();
959  if ( (strlen(postfix) + strlen(tmpstr)) < (PAPI_HUGE_STR_LEN - 1) ) {
960  strcat(postfix, tmpstr);
961  strcat(postfix, "|");
962  } // end if enough space
963  if ( top < 0 )
964  break;
965  } // end while
966  } // if something on stack
967  push(&token[0]);
968  break;
969  default: // if an operand comes
970  if ( (strlen(postfix) + strlen(token)) < (PAPI_HUGE_STR_LEN - 1) ) {
971  strcat(postfix, token);
972  strcat(postfix, "|");
973 
974 
975  } // end if enough space
976  break;
977  } // end switch symbol
978  } // end while
979 
980  papi_free(index);
981 
982  while( top >= 0 ) {
983  char *tmpstr;
984  tmpstr = pop();
985  if ( (strlen(postfix) + strlen(tmpstr)) < (PAPI_HUGE_STR_LEN - 1) ) {
986  strcat(postfix, tmpstr);
987  strcat(postfix, "|");
988  } // end if enough space
989  } // end while still stuff in the stack
990 
991  INTDBG("EXIT: postfix: %s, size: %zu\n", postfix, strlen(postfix));
992  freestack();
993  return (postfix);
994 } // end infix_to_postfix
995 
996 /*
997  * This function will load event definitions from either a file or an in memory table. It is used to load both preset events
998  * which are defined by the PAPI development team and delivered with the product and user defined events which can be defined
999  * by papi users and provided to papi to be processed at library initialization. Both the preset events and user defined events
1000  * support the same event definition syntax.
1001  *
1002  * Event definition file syntax:
1003  * see PAPI_derived_event_files(1) man page.
1004  *
1005  * Blank lines are ignored
1006  * Lines that begin with '#' are comments.
1007  * Lines that begin with 'CPU' identify a pmu name and have the following effect.
1008  * If this pmu name does not match the pmu_str passed in, it is ignored and we get the next input line.
1009  * If this pmu name matches the pmu_str passed in, we set a 'process events' flag.
1010  * Multiple consecutive 'CPU' lines may be provided and if any of them match the pmu_str passed in, we set a 'process events' flag.
1011  * When a 'CPU' line is found following event definition lines, it turns off the 'process events' flag and then does the above checks.
1012  * Lines that begin with 'PRESET' or 'EVENT' specify an event definition and are processed as follows.
1013  * If the 'process events' flag is not set, the line is ignored and we get the next input line.
1014  * If the 'process events' flag is set, the event is processed and the event information is put into the next slot in the results array.
1015  *
1016  * There are three possible sources of input for preset event definitions. The code will first look for the environment variable
1017  * "PAPI_CSV_EVENT_FILE". If found its value will be used as the pathname of where to get the preset information. If not found,
1018  * the code will look for a built in table containing preset events. If the built in table was not created during the build of
1019  * PAPI then the code will build a pathname of the form "PAPI_DATADIR/PAPI_EVENT_FILE". Each of these are build variables, the
1020  * PAPI_DATADIR variable can be given a value during the configure of PAPI at build time, and the PAPI_EVENT_FILE variable has a
1021  * hard coded value of "papi_events.csv".
1022  *
1023  * There is only one way to define user events. The code will look for an environment variable "PAPI_USER_EVENTS_FILE". If found
1024  * its value will be used as the pathname of a file which contains user event definitions. The events defined in this file will be
1025  * added to the ones known by PAPI when the call to PAPI_library_init is done.
1026  *
1027  * TODO:
1028  * Look into restoring the ability to specify a user defined event file with a call to PAPI_set_opt(PAPI_USER_EVENTS_FILE).
1029  * This needs to figure out how to pass a pmu name (could use default pmu from component 0) to this function.
1030  *
1031  * Currently code elsewhere in PAPI limits the events which preset and user events can depend on to those events which are known to component 0. This possibly could
1032  * be relaxed to allow events from different components. But since all the events used by any derived event must be added to the same eventset, it will always be a
1033  * requirement that all events used by a given derived event must be from the same component.
1034  *
1035  */
1036 
1037 
1038 static int
1039 papi_load_derived_events (char *pmu_str, int pmu_type, int cidx, int preset_flag) {
1040  SUBDBG( "ENTER: pmu_str: %s, pmu_type: %d, cidx: %d, preset_flag: %d\n", pmu_str, pmu_type, cidx, preset_flag);
1041 
1042  char pmu_name[PAPI_MIN_STR_LEN];
1043  char line[LINE_MAX];
1044  char name[PATH_MAX] = "builtin papi_events_table";
1045  char *event_file_path=NULL;
1046  char *event_table_ptr=NULL;
1047  int event_type_bits = 0;
1048  char *tmpn;
1049  char *tok_save_ptr=NULL;
1050  FILE *event_file = NULL;
1051  hwi_presets_t *results=NULL;
1052  int result_size = 0;
1053  int *event_count = NULL;
1054  int invalid_event;
1055  int line_no = 0; /* count of lines read from event definition input */
1056  int derived = 0;
1057  int res_idx = 0; /* index into results array for where to store next event */
1058  int preset = 0;
1059  int get_events = 0; /* only process derived events after CPU type they apply to is identified */
1060  int found_events = 0; /* flag to track if event definitions (PRESETS) are found since last CPU declaration */
1061 #ifdef PAPI_DATADIR
1062  char path[PATH_MAX];
1063 #endif
1064 
1065 
1066  if (preset_flag) {
1067  /* try the environment variable first */
1068  if ((tmpn = getenv("PAPI_CSV_EVENT_FILE")) && (strlen(tmpn) > 0)) {
1069  event_file_path = tmpn;
1070  }
1071  /* if no valid environment variable, look for built-in table */
1072  else if (papi_events_table) {
1073  event_table_ptr = papi_events_table;
1074  }
1075  /* if no env var and no built-in, search for default file */
1076  else {
1077 #ifdef PAPI_DATADIR
1078  sprintf( path, "%s/%s", PAPI_DATADIR, PAPI_EVENT_FILE );
1079  event_file_path = path;
1080 #else
1081  event_file_path = PAPI_EVENT_FILE;
1082 #endif
1083  }
1084  event_type_bits = PAPI_PRESET_MASK;
1085  results = &_papi_hwi_presets[0];
1086  result_size = PAPI_MAX_PRESET_EVENTS;
1087  event_count = &_papi_hwd[cidx]->cmp_info.num_preset_events;
1088  } else {
1089  if ((event_file_path = getenv( "PAPI_USER_EVENTS_FILE" )) == NULL ) {
1090  SUBDBG("EXIT: User event definition file not provided.\n");
1091  return PAPI_OK;
1092  }
1093 
1094  event_type_bits = PAPI_UE_MASK;
1095  results = &user_defined_events[0];
1096  result_size = PAPI_MAX_USER_EVENTS;
1097  event_count = &user_defined_events_count;
1098  }
1099 
1100  // if we have an event file pathname, open it and read event definitions from the file
1101  if (event_file_path != NULL) {
1102  if ((event_file = open_event_table(event_file_path)) == NULL) {
1103  // if file open fails, return an error
1104  SUBDBG("EXIT: Event file open failed.\n");
1105  return PAPI_ESYS;
1106  }
1107  strncpy(name, event_file_path, sizeof(name)-1);
1108  name[sizeof(name)-1] = '\0';
1109  } else if (event_table_ptr == NULL) {
1110  // if we do not have a path name or table pointer, return an error
1111  SUBDBG("EXIT: Both event_file_path and event_table_ptr are NULL.\n");
1112  return PAPI_ESYS;
1113  }
1114 
1115  /* copy the pmu identifier, stripping commas if found */
1116  tmpn = pmu_name;
1117  while (*pmu_str) {
1118  if (*pmu_str != ',')
1119  *tmpn++ = *pmu_str;
1120  pmu_str++;
1121  }
1122  *tmpn = '\0';
1123 
1124  /* at this point we have either a valid file pointer or built-in table pointer */
1125  while (get_event_line(line, event_file, &event_table_ptr)) {
1126  char *t;
1127  int i;
1128 
1129  // increment number of lines we have read
1130  line_no++;
1131 
1132  t = trim_string(strtok_r(line, ",", &tok_save_ptr));
1133 
1134  /* Skip blank lines */
1135  if ((t == NULL) || (strlen(t) == 0))
1136  continue;
1137 
1138  /* Skip comments */
1139  if (t[0] == '#') {
1140  continue;
1141  }
1142 
1143  if (strcasecmp(t, "CPU") == 0) {
1144  if (get_events != 0 && found_events != 0) {
1145  SUBDBG( "Ending event scanning at line %d of %s.\n", line_no, name);
1146  get_events = 0;
1147  found_events = 0;
1148  }
1149 
1150  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1151  if ((t == NULL) || (strlen(t) == 0)) {
1152  PAPIERROR("Expected name after CPU token at line %d of %s -- ignoring", line_no, name);
1153  continue;
1154  }
1155 
1156  if (strcasecmp(t, pmu_name) == 0) {
1157  int type;
1158 
1159  SUBDBG( "Process events for PMU %s found at line %d of %s.\n", t, line_no, name);
1160 
1161  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1162  if ((t == NULL) || (strlen(t) == 0)) {
1163  SUBDBG("No additional qualifier found, matching on string.\n");
1164  get_events = 1;
1165  } else if ((sscanf(t, "%d", &type) == 1) && (type == pmu_type)) {
1166  SUBDBG( "Found CPU %s type %d at line %d of %s.\n", pmu_name, type, line_no, name);
1167  get_events = 1;
1168  } else {
1169  SUBDBG( "Additional qualifier match failed %d vs %d.\n", pmu_type, type);
1170  }
1171  }
1172  continue;
1173  }
1174 
1175  if ((strcasecmp(t, "PRESET") == 0) || (strcasecmp(t, "EVENT") == 0)) {
1176 
1177  if (get_events == 0)
1178  continue;
1179 
1180  found_events = 1;
1181  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1182 
1183  if ((t == NULL) || (strlen(t) == 0)) {
1184  PAPIERROR("Expected name after PRESET token at line %d of %s -- ignoring", line_no, name);
1185  continue;
1186  }
1187 
1188  SUBDBG( "Examining event %s\n", t);
1189 
1190  // see if this event already exists in the results array, if not already known it sets up event in unused entry
1191  if ((res_idx = find_event_index (results, result_size, t)) < 0) {
1192  PAPIERROR("No room left for event %s -- ignoring", t);
1193  continue;
1194  }
1195 
1196  // add the proper event bits (preset or user defined bits)
1197  preset = res_idx | event_type_bits;
1198 
1199  SUBDBG( "Use event code: %#x for %s\n", preset, t);
1200 
1201  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1202  if ((t == NULL) || (strlen(t) == 0)) {
1203  // got an error, make this entry unused
1204  papi_free (results[res_idx].symbol);
1205  results[res_idx].symbol = NULL;
1206  PAPIERROR("Expected derived type after PRESET token at line %d of %s -- ignoring", line_no, name);
1207  continue;
1208  }
1209 
1210  if (_papi_hwi_derived_type(t, &derived) != PAPI_OK) {
1211  // got an error, make this entry unused
1212  papi_free (results[res_idx].symbol);
1213  results[res_idx].symbol = NULL;
1214  PAPIERROR("Invalid derived name %s after PRESET token at line %d of %s -- ignoring", t, line_no, name);
1215  continue;
1216  }
1217 
1218  /****************************************/
1219  /* Have an event, let's start assigning */
1220  /****************************************/
1221 
1222  SUBDBG( "Adding event: %s, code: %#x, derived: %d results[%d]: %p.\n", t, preset, derived, res_idx, &results[res_idx]);
1223 
1224  /* results[res_idx].event_code = preset; */
1225  results[res_idx].derived_int = derived;
1226 
1227  /* Derived support starts here */
1228  /* Special handling for postfix and infix */
1229  if ((derived == DERIVED_POSTFIX) || (derived == DERIVED_INFIX)) {
1230  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1231  if ((t == NULL) || (strlen(t) == 0)) {
1232  // got an error, make this entry unused
1233  papi_free (results[res_idx].symbol);
1234  results[res_idx].symbol = NULL;
1235  PAPIERROR("Expected Operation string after derived type DERIVED_POSTFIX or DERIVED_INFIX at line %d of %s -- ignoring", line_no, name);
1236  continue;
1237  }
1238 
1239  // if it is an algebraic formula, we need to convert it to postfix
1240  if (derived == DERIVED_INFIX) {
1241  SUBDBG( "Converting InFix operations %s\n", t);
1242  t = infix_to_postfix( t );
1243  results[res_idx].derived_int = DERIVED_POSTFIX;
1244  }
1245 
1246  SUBDBG( "Saving PostFix operations %s\n", t);
1247  results[res_idx].postfix = papi_strdup(t);
1248  }
1249 
1250  /* All derived terms collected here */
1251  i = 0;
1252  invalid_event = 0;
1253  results[res_idx].count = 0;
1254  do {
1255  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1256  if ((t == NULL) || (strlen(t) == 0))
1257  break;
1258  if (strcasecmp(t, "NOTE") == 0)
1259  break;
1260  if (strcasecmp(t, "LDESC") == 0)
1261  break;
1262  if (strcasecmp(t, "SDESC") == 0)
1263  break;
1264 
1265  SUBDBG( "Adding term (%d) %s to derived event %#x, current native event count: %d.\n", i, t, preset, results[res_idx].count);
1266 
1267  // show that we do not have an event code yet (the component may create one and update this info)
1268  // this also clears any values left over from a previous call
1270 
1271  // make sure that this term in the derived event is a valid event name
1272  // this call replaces preset and user event names with the equivalent native events in our results table
1273  // it also updates formulas for derived events so that they refer to the correct native event index
1274  if (is_event(t, results[res_idx].derived_int, &results[res_idx], i) == 0) {
1275  invalid_event = 1;
1276  PAPIERROR("Error finding event %s, it is used in derived event %s", t, results[res_idx].symbol);
1277  break;
1278  }
1279 
1280  i++;
1281  } while (results[res_idx].count < PAPI_EVENTS_IN_DERIVED_EVENT);
1282 
1283  /* preset code list must be PAPI_NULL terminated */
1284  if (i < PAPI_EVENTS_IN_DERIVED_EVENT) {
1285  results[res_idx].code[results[res_idx].count] = PAPI_NULL;
1286  }
1287 
1288  if (invalid_event) {
1289  // got an error, make this entry unused
1290  papi_free (results[res_idx].symbol);
1291  results[res_idx].symbol = NULL;
1292  continue;
1293  }
1294 
1295  /* End of derived support */
1296 
1297  // if we did not find any terms to base this derived event on, report error
1298  if (i == 0) {
1299  // got an error, make this entry unused
1300  papi_free (results[res_idx].symbol);
1301  results[res_idx].symbol = NULL;
1302  PAPIERROR("Expected PFM event after DERIVED token at line %d of %s -- ignoring", line_no, name);
1303  continue;
1304  }
1305 
1306  if (i == PAPI_EVENTS_IN_DERIVED_EVENT) {
1307  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1308  }
1309 
1310  // if something was provided following the list of events to be used by the operation, process it
1311  if ( t!= NULL && strlen(t) > 0 ) {
1312  do {
1313  // save the field name
1314  char *fptr = papi_strdup(t);
1315 
1316  // get the value to be used with this field
1317  t = trim_note(strtok_r(NULL, ",", &tok_save_ptr));
1318  if ( t== NULL || strlen(t) == 0 ) {
1319  papi_free(fptr);
1320  break;
1321  }
1322 
1323  // Handle optional short descriptions, long descriptions and notes
1324  if (strcasecmp(fptr, "SDESC") == 0) {
1325  results[res_idx].short_descr = papi_strdup(t);
1326  }
1327  if (strcasecmp(fptr, "LDESC") == 0) {
1328  results[res_idx].long_descr = papi_strdup(t);
1329  }
1330  if (strcasecmp(fptr, "NOTE") == 0) {
1331  results[res_idx].note = papi_strdup(t);
1332  }
1333 
1334  SUBDBG( "Found %s (%s) on line %d\n", fptr, t, line_no);
1335  papi_free (fptr);
1336 
1337  // look for another field name
1338  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1339  if ( t== NULL || strlen(t) == 0 ) {
1340  break;
1341  }
1342  } while (t != NULL);
1343  }
1344  (*event_count)++;
1345  continue;
1346  }
1347 
1348  PAPIERROR("Unrecognized token %s at line %d of %s -- ignoring", t, line_no, name);
1349  }
1350 
1351  if (event_file) {
1352  fclose(event_file);
1353  }
1354 
1355  SUBDBG("EXIT: Done processing derived event file.\n");
1356  return PAPI_OK;
1357 }
1358 
1359 
1360 
1361 
1362 /* The following code is proof of principle for reading preset events from an
1363  xml file. It has been tested and works for pentium3. It relys on the expat
1364  library and is invoked by adding
1365  XMLFLAG = -DXML
1366  to the Makefile. It is presently hardcoded to look for "./papi_events.xml"
1367 */
1368 #ifdef XML
1369 
1370 #define BUFFSIZE 8192
1371 #define SPARSE_BEGIN 0
1372 #define SPARSE_EVENT_SEARCH 1
1373 #define SPARSE_EVENT 2
1374 #define SPARSE_DESC 3
1375 #define ARCH_SEARCH 4
1376 #define DENSE_EVENT_SEARCH 5
1377 #define DENSE_NATIVE_SEARCH 6
1378 #define DENSE_NATIVE_DESC 7
1379 #define FINISHED 8
1380 
1381 char buffer[BUFFSIZE], *xml_arch;
1382 int location = SPARSE_BEGIN, sparse_index = 0, native_index, error = 0;
1383 
1384 /* The function below, _xml_start(), is a hook into expat's XML
1385  * parser. _xml_start() defines how the parser handles the
1386  * opening tags in PAPI's XML file. This function can be understood
1387  * more easily if you follow along with its logic while looking at
1388  * papi_events.xml. The location variable is a global telling us
1389  * where we are in the XML file. Have we found our architecture's
1390  * events yet? Are we looking at an event definition?...etc.
1391  */
1392 static void
1393 _xml_start( void *data, const char *el, const char **attr )
1394 {
1395  int native_encoding;
1396 
1397  if ( location == SPARSE_BEGIN && !strcmp( "papistdevents", el ) ) {
1398  location = SPARSE_EVENT_SEARCH;
1399  } else if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
1400  _papi_hwi_presets[sparse_index].info.symbol = papi_strdup( attr[1] );
1401 // strcpy(_papi_hwi_presets.info[sparse_index].symbol, attr[1]);
1402  location = SPARSE_EVENT;
1403  } else if ( location == SPARSE_EVENT && !strcmp( "desc", el ) ) {
1404  location = SPARSE_DESC;
1405  } else if ( location == ARCH_SEARCH && !strcmp( "availevents", el ) &&
1406  !strcmp( xml_arch, attr[1] ) ) {
1407  location = DENSE_EVENT_SEARCH;
1408  } else if ( location == DENSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
1409  if ( !strcmp( "PAPI_NULL", attr[1] ) ) {
1410  location = FINISHED;
1411  return;
1412  } else if ( PAPI_event_name_to_code( ( char * ) attr[1], &sparse_index )
1413  != PAPI_OK ) {
1414  PAPIERROR( "Improper Preset name given in XML file for %s.",
1415  attr[1] );
1416  error = 1;
1417  }
1418  sparse_index &= PAPI_PRESET_AND_MASK;
1419 
1420  /* allocate and initialize data space for this event */
1421  papi_valid_free( _papi_hwi_presets[sparse_index].data );
1422  _papi_hwi_presets[sparse_index].data =
1423  papi_malloc( sizeof ( hwi_preset_data_t ) );
1424  native_index = 0;
1425  _papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
1426  _papi_hwi_presets[sparse_index].data->operation[0] = '\0';
1427 
1428 
1429  if ( attr[2] ) { /* derived event */
1430  _papi_hwi_presets[sparse_index].data->derived =
1431  _papi_hwi_derived_type( ( char * ) attr[3] );
1432  /* where does DERIVED POSTSCRIPT get encoded?? */
1433  if ( _papi_hwi_presets[sparse_index].data->derived == -1 ) {
1434  PAPIERROR( "No derived type match for %s in Preset XML file.",
1435  attr[3] );
1436  error = 1;
1437  }
1438 
1439  if ( attr[5] ) {
1440  _papi_hwi_presets[sparse_index].count = atoi( attr[5] );
1441  } else {
1442  PAPIERROR( "No count given for %s in Preset XML file.",
1443  attr[1] );
1444  error = 1;
1445  }
1446  } else {
1447  _papi_hwi_presets[sparse_index].data->derived = NOT_DERIVED;
1448  _papi_hwi_presets[sparse_index].count = 1;
1449  }
1450  location = DENSE_NATIVE_SEARCH;
1451  } else if ( location == DENSE_NATIVE_SEARCH && !strcmp( "native", el ) ) {
1452  location = DENSE_NATIVE_DESC;
1453  } else if ( location == DENSE_NATIVE_DESC && !strcmp( "event", el ) ) {
1454  if ( _papi_hwi_native_name_to_code( attr[1], &native_encoding ) !=
1455  PAPI_OK ) {
1456  printf( "Improper Native name given in XML file for %s\n",
1457  attr[1] );
1458  PAPIERROR( "Improper Native name given in XML file for %s",
1459  attr[1] );
1460  error = 1;
1461  }
1462  _papi_hwi_presets[sparse_index].data->native[native_index] =
1463  native_encoding;
1464  native_index++;
1465  _papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
1466  } else if ( location && location != ARCH_SEARCH && location != FINISHED ) {
1467  PAPIERROR( "Poorly-formed Preset XML document." );
1468  error = 1;
1469  }
1470 }
1471 
1472 /* The function below, _xml_end(), is a hook into expat's XML
1473  * parser. _xml_end() defines how the parser handles the
1474  * end tags in PAPI's XML file.
1475  */
1476 static void
1477 _xml_end( void *data, const char *el )
1478 {
1479  int i;
1480 
1481  if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papistdevents", el ) ) {
1482  for ( i = sparse_index; i < PAPI_MAX_PRESET_EVENTS; i++ ) {
1483  _papi_hwi_presets[i].info.symbol = NULL;
1484  _papi_hwi_presets[i].info.long_descr = NULL;
1485  _papi_hwi_presets[i].info.short_descr = NULL;
1486  }
1487  location = ARCH_SEARCH;
1488  } else if ( location == DENSE_NATIVE_DESC && !strcmp( "native", el ) ) {
1489  location = DENSE_EVENT_SEARCH;
1490  } else if ( location == DENSE_EVENT_SEARCH && !strcmp( "availevents", el ) ) {
1491  location = FINISHED;
1492  }
1493 }
1494 
1495 /* The function below, _xml_content(), is a hook into expat's XML
1496  * parser. _xml_content() defines how the parser handles the
1497  * text between tags in PAPI's XML file. The information between
1498  * tags is usally text for event descriptions.
1499  */
1500 static void
1501 _xml_content( void *data, const char *el, const int len )
1502 {
1503  int i;
1504  if ( location == SPARSE_DESC ) {
1505  _papi_hwi_presets[sparse_index].info.long_descr =
1506  papi_malloc( len + 1 );
1507  for ( i = 0; i < len; i++ )
1508  _papi_hwi_presets[sparse_index].info.long_descr[i] = el[i];
1509  _papi_hwi_presets[sparse_index].info.long_descr[len] = '\0';
1510  /* the XML data currently doesn't contain a short description */
1511  _papi_hwi_presets[sparse_index].info.short_descr = NULL;
1512  sparse_index++;
1513  _papi_hwi_presets[sparse_index].data = NULL;
1514  location = SPARSE_EVENT_SEARCH;
1515  }
1516 }
1517 
1518 int
1519 _xml_papi_hwi_setup_all_presets( char *arch, hwi_dev_notes_t * notes )
1520 {
1521  int done = 0;
1522  FILE *fp = fopen( "./papi_events.xml", "r" );
1523  XML_Parser p = XML_ParserCreate( NULL );
1524 
1525  if ( !p ) {
1526  PAPIERROR( "Couldn't allocate memory for XML parser." );
1527  fclose(fp);
1528  return ( PAPI_ESYS );
1529  }
1530  XML_SetElementHandler( p, _xml_start, _xml_end );
1531  XML_SetCharacterDataHandler( p, _xml_content );
1532  if ( fp == NULL ) {
1533  PAPIERROR( "Error opening Preset XML file." );
1534  fclose(fp);
1535  return ( PAPI_ESYS );
1536  }
1537 
1538  xml_arch = arch;
1539 
1540  do {
1541  int len;
1542  void *buffer = XML_GetBuffer( p, BUFFSIZE );
1543 
1544  if ( buffer == NULL ) {
1545  PAPIERROR( "Couldn't allocate memory for XML buffer." );
1546  fclose(fp);
1547  return ( PAPI_ESYS );
1548  }
1549  len = fread( buffer, 1, BUFFSIZE, fp );
1550  if ( ferror( fp ) ) {
1551  PAPIERROR( "XML read error." );
1552  fclose(fp);
1553  return ( PAPI_ESYS );
1554  }
1555  done = feof( fp );
1556  if ( !XML_ParseBuffer( p, len, len == 0 ) ) {
1557  PAPIERROR( "Parse error at line %d:\n%s",
1558  XML_GetCurrentLineNumber( p ),
1559  XML_ErrorString( XML_GetErrorCode( p ) ) );
1560  fclose(fp);
1561  return ( PAPI_ESYS );
1562  }
1563  if ( error ) {
1564  fclose(fp);
1565  return ( PAPI_ESYS );
1566  }
1567  } while ( !done );
1568  XML_ParserFree( p );
1569  fclose( fp );
1570  return ( PAPI_OK );
1571 }
1572 #endif
char event_name[2][PAPI_MAX_STR_LEN]
Definition: data_range.c:23
#define PAPI_ENOEVNT
Definition: papi.h:258
sprintf(splash[splash_line++],"\tIozone: Performance Test of File I/O\n")
int atoi()
static int find_event_index(hwi_presets_t *array, int size, char *tmp)
Definition: papi_preset.c:225
int val
Definition: libbif.c:235
static void work(int EventSet, int mhz)
Definition: cycle_ratio.c:108
#define DERIVED_SUB
Definition: papi_internal.h:74
static void ops_string_merge(char **original, char *insertion, int replaces, int start_index)
Definition: papi_preset.c:464
char * getenv()
#define PAPI_EVENTS_IN_DERIVED_EVENT
Definition: genpapifdef.c:39
#define papi_free(a)
Definition: papi_memory.h:35
unsigned int event_code
Definition: papi_preset.h:14
start
Definition: iozone.c:22736
#define papi_malloc(a)
Definition: papi_memory.h:34
#define PAPI_NULL
Definition: papi.h:290
static int top
Definition: papi_preset.c:794
static char * trim_note(char *in)
Definition: papi_preset.c:197
#define STACK_MAX
Definition: papi_preset.c:791
#define PAPI_MAX_PRESET_EVENTS
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
Definition: appio.c:275
int _papi_hwi_derived_type(char *tmp, int *code)
return PAPI_OK
Definition: linux-nvml.c:458
int count
Definition: iozone.c:22422
#define papi_strdup(a)
Definition: papi_memory.h:39
#define DERIVED_ADD
Definition: papi_internal.h:70
#define PAPI_PRESET_MASK
static int preset
Definition: event_info.c:38
fclose(thread_wqfd)
return PAPI_EINVAL
Definition: linux-nvml.c:408
static char * pop()
Definition: papi_preset.c:844
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
#define printf
Definition: papi_test.h:125
static void ops_string_append(hwi_presets_t *results, hwi_presets_t *depends_on, int addition)
Definition: papi_preset.c:363
int _papi_hwi_native_name_to_code(char *in, int *out)
papi_vector_t * _papi_hwd[]
#define PAPI_HUGE_STR_LEN
Definition: papi.h:465
Return codes and api definitions.
static int check_derived_events(char *target, int derived_type, hwi_presets_t *results, hwi_presets_t *search, int search_size, int token_index)
Definition: papi_preset.c:617
static char * papi_events_table
Definition: papi_preset.c:768
#define INTDBG(format, args...)
Definition: papi_debug.h:65
unsigned char * sptr
Definition: libbif.c:278
static int priority(char symbol)
Definition: papi_preset.c:815
#define papi_valid_free(a)
Definition: papi_memory.h:38
long long ret
Definition: iozone.c:1346
t
Definition: iozone.c:23562
static int papi_load_derived_events(char *pmu_str, int pmu_type, int cidx, int preset_flag)
Definition: papi_preset.c:1039
#define PAPI_MAX_USER_EVENTS
static int is_event(char *event_name, int derived_type, hwi_presets_t *results, int token_index)
Definition: papi_preset.c:739
int _papi_hwi_setup_all_presets(hwi_search_t *findem, int cidx)
Definition: papi_preset.c:44
int i
Definition: fileop.c:140
static int check_native_events(char *target, hwi_presets_t *results)
Definition: papi_preset.c:704
long long found
Definition: libasync.c:735
#define NOT_DERIVED
Definition: papi_internal.h:69
char *long long size
Definition: iozone.c:12023
int k
Definition: iozone.c:19136
static int cidx
Definition: event_info.c:40
static char * stack[STACK_MAX]
Definition: papi_preset.c:792
#define PAPI_EVENT_FILE
Definition: papi_preset.c:151
static int push(char *symbol)
Definition: papi_preset.c:832
hwi_presets_t _papi_hwi_presets[PAPI_MAX_PRESET_EVENTS]
#define PAPI_ESYS
Definition: papi.h:253
static int native
Definition: event_info.c:39
int user_defined_events_count
Definition: papi_internal.c:59
#define DERIVED_INFIX
Definition: papi_internal.h:76
int native[PAPI_EVENTS_IN_DERIVED_EVENT]
Definition: papi_preset.h:16
hwi_presets_t user_defined_events[PAPI_MAX_USER_EVENTS]
Definition: papi_internal.c:58
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
static FILE * fp
void PAPIERROR(char *format,...)
static char * infix_to_postfix(char *in)
Definition: papi_preset.c:910
strcat(command, mountname)
int _papi_load_preset_table(char *pmu_str, int pmu_type, int cidx)
Definition: papi_preset.c:771
static void update_ops_string(char **formula, int old_index, int new_index)
Definition: papi_preset.c:304
char * short_descr
Definition: papi_preset.h:25
hwi_search_t * preset_search_map
static int get_event_line(char *line, FILE *table, char **tmp_perfmon_events_table)
Definition: papi_preset.c:273
strcpy(filename, default_filename)
static FILE * open_event_table(char *name)
Definition: papi_preset.c:246
int PAPI_event_name_to_code(char *in, int *out)
Definition: papi.c:1013
char * buffer
Definition: iozone.c:1366
nsize_list next
Definition: iozone.c:20053
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
int papi_num_components
sscanf(mnc->m_child_port,"%d",&mc.m_child_port)
#define PATH_MAX
Definition: fileop.c:68
char * name
Definition: iozone.c:23648
char * long_descr
Definition: papi_preset.h:26
void freestack()
Definition: papi_preset.c:855
int
Definition: iozone.c:18528
#define PAPI_MIN_STR_LEN
Definition: papi.h:462
int temp
Definition: iozone.c:22158
unsigned int code[PAPI_MAX_INFO_TERMS]
Definition: papi_preset.h:32
char * name[PAPI_MAX_INFO_TERMS]
Definition: papi_preset.h:33
static int gettoken(char *infix, char *token, unsigned int *index)
Definition: papi_preset.c:867
static char * trim_string(char *in)
Definition: papi_preset.c:157
int _papi_hwi_component_index(int event_code)
#define PAPI_PRESET_AND_MASK
int _xml_papi_hwi_setup_all_presets(char *arch)
#define PAPI_UE_MASK
long j
Definition: iozone.c:19135
char * symbol
Definition: papi_preset.h:24
ssize_t retval
Definition: libasync.c:338
long long tmp
Definition: iozone.c:12031
int _papi_hwi_cleanup_all_presets(void)
Definition: papi_preset.c:114
#define DERIVED_POSTFIX
Definition: papi_internal.h:75
unsigned int count
Definition: papi_preset.h:29
static int isitsym(char symbol)
Definition: papi_preset.c:798
pthread_attr_t attr
Definition: iozone.c:18466
#define papi_calloc(a, b)
Definition: papi_memory.h:37
char * postfix
Definition: papi_preset.h:31
char * ptr
Definition: iozone.c:23586