PAPI  5.7.0.0
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++) {
135  _papi_hwd[cidx]->cmp_info.num_preset_events = 0;
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
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",
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",
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 static char stack[2*PAPI_HUGE_STR_LEN]; // stack
792 static int stacktop = -1; // stack length
793 
794 // priority: This function returns the priority of the operator
795 static
796 int priority( char symbol ) {
797  switch( symbol ) {
798  case '@':
799  return -1;
800  case '(':
801  return 0;
802  case '+':
803  case '-':
804  return 1;
805  case '*':
806  case '/':
807  case '%':
808  return 2;
809  default :
810  return 0;
811  } // end switch symbol
812 } // end priority
813 
814 static
815 int push( char symbol ) {
816  if (stacktop >= 2*PAPI_HUGE_STR_LEN - 1) {
817  INTDBG("stack overflow converting algebraic expression (%d,%c)\n", stacktop,symbol );
818  return -1; //***TODO: Figure out how to exit gracefully
819  } // end if stacktop>MAX
820  stack[++stacktop] = symbol;
821  return 0;
822 } // end push
823 
824 // pop from stack
825 static
826 char pop() {
827  if( stacktop < 0 ) {
828  INTDBG("stack underflow converting algebraic expression\n" );
829  return '\0'; //***TODO: Figure out how to exit gracefully
830  } // end if empty
831  return( stack[stacktop--] );
832 } // end pop
833 
834 /* infix_to_postfix:
835  routine that will be called with parameter:
836  char *in characters of infix notation (algebraic formula)
837  returns: char * pointer to string of returned postfix */
838 static char *
839 infix_to_postfix( char *infix ) {
840  INTDBG("ENTER: in: %s, size: %zu\n", infix, strlen(infix));
841  static char postfix[2*PAPI_HUGE_STR_LEN]; // output
842  unsigned int index;
843  int postfixlen;
844  char token;
845  if ( strlen(infix) > PAPI_HUGE_STR_LEN )
846  PAPIERROR("A infix string (probably in user-defined presets) is too big (max allowed %d): %s", PAPI_HUGE_STR_LEN, infix );
847 
848  // initialize stack
849  memset(stack, 0, 2*PAPI_HUGE_STR_LEN);
850  stacktop = -1;
851  push('#');
852  stacktop = 0; // after initialization of stack to #
853  /* initialize output string */
854  memset(postfix,0,2*PAPI_HUGE_STR_LEN);
855  postfixlen = 0;
856 
857  for( index=0; index<strlen(infix); index++ ) {
858  token = infix[index];
859  INTDBG("INTDBG: in: %s, length: %zu, index: %d token %c\n", infix, strlen( infix ), index, token);
860  switch( token ) {
861  case '(':
862  push( token );
863  break;
864  case ')':
865  if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
866  while ( stack[stacktop] != '(' ) {
867  postfix[postfixlen++] = pop();
868  postfix[postfixlen++] = '|';
869  }
870  token = pop(); /* pop the '(' character */
871  break;
872  case '+':
873  case '-':
874  case '*':
875  case '/':
876  case '%':
877  case '^': /* if an operator */
878  if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
879  while ( priority(stack[stacktop]) > priority(token) ) {
880  postfix[postfixlen++] = pop();
881  postfix[postfixlen++] = '|';
882  }
883  push( token ); /* save current operator */
884  break;
885  default: // if alphanumeric character which is not parenthesis or an operator
886  postfix[postfixlen++] = token;
887  break;
888  } // end switch symbol
889  } // end while
890 
891  /* Write any remaining operators */
892  if (postfix[postfixlen-1]!='|') postfix[postfixlen++] = '|';
893  while ( stacktop>0 ) {
894  postfix[postfixlen++] = pop();
895  postfix[postfixlen++] = '|';
896  }
897  postfix[postfixlen++] = '\0';
898  stacktop = -1;
899 
900  INTDBG("EXIT: postfix: %s, size: %zu\n", postfix, strlen(postfix));
901  return (postfix);
902 } // end infix_to_postfix
903 
904 /*
905  * This function will load event definitions from either a file or an in memory table. It is used to load both preset events
906  * which are defined by the PAPI development team and delivered with the product and user defined events which can be defined
907  * by papi users and provided to papi to be processed at library initialization. Both the preset events and user defined events
908  * support the same event definition syntax.
909  *
910  * Event definition file syntax:
911  * see PAPI_derived_event_files(1) man page.
912  *
913  * Blank lines are ignored
914  * Lines that begin with '#' are comments.
915  * Lines that begin with 'CPU' identify a pmu name and have the following effect.
916  * If this pmu name does not match the pmu_str passed in, it is ignored and we get the next input line.
917  * If this pmu name matches the pmu_str passed in, we set a 'process events' flag.
918  * Multiple consecutive 'CPU' lines may be provided and if any of them match the pmu_str passed in, we set a 'process events' flag.
919  * When a 'CPU' line is found following event definition lines, it turns off the 'process events' flag and then does the above checks.
920  * Lines that begin with 'PRESET' or 'EVENT' specify an event definition and are processed as follows.
921  * If the 'process events' flag is not set, the line is ignored and we get the next input line.
922  * 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.
923  *
924  * There are three possible sources of input for preset event definitions. The code will first look for the environment variable
925  * "PAPI_CSV_EVENT_FILE". If found its value will be used as the pathname of where to get the preset information. If not found,
926  * the code will look for a built in table containing preset events. If the built in table was not created during the build of
927  * PAPI then the code will build a pathname of the form "PAPI_DATADIR/PAPI_EVENT_FILE". Each of these are build variables, the
928  * PAPI_DATADIR variable can be given a value during the configure of PAPI at build time, and the PAPI_EVENT_FILE variable has a
929  * hard coded value of "papi_events.csv".
930  *
931  * There is only one way to define user events. The code will look for an environment variable "PAPI_USER_EVENTS_FILE". If found
932  * its value will be used as the pathname of a file which contains user event definitions. The events defined in this file will be
933  * added to the ones known by PAPI when the call to PAPI_library_init is done.
934  *
935  * TODO:
936  * Look into restoring the ability to specify a user defined event file with a call to PAPI_set_opt(PAPI_USER_EVENTS_FILE).
937  * This needs to figure out how to pass a pmu name (could use default pmu from component 0) to this function.
938  *
939  * 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
940  * 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
941  * requirement that all events used by a given derived event must be from the same component.
942  *
943  */
944 
945 
946 static int
947 papi_load_derived_events (char *pmu_str, int pmu_type, int cidx, int preset_flag) {
948  SUBDBG( "ENTER: pmu_str: %s, pmu_type: %d, cidx: %d, preset_flag: %d\n", pmu_str, pmu_type, cidx, preset_flag);
949 
950  char pmu_name[PAPI_MIN_STR_LEN];
951  char line[LINE_MAX];
952  char name[PATH_MAX] = "builtin papi_events_table";
953  char *event_file_path=NULL;
954  char *event_table_ptr=NULL;
955  int event_type_bits = 0;
956  char *tmpn;
957  char *tok_save_ptr=NULL;
958  FILE *event_file = NULL;
959  hwi_presets_t *results=NULL;
960  int result_size = 0;
961  int *event_count = NULL;
962  int invalid_event;
963  int line_no = 0; /* count of lines read from event definition input */
964  int derived = 0;
965  int res_idx = 0; /* index into results array for where to store next event */
966  int preset = 0;
967  int get_events = 0; /* only process derived events after CPU type they apply to is identified */
968  int found_events = 0; /* flag to track if event definitions (PRESETS) are found since last CPU declaration */
969 #ifdef PAPI_DATADIR
970  char path[PATH_MAX];
971 #endif
972 
973 
974  if (preset_flag) {
975  /* try the environment variable first */
976  if ((tmpn = getenv("PAPI_CSV_EVENT_FILE")) && (strlen(tmpn) > 0)) {
977  event_file_path = tmpn;
978  }
979  /* if no valid environment variable, look for built-in table */
980  else if (papi_events_table) {
981  event_table_ptr = papi_events_table;
982  }
983  /* if no env var and no built-in, search for default file */
984  else {
985 #ifdef PAPI_DATADIR
986  sprintf( path, "%s/%s", PAPI_DATADIR, PAPI_EVENT_FILE );
987  event_file_path = path;
988 #else
989  event_file_path = PAPI_EVENT_FILE;
990 #endif
991  }
992  event_type_bits = PAPI_PRESET_MASK;
993  results = &_papi_hwi_presets[0];
994  result_size = PAPI_MAX_PRESET_EVENTS;
995  event_count = &_papi_hwd[cidx]->cmp_info.num_preset_events;
996  } else {
997  if ((event_file_path = getenv( "PAPI_USER_EVENTS_FILE" )) == NULL ) {
998  SUBDBG("EXIT: User event definition file not provided.\n");
999  return PAPI_OK;
1000  }
1001 
1002  event_type_bits = PAPI_UE_MASK;
1003  results = &user_defined_events[0];
1004  result_size = PAPI_MAX_USER_EVENTS;
1005  event_count = &user_defined_events_count;
1006  }
1007 
1008  // if we have an event file pathname, open it and read event definitions from the file
1009  if (event_file_path != NULL) {
1010  if ((event_file = open_event_table(event_file_path)) == NULL) {
1011  // if file open fails, return an error
1012  SUBDBG("EXIT: Event file open failed.\n");
1013  return PAPI_ESYS;
1014  }
1015  strncpy(name, event_file_path, sizeof(name)-1);
1016  name[sizeof(name)-1] = '\0';
1017  } else if (event_table_ptr == NULL) {
1018  // if we do not have a path name or table pointer, return an error
1019  SUBDBG("EXIT: Both event_file_path and event_table_ptr are NULL.\n");
1020  return PAPI_ESYS;
1021  }
1022 
1023  /* copy the pmu identifier, stripping commas if found */
1024  tmpn = pmu_name;
1025  while (*pmu_str) {
1026  if (*pmu_str != ',')
1027  *tmpn++ = *pmu_str;
1028  pmu_str++;
1029  }
1030  *tmpn = '\0';
1031 
1032  /* at this point we have either a valid file pointer or built-in table pointer */
1033  while (get_event_line(line, event_file, &event_table_ptr)) {
1034  char *t;
1035  int i;
1036 
1037  // increment number of lines we have read
1038  line_no++;
1039 
1040  t = trim_string(strtok_r(line, ",", &tok_save_ptr));
1041 
1042  /* Skip blank lines */
1043  if ((t == NULL) || (strlen(t) == 0))
1044  continue;
1045 
1046  /* Skip comments */
1047  if (t[0] == '#') {
1048  continue;
1049  }
1050 
1051  if (strcasecmp(t, "CPU") == 0) {
1052  if (get_events != 0 && found_events != 0) {
1053  SUBDBG( "Ending event scanning at line %d of %s.\n", line_no, name);
1054  get_events = 0;
1055  found_events = 0;
1056  }
1057 
1058  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1059  if ((t == NULL) || (strlen(t) == 0)) {
1060  PAPIERROR("Expected name after CPU token at line %d of %s -- ignoring", line_no, name);
1061  continue;
1062  }
1063 
1064  if (strcasecmp(t, pmu_name) == 0) {
1065  int type;
1066 
1067  SUBDBG( "Process events for PMU %s found at line %d of %s.\n", t, line_no, name);
1068 
1069  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1070  if ((t == NULL) || (strlen(t) == 0)) {
1071  SUBDBG("No additional qualifier found, matching on string.\n");
1072  get_events = 1;
1073  } else if ((sscanf(t, "%d", &type) == 1) && (type == pmu_type)) {
1074  SUBDBG( "Found CPU %s type %d at line %d of %s.\n", pmu_name, type, line_no, name);
1075  get_events = 1;
1076  } else {
1077  SUBDBG( "Additional qualifier match failed %d vs %d.\n", pmu_type, type);
1078  }
1079  }
1080  continue;
1081  }
1082 
1083  if ((strcasecmp(t, "PRESET") == 0) || (strcasecmp(t, "EVENT") == 0)) {
1084 
1085  if (get_events == 0)
1086  continue;
1087 
1088  found_events = 1;
1089  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1090 
1091  if ((t == NULL) || (strlen(t) == 0)) {
1092  PAPIERROR("Expected name after PRESET token at line %d of %s -- ignoring", line_no, name);
1093  continue;
1094  }
1095 
1096  SUBDBG( "Examining event %s\n", t);
1097 
1098  // see if this event already exists in the results array, if not already known it sets up event in unused entry
1099  if ((res_idx = find_event_index (results, result_size, t)) < 0) {
1100  PAPIERROR("No room left for event %s -- ignoring", t);
1101  continue;
1102  }
1103 
1104  // add the proper event bits (preset or user defined bits)
1105  preset = res_idx | event_type_bits;
1106  (void) preset;
1107 
1108  SUBDBG( "Use event code: %#x for %s\n", preset, t);
1109 
1110  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1111  if ((t == NULL) || (strlen(t) == 0)) {
1112  // got an error, make this entry unused
1113  if (results[res_idx].symbol != NULL){
1114  papi_free (results[res_idx].symbol);
1115  results[res_idx].symbol = NULL;
1116  }
1117  PAPIERROR("Expected derived type after PRESET token at line %d of %s -- ignoring", line_no, name);
1118  continue;
1119  }
1120 
1121  if (_papi_hwi_derived_type(t, &derived) != PAPI_OK) {
1122  // got an error, make this entry unused
1123  if (results[res_idx].symbol != NULL){
1124  papi_free (results[res_idx].symbol);
1125  results[res_idx].symbol = NULL;
1126  }
1127  PAPIERROR("Invalid derived name %s after PRESET token at line %d of %s -- ignoring", t, line_no, name);
1128  continue;
1129  }
1130 
1131  /****************************************/
1132  /* Have an event, let's start assigning */
1133  /****************************************/
1134 
1135  SUBDBG( "Adding event: %s, code: %#x, derived: %d results[%d]: %p.\n", t, preset, derived, res_idx, &results[res_idx]);
1136 
1137  /* results[res_idx].event_code = preset; */
1138  results[res_idx].derived_int = derived;
1139 
1140  /* Derived support starts here */
1141  /* Special handling for postfix and infix */
1142  if ((derived == DERIVED_POSTFIX) || (derived == DERIVED_INFIX)) {
1143  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1144  if ((t == NULL) || (strlen(t) == 0)) {
1145  // got an error, make this entry unused
1146  if (results[res_idx].symbol != NULL){
1147  papi_free (results[res_idx].symbol);
1148  results[res_idx].symbol = NULL;
1149  }
1150  PAPIERROR("Expected Operation string after derived type DERIVED_POSTFIX or DERIVED_INFIX at line %d of %s -- ignoring", line_no, name);
1151  continue;
1152  }
1153 
1154  // if it is an algebraic formula, we need to convert it to postfix
1155  if (derived == DERIVED_INFIX) {
1156  SUBDBG( "Converting InFix operations %s\n", t);
1157  t = infix_to_postfix( t );
1158  results[res_idx].derived_int = DERIVED_POSTFIX;
1159  }
1160 
1161  SUBDBG( "Saving PostFix operations %s\n", t);
1162  results[res_idx].postfix = papi_strdup(t);
1163  }
1164 
1165  /* All derived terms collected here */
1166  i = 0;
1167  invalid_event = 0;
1168  results[res_idx].count = 0;
1169  do {
1170  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1171  if ((t == NULL) || (strlen(t) == 0))
1172  break;
1173  if (strcasecmp(t, "NOTE") == 0)
1174  break;
1175  if (strcasecmp(t, "LDESC") == 0)
1176  break;
1177  if (strcasecmp(t, "SDESC") == 0)
1178  break;
1179 
1180  SUBDBG( "Adding term (%d) %s to derived event %#x, current native event count: %d.\n", i, t, preset, results[res_idx].count);
1181 
1182  // show that we do not have an event code yet (the component may create one and update this info)
1183  // this also clears any values left over from a previous call
1185 
1186  // make sure that this term in the derived event is a valid event name
1187  // this call replaces preset and user event names with the equivalent native events in our results table
1188  // it also updates formulas for derived events so that they refer to the correct native event index
1189  if (is_event(t, results[res_idx].derived_int, &results[res_idx], i) == 0) {
1190  invalid_event = 1;
1191  PAPIERROR("Missing event %s, used in derived event %s", t, results[res_idx].symbol);
1192  break;
1193  }
1194 
1195  i++;
1196  } while (results[res_idx].count < PAPI_EVENTS_IN_DERIVED_EVENT);
1197 
1198  /* preset code list must be PAPI_NULL terminated */
1200  results[res_idx].code[results[res_idx].count] = PAPI_NULL;
1201  }
1202 
1203  if (invalid_event) {
1204  // got an error, make this entry unused
1205  // preset table is statically allocated, user defined is dynamic
1206  unsigned int j;
1207  for (j = 0; j < results[res_idx].count; j++){
1208  if (results[res_idx].name[j] != NULL){
1209  papi_free( results[res_idx].name[j] );
1210  results[res_idx].name[j] = NULL;
1211  }
1212  }
1213 
1214  if (!preset_flag){
1215  if(results[res_idx].symbol != NULL){
1216  papi_free (results[res_idx].symbol);
1217  results[res_idx].symbol = NULL;
1218  }
1219  }
1220 
1221  continue;
1222  }
1223 
1224  /* End of derived support */
1225 
1226  // if we did not find any terms to base this derived event on, report error
1227  if (i == 0) {
1228  // got an error, make this entry unused
1229  if (!preset_flag){
1230  if(results[res_idx].symbol != NULL){
1231  papi_free (results[res_idx].symbol);
1232  results[res_idx].symbol = NULL;
1233  }
1234  }
1235  PAPIERROR("Expected PFM event after DERIVED token at line %d of %s -- ignoring", line_no, name);
1236  continue;
1237  }
1238 
1240  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1241  }
1242 
1243  // if something was provided following the list of events to be used by the operation, process it
1244  if ( t!= NULL && strlen(t) > 0 ) {
1245  do {
1246  // save the field name
1247  char *fptr = papi_strdup(t);
1248 
1249  // get the value to be used with this field
1250  t = trim_note(strtok_r(NULL, ",", &tok_save_ptr));
1251  if ( t== NULL || strlen(t) == 0 ) {
1252  papi_free(fptr);
1253  break;
1254  }
1255 
1256  // Handle optional short descriptions, long descriptions and notes
1257  if (strcasecmp(fptr, "SDESC") == 0) {
1258  results[res_idx].short_descr = papi_strdup(t);
1259  }
1260  if (strcasecmp(fptr, "LDESC") == 0) {
1261  results[res_idx].long_descr = papi_strdup(t);
1262  }
1263  if (strcasecmp(fptr, "NOTE") == 0) {
1264  results[res_idx].note = papi_strdup(t);
1265  }
1266 
1267  SUBDBG( "Found %s (%s) on line %d\n", fptr, t, line_no);
1268  papi_free (fptr);
1269 
1270  // look for another field name
1271  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1272  if ( t== NULL || strlen(t) == 0 ) {
1273  break;
1274  }
1275  } while (t != NULL);
1276  }
1277  (*event_count)++;
1278  continue;
1279  }
1280 
1281  PAPIERROR("Unrecognized token %s at line %d of %s -- ignoring", t, line_no, name);
1282  }
1283 
1284  if (event_file) {
1285  fclose(event_file);
1286  }
1287 
1288  SUBDBG("EXIT: Done processing derived event file.\n");
1289  return PAPI_OK;
1290 }
1291 
1292 
1293 
1294 
1295 /* The following code is proof of principle for reading preset events from an
1296  xml file. It has been tested and works for pentium3. It relys on the expat
1297  library and is invoked by adding
1298  XMLFLAG = -DXML
1299  to the Makefile. It is presently hardcoded to look for "./papi_events.xml"
1300 */
1301 #ifdef XML
1302 
1303 #define BUFFSIZE 8192
1304 #define SPARSE_BEGIN 0
1305 #define SPARSE_EVENT_SEARCH 1
1306 #define SPARSE_EVENT 2
1307 #define SPARSE_DESC 3
1308 #define ARCH_SEARCH 4
1309 #define DENSE_EVENT_SEARCH 5
1310 #define DENSE_NATIVE_SEARCH 6
1311 #define DENSE_NATIVE_DESC 7
1312 #define FINISHED 8
1313 
1314 char buffer[BUFFSIZE], *xml_arch;
1315 int location = SPARSE_BEGIN, sparse_index = 0, native_index, error = 0;
1316 
1317 /* The function below, _xml_start(), is a hook into expat's XML
1318  * parser. _xml_start() defines how the parser handles the
1319  * opening tags in PAPI's XML file. This function can be understood
1320  * more easily if you follow along with its logic while looking at
1321  * papi_events.xml. The location variable is a global telling us
1322  * where we are in the XML file. Have we found our architecture's
1323  * events yet? Are we looking at an event definition?...etc.
1324  */
1325 static void
1326 _xml_start( void *data, const char *el, const char **attr )
1327 {
1328  int native_encoding;
1329 
1330  if ( location == SPARSE_BEGIN && !strcmp( "papistdevents", el ) ) {
1331  location = SPARSE_EVENT_SEARCH;
1332  } else if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
1333  _papi_hwi_presets[sparse_index].info.symbol = papi_strdup( attr[1] );
1334 // strcpy(_papi_hwi_presets.info[sparse_index].symbol, attr[1]);
1335  location = SPARSE_EVENT;
1336  } else if ( location == SPARSE_EVENT && !strcmp( "desc", el ) ) {
1337  location = SPARSE_DESC;
1338  } else if ( location == ARCH_SEARCH && !strcmp( "availevents", el ) &&
1339  !strcmp( xml_arch, attr[1] ) ) {
1340  location = DENSE_EVENT_SEARCH;
1341  } else if ( location == DENSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
1342  if ( !strcmp( "PAPI_NULL", attr[1] ) ) {
1343  location = FINISHED;
1344  return;
1345  } else if ( PAPI_event_name_to_code( ( char * ) attr[1], &sparse_index )
1346  != PAPI_OK ) {
1347  PAPIERROR( "Improper Preset name given in XML file for %s.",
1348  attr[1] );
1349  error = 1;
1350  }
1351  sparse_index &= PAPI_PRESET_AND_MASK;
1352 
1353  /* allocate and initialize data space for this event */
1354  papi_valid_free( _papi_hwi_presets[sparse_index].data );
1355  _papi_hwi_presets[sparse_index].data =
1356  papi_malloc( sizeof ( hwi_preset_data_t ) );
1357  native_index = 0;
1358  _papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
1359  _papi_hwi_presets[sparse_index].data->operation[0] = '\0';
1360 
1361 
1362  if ( attr[2] ) { /* derived event */
1363  _papi_hwi_presets[sparse_index].data->derived =
1364  _papi_hwi_derived_type( ( char * ) attr[3] );
1365  /* where does DERIVED POSTSCRIPT get encoded?? */
1366  if ( _papi_hwi_presets[sparse_index].data->derived == -1 ) {
1367  PAPIERROR( "No derived type match for %s in Preset XML file.",
1368  attr[3] );
1369  error = 1;
1370  }
1371 
1372  if ( attr[5] ) {
1373  _papi_hwi_presets[sparse_index].count = atoi( attr[5] );
1374  } else {
1375  PAPIERROR( "No count given for %s in Preset XML file.",
1376  attr[1] );
1377  error = 1;
1378  }
1379  } else {
1380  _papi_hwi_presets[sparse_index].data->derived = NOT_DERIVED;
1381  _papi_hwi_presets[sparse_index].count = 1;
1382  }
1383  location = DENSE_NATIVE_SEARCH;
1384  } else if ( location == DENSE_NATIVE_SEARCH && !strcmp( "native", el ) ) {
1385  location = DENSE_NATIVE_DESC;
1386  } else if ( location == DENSE_NATIVE_DESC && !strcmp( "event", el ) ) {
1387  if ( _papi_hwi_native_name_to_code( attr[1], &native_encoding ) !=
1388  PAPI_OK ) {
1389  printf( "Improper Native name given in XML file for %s\n",
1390  attr[1] );
1391  PAPIERROR( "Improper Native name given in XML file for %s",
1392  attr[1] );
1393  error = 1;
1394  }
1395  _papi_hwi_presets[sparse_index].data->native[native_index] =
1396  native_encoding;
1397  native_index++;
1398  _papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
1399  } else if ( location && location != ARCH_SEARCH && location != FINISHED ) {
1400  PAPIERROR( "Poorly-formed Preset XML document." );
1401  error = 1;
1402  }
1403 }
1404 
1405 /* The function below, _xml_end(), is a hook into expat's XML
1406  * parser. _xml_end() defines how the parser handles the
1407  * end tags in PAPI's XML file.
1408  */
1409 static void
1410 _xml_end( void *data, const char *el )
1411 {
1412  int i;
1413 
1414  if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papistdevents", el ) ) {
1415  for ( i = sparse_index; i < PAPI_MAX_PRESET_EVENTS; i++ ) {
1416  _papi_hwi_presets[i].info.symbol = NULL;
1417  _papi_hwi_presets[i].info.long_descr = NULL;
1418  _papi_hwi_presets[i].info.short_descr = NULL;
1419  }
1420  location = ARCH_SEARCH;
1421  } else if ( location == DENSE_NATIVE_DESC && !strcmp( "native", el ) ) {
1422  location = DENSE_EVENT_SEARCH;
1423  } else if ( location == DENSE_EVENT_SEARCH && !strcmp( "availevents", el ) ) {
1424  location = FINISHED;
1425  }
1426 }
1427 
1428 /* The function below, _xml_content(), is a hook into expat's XML
1429  * parser. _xml_content() defines how the parser handles the
1430  * text between tags in PAPI's XML file. The information between
1431  * tags is usally text for event descriptions.
1432  */
1433 static void
1434 _xml_content( void *data, const char *el, const int len )
1435 {
1436  int i;
1437  if ( location == SPARSE_DESC ) {
1438  _papi_hwi_presets[sparse_index].info.long_descr =
1439  papi_malloc( len + 1 );
1440  for ( i = 0; i < len; i++ )
1441  _papi_hwi_presets[sparse_index].info.long_descr[i] = el[i];
1442  _papi_hwi_presets[sparse_index].info.long_descr[len] = '\0';
1443  /* the XML data currently doesn't contain a short description */
1444  _papi_hwi_presets[sparse_index].info.short_descr = NULL;
1445  sparse_index++;
1446  _papi_hwi_presets[sparse_index].data = NULL;
1447  location = SPARSE_EVENT_SEARCH;
1448  }
1449 }
1450 
1451 int
1452 _xml_papi_hwi_setup_all_presets( char *arch, hwi_dev_notes_t * notes )
1453 {
1454  int done = 0;
1455  FILE *fp = fopen( "./papi_events.xml", "r" );
1456  XML_Parser p = XML_ParserCreate( NULL );
1457 
1458  if ( !p ) {
1459  PAPIERROR( "Couldn't allocate memory for XML parser." );
1460  fclose(fp);
1461  return ( PAPI_ESYS );
1462  }
1463  XML_SetElementHandler( p, _xml_start, _xml_end );
1464  XML_SetCharacterDataHandler( p, _xml_content );
1465  if ( fp == NULL ) {
1466  PAPIERROR( "Error opening Preset XML file." );
1467  fclose(fp);
1468  return ( PAPI_ESYS );
1469  }
1470 
1471  xml_arch = arch;
1472 
1473  do {
1474  int len;
1475  void *buffer = XML_GetBuffer( p, BUFFSIZE );
1476 
1477  if ( buffer == NULL ) {
1478  PAPIERROR( "Couldn't allocate memory for XML buffer." );
1479  fclose(fp);
1480  return ( PAPI_ESYS );
1481  }
1482  len = fread( buffer, 1, BUFFSIZE, fp );
1483  if ( ferror( fp ) ) {
1484  PAPIERROR( "XML read error." );
1485  fclose(fp);
1486  return ( PAPI_ESYS );
1487  }
1488  done = feof( fp );
1489  if ( !XML_ParseBuffer( p, len, len == 0 ) ) {
1490  PAPIERROR( "Parse error at line %d:\n%s",
1491  XML_GetCurrentLineNumber( p ),
1492  XML_ErrorString( XML_GetErrorCode( p ) ) );
1493  fclose(fp);
1494  return ( PAPI_ESYS );
1495  }
1496  if ( error ) {
1497  fclose(fp);
1498  return ( PAPI_ESYS );
1499  }
1500  } while ( !done );
1501  XML_ParserFree( p );
1502  fclose( fp );
1503  return ( PAPI_OK );
1504 }
1505 #endif
char event_name[2][PAPI_MAX_STR_LEN]
Definition: data_range.c:29
#define PAPI_OK
Definition: fpapi.h:105
int atoi()
static int find_event_index(hwi_presets_t *array, int size, char *tmp)
Definition: papi_preset.c:225
#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
static const char * name
Definition: fork_overflow.c:31
char * getenv()
#define PAPI_EVENTS_IN_DERIVED_EVENT
Definition: genpapifdef.c:39
#define PAPI_EINVAL
Definition: fpapi.h:106
#define papi_free(a)
Definition: papi_memory.h:35
unsigned int event_code
Definition: papi_preset.h:14
static void work(int EventSet, int sleep_test, int quiet)
Definition: papi_ref_cyc.c:56
#define papi_malloc(a)
Definition: papi_memory.h:34
static char * trim_note(char *in)
Definition: papi_preset.c:197
static double array[ARRAYSIZE]
Definition: papi_l1_dca.c:23
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)
static int stacktop
Definition: papi_preset.c:792
#define papi_strdup(a)
Definition: papi_memory.h:39
#define DERIVED_ADD
Definition: papi_internal.h:70
int PAPI_event_name_to_code(const char *in, int *out)
Definition: papi.c:1004
#define PAPI_PRESET_MASK
int retval
Definition: zero_fork.c:53
static struct timeval start
static char pop()
Definition: papi_preset.c:826
static void ops_string_append(hwi_presets_t *results, hwi_presets_t *depends_on, int addition)
Definition: papi_preset.c:363
static FILE * fp
double tmp
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
static int priority(char symbol)
Definition: papi_preset.c:796
#define papi_valid_free(a)
Definition: papi_memory.h:38
#define PAPI_ESYS
Definition: fpapi.h:108
static int papi_load_derived_events(char *pmu_str, int pmu_type, int cidx, int preset_flag)
Definition: papi_preset.c:947
static int cidx
#define PAPI_MAX_PRESET_EVENTS
Definition: fpapi.h:16
#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
static int check_native_events(char *target, hwi_presets_t *results)
Definition: papi_preset.c:704
#define NOT_DERIVED
Definition: papi_internal.h:69
int user_defined_events_count
Definition: papi_internal.c:60
#define PAPI_EVENT_FILE
Definition: papi_preset.c:151
#define PAPI_HUGE_STR_LEN
Definition: fpapi.h:42
hwi_presets_t _papi_hwi_presets[PAPI_MAX_PRESET_EVENTS]
#define PAPI_MIN_STR_LEN
Definition: fpapi.h:41
hwi_presets_t user_defined_events[]
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
static int native
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
#define PAPI_NULL
Definition: fpapi.h:13
void PAPIERROR(char *format,...)
long long ret
Definition: iozone.c:1346
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
static FILE * open_event_table(char *name)
Definition: papi_preset.c:246
char * buffer
Definition: iozone.c:1366
static int val[12]
Definition: activity.c:47
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
int papi_num_components
#define PATH_MAX
Definition: fileop.c:68
static char * infix_to_postfix(char *infix)
Definition: papi_preset.c:839
char * long_descr
Definition: papi_preset.h:26
static char stack[2 *PAPI_HUGE_STR_LEN]
Definition: papi_preset.c:791
#define PAPI_ENOEVNT
Definition: fpapi.h:112
unsigned int code[PAPI_MAX_INFO_TERMS]
Definition: papi_preset.h:32
char * name[PAPI_MAX_INFO_TERMS]
Definition: papi_preset.h:33
static char * trim_string(char *in)
Definition: papi_preset.c:157
int _papi_hwi_component_index(int event_code)
static int push(char symbol)
Definition: papi_preset.c:815
#define PAPI_PRESET_AND_MASK
struct papi_vectors * _papi_hwd[]
int _xml_papi_hwi_setup_all_presets(char *arch)
static int preset
#define PAPI_UE_MASK
char * symbol
Definition: papi_preset.h:24
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
int _papi_hwi_native_name_to_code(const char *in, int *out)
static long count
#define papi_calloc(a, b)
Definition: papi_memory.h:37
int i
Definition: fileop.c:140
char * postfix
Definition: papi_preset.h:31