PAPI  5.6.0.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
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 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  papi_free (results[res_idx].symbol);
1114  results[res_idx].symbol = NULL;
1115  PAPIERROR("Expected derived type after PRESET token at line %d of %s -- ignoring", line_no, name);
1116  continue;
1117  }
1118 
1119  if (_papi_hwi_derived_type(t, &derived) != PAPI_OK) {
1120  // got an error, make this entry unused
1121  papi_free (results[res_idx].symbol);
1122  results[res_idx].symbol = NULL;
1123  PAPIERROR("Invalid derived name %s after PRESET token at line %d of %s -- ignoring", t, line_no, name);
1124  continue;
1125  }
1126 
1127  /****************************************/
1128  /* Have an event, let's start assigning */
1129  /****************************************/
1130 
1131  SUBDBG( "Adding event: %s, code: %#x, derived: %d results[%d]: %p.\n", t, preset, derived, res_idx, &results[res_idx]);
1132 
1133  /* results[res_idx].event_code = preset; */
1134  results[res_idx].derived_int = derived;
1135 
1136  /* Derived support starts here */
1137  /* Special handling for postfix and infix */
1138  if ((derived == DERIVED_POSTFIX) || (derived == DERIVED_INFIX)) {
1139  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1140  if ((t == NULL) || (strlen(t) == 0)) {
1141  // got an error, make this entry unused
1142  papi_free (results[res_idx].symbol);
1143  results[res_idx].symbol = NULL;
1144  PAPIERROR("Expected Operation string after derived type DERIVED_POSTFIX or DERIVED_INFIX at line %d of %s -- ignoring", line_no, name);
1145  continue;
1146  }
1147 
1148  // if it is an algebraic formula, we need to convert it to postfix
1149  if (derived == DERIVED_INFIX) {
1150  SUBDBG( "Converting InFix operations %s\n", t);
1151  t = infix_to_postfix( t );
1152  results[res_idx].derived_int = DERIVED_POSTFIX;
1153  }
1154 
1155  SUBDBG( "Saving PostFix operations %s\n", t);
1156  results[res_idx].postfix = papi_strdup(t);
1157  }
1158 
1159  /* All derived terms collected here */
1160  i = 0;
1161  invalid_event = 0;
1162  results[res_idx].count = 0;
1163  do {
1164  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1165  if ((t == NULL) || (strlen(t) == 0))
1166  break;
1167  if (strcasecmp(t, "NOTE") == 0)
1168  break;
1169  if (strcasecmp(t, "LDESC") == 0)
1170  break;
1171  if (strcasecmp(t, "SDESC") == 0)
1172  break;
1173 
1174  SUBDBG( "Adding term (%d) %s to derived event %#x, current native event count: %d.\n", i, t, preset, results[res_idx].count);
1175 
1176  // show that we do not have an event code yet (the component may create one and update this info)
1177  // this also clears any values left over from a previous call
1179 
1180  // make sure that this term in the derived event is a valid event name
1181  // this call replaces preset and user event names with the equivalent native events in our results table
1182  // it also updates formulas for derived events so that they refer to the correct native event index
1183  if (is_event(t, results[res_idx].derived_int, &results[res_idx], i) == 0) {
1184  invalid_event = 1;
1185  PAPIERROR("Missing event %s, used in derived event %s", t, results[res_idx].symbol);
1186  break;
1187  }
1188 
1189  i++;
1190  } while (results[res_idx].count < PAPI_EVENTS_IN_DERIVED_EVENT);
1191 
1192  /* preset code list must be PAPI_NULL terminated */
1193  if (i < PAPI_EVENTS_IN_DERIVED_EVENT) {
1194  results[res_idx].code[results[res_idx].count] = PAPI_NULL;
1195  }
1196 
1197  if (invalid_event) {
1198  // got an error, make this entry unused
1199  // preset table is statically allocated, user defined is dynamic
1200  if (!preset_flag) papi_free (results[res_idx].symbol);
1201  results[res_idx].symbol = NULL;
1202  continue;
1203  }
1204 
1205  /* End of derived support */
1206 
1207  // if we did not find any terms to base this derived event on, report error
1208  if (i == 0) {
1209  // got an error, make this entry unused
1210  if (!preset_flag) papi_free (results[res_idx].symbol);
1211  results[res_idx].symbol = NULL;
1212  PAPIERROR("Expected PFM event after DERIVED token at line %d of %s -- ignoring", line_no, name);
1213  continue;
1214  }
1215 
1216  if (i == PAPI_EVENTS_IN_DERIVED_EVENT) {
1217  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1218  }
1219 
1220  // if something was provided following the list of events to be used by the operation, process it
1221  if ( t!= NULL && strlen(t) > 0 ) {
1222  do {
1223  // save the field name
1224  char *fptr = papi_strdup(t);
1225 
1226  // get the value to be used with this field
1227  t = trim_note(strtok_r(NULL, ",", &tok_save_ptr));
1228  if ( t== NULL || strlen(t) == 0 ) {
1229  papi_free(fptr);
1230  break;
1231  }
1232 
1233  // Handle optional short descriptions, long descriptions and notes
1234  if (strcasecmp(fptr, "SDESC") == 0) {
1235  results[res_idx].short_descr = papi_strdup(t);
1236  }
1237  if (strcasecmp(fptr, "LDESC") == 0) {
1238  results[res_idx].long_descr = papi_strdup(t);
1239  }
1240  if (strcasecmp(fptr, "NOTE") == 0) {
1241  results[res_idx].note = papi_strdup(t);
1242  }
1243 
1244  SUBDBG( "Found %s (%s) on line %d\n", fptr, t, line_no);
1245  papi_free (fptr);
1246 
1247  // look for another field name
1248  t = trim_string(strtok_r(NULL, ",", &tok_save_ptr));
1249  if ( t== NULL || strlen(t) == 0 ) {
1250  break;
1251  }
1252  } while (t != NULL);
1253  }
1254  (*event_count)++;
1255  continue;
1256  }
1257 
1258  PAPIERROR("Unrecognized token %s at line %d of %s -- ignoring", t, line_no, name);
1259  }
1260 
1261  if (event_file) {
1262  fclose(event_file);
1263  }
1264 
1265  SUBDBG("EXIT: Done processing derived event file.\n");
1266  return PAPI_OK;
1267 }
1268 
1269 
1270 
1271 
1272 /* The following code is proof of principle for reading preset events from an
1273  xml file. It has been tested and works for pentium3. It relys on the expat
1274  library and is invoked by adding
1275  XMLFLAG = -DXML
1276  to the Makefile. It is presently hardcoded to look for "./papi_events.xml"
1277 */
1278 #ifdef XML
1279 
1280 #define BUFFSIZE 8192
1281 #define SPARSE_BEGIN 0
1282 #define SPARSE_EVENT_SEARCH 1
1283 #define SPARSE_EVENT 2
1284 #define SPARSE_DESC 3
1285 #define ARCH_SEARCH 4
1286 #define DENSE_EVENT_SEARCH 5
1287 #define DENSE_NATIVE_SEARCH 6
1288 #define DENSE_NATIVE_DESC 7
1289 #define FINISHED 8
1290 
1291 char buffer[BUFFSIZE], *xml_arch;
1292 int location = SPARSE_BEGIN, sparse_index = 0, native_index, error = 0;
1293 
1294 /* The function below, _xml_start(), is a hook into expat's XML
1295  * parser. _xml_start() defines how the parser handles the
1296  * opening tags in PAPI's XML file. This function can be understood
1297  * more easily if you follow along with its logic while looking at
1298  * papi_events.xml. The location variable is a global telling us
1299  * where we are in the XML file. Have we found our architecture's
1300  * events yet? Are we looking at an event definition?...etc.
1301  */
1302 static void
1303 _xml_start( void *data, const char *el, const char **attr )
1304 {
1305  int native_encoding;
1306 
1307  if ( location == SPARSE_BEGIN && !strcmp( "papistdevents", el ) ) {
1308  location = SPARSE_EVENT_SEARCH;
1309  } else if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
1310  _papi_hwi_presets[sparse_index].info.symbol = papi_strdup( attr[1] );
1311 // strcpy(_papi_hwi_presets.info[sparse_index].symbol, attr[1]);
1312  location = SPARSE_EVENT;
1313  } else if ( location == SPARSE_EVENT && !strcmp( "desc", el ) ) {
1314  location = SPARSE_DESC;
1315  } else if ( location == ARCH_SEARCH && !strcmp( "availevents", el ) &&
1316  !strcmp( xml_arch, attr[1] ) ) {
1317  location = DENSE_EVENT_SEARCH;
1318  } else if ( location == DENSE_EVENT_SEARCH && !strcmp( "papievent", el ) ) {
1319  if ( !strcmp( "PAPI_NULL", attr[1] ) ) {
1320  location = FINISHED;
1321  return;
1322  } else if ( PAPI_event_name_to_code( ( char * ) attr[1], &sparse_index )
1323  != PAPI_OK ) {
1324  PAPIERROR( "Improper Preset name given in XML file for %s.",
1325  attr[1] );
1326  error = 1;
1327  }
1328  sparse_index &= PAPI_PRESET_AND_MASK;
1329 
1330  /* allocate and initialize data space for this event */
1331  papi_valid_free( _papi_hwi_presets[sparse_index].data );
1332  _papi_hwi_presets[sparse_index].data =
1333  papi_malloc( sizeof ( hwi_preset_data_t ) );
1334  native_index = 0;
1335  _papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
1336  _papi_hwi_presets[sparse_index].data->operation[0] = '\0';
1337 
1338 
1339  if ( attr[2] ) { /* derived event */
1340  _papi_hwi_presets[sparse_index].data->derived =
1341  _papi_hwi_derived_type( ( char * ) attr[3] );
1342  /* where does DERIVED POSTSCRIPT get encoded?? */
1343  if ( _papi_hwi_presets[sparse_index].data->derived == -1 ) {
1344  PAPIERROR( "No derived type match for %s in Preset XML file.",
1345  attr[3] );
1346  error = 1;
1347  }
1348 
1349  if ( attr[5] ) {
1350  _papi_hwi_presets[sparse_index].count = atoi( attr[5] );
1351  } else {
1352  PAPIERROR( "No count given for %s in Preset XML file.",
1353  attr[1] );
1354  error = 1;
1355  }
1356  } else {
1357  _papi_hwi_presets[sparse_index].data->derived = NOT_DERIVED;
1358  _papi_hwi_presets[sparse_index].count = 1;
1359  }
1360  location = DENSE_NATIVE_SEARCH;
1361  } else if ( location == DENSE_NATIVE_SEARCH && !strcmp( "native", el ) ) {
1362  location = DENSE_NATIVE_DESC;
1363  } else if ( location == DENSE_NATIVE_DESC && !strcmp( "event", el ) ) {
1364  if ( _papi_hwi_native_name_to_code( attr[1], &native_encoding ) !=
1365  PAPI_OK ) {
1366  printf( "Improper Native name given in XML file for %s\n",
1367  attr[1] );
1368  PAPIERROR( "Improper Native name given in XML file for %s",
1369  attr[1] );
1370  error = 1;
1371  }
1372  _papi_hwi_presets[sparse_index].data->native[native_index] =
1373  native_encoding;
1374  native_index++;
1375  _papi_hwi_presets[sparse_index].data->native[native_index] = PAPI_NULL;
1376  } else if ( location && location != ARCH_SEARCH && location != FINISHED ) {
1377  PAPIERROR( "Poorly-formed Preset XML document." );
1378  error = 1;
1379  }
1380 }
1381 
1382 /* The function below, _xml_end(), is a hook into expat's XML
1383  * parser. _xml_end() defines how the parser handles the
1384  * end tags in PAPI's XML file.
1385  */
1386 static void
1387 _xml_end( void *data, const char *el )
1388 {
1389  int i;
1390 
1391  if ( location == SPARSE_EVENT_SEARCH && !strcmp( "papistdevents", el ) ) {
1392  for ( i = sparse_index; i < PAPI_MAX_PRESET_EVENTS; i++ ) {
1393  _papi_hwi_presets[i].info.symbol = NULL;
1394  _papi_hwi_presets[i].info.long_descr = NULL;
1395  _papi_hwi_presets[i].info.short_descr = NULL;
1396  }
1397  location = ARCH_SEARCH;
1398  } else if ( location == DENSE_NATIVE_DESC && !strcmp( "native", el ) ) {
1399  location = DENSE_EVENT_SEARCH;
1400  } else if ( location == DENSE_EVENT_SEARCH && !strcmp( "availevents", el ) ) {
1401  location = FINISHED;
1402  }
1403 }
1404 
1405 /* The function below, _xml_content(), is a hook into expat's XML
1406  * parser. _xml_content() defines how the parser handles the
1407  * text between tags in PAPI's XML file. The information between
1408  * tags is usally text for event descriptions.
1409  */
1410 static void
1411 _xml_content( void *data, const char *el, const int len )
1412 {
1413  int i;
1414  if ( location == SPARSE_DESC ) {
1415  _papi_hwi_presets[sparse_index].info.long_descr =
1416  papi_malloc( len + 1 );
1417  for ( i = 0; i < len; i++ )
1418  _papi_hwi_presets[sparse_index].info.long_descr[i] = el[i];
1419  _papi_hwi_presets[sparse_index].info.long_descr[len] = '\0';
1420  /* the XML data currently doesn't contain a short description */
1421  _papi_hwi_presets[sparse_index].info.short_descr = NULL;
1422  sparse_index++;
1423  _papi_hwi_presets[sparse_index].data = NULL;
1424  location = SPARSE_EVENT_SEARCH;
1425  }
1426 }
1427 
1428 int
1429 _xml_papi_hwi_setup_all_presets( char *arch, hwi_dev_notes_t * notes )
1430 {
1431  int done = 0;
1432  FILE *fp = fopen( "./papi_events.xml", "r" );
1433  XML_Parser p = XML_ParserCreate( NULL );
1434 
1435  if ( !p ) {
1436  PAPIERROR( "Couldn't allocate memory for XML parser." );
1437  fclose(fp);
1438  return ( PAPI_ESYS );
1439  }
1440  XML_SetElementHandler( p, _xml_start, _xml_end );
1441  XML_SetCharacterDataHandler( p, _xml_content );
1442  if ( fp == NULL ) {
1443  PAPIERROR( "Error opening Preset XML file." );
1444  fclose(fp);
1445  return ( PAPI_ESYS );
1446  }
1447 
1448  xml_arch = arch;
1449 
1450  do {
1451  int len;
1452  void *buffer = XML_GetBuffer( p, BUFFSIZE );
1453 
1454  if ( buffer == NULL ) {
1455  PAPIERROR( "Couldn't allocate memory for XML buffer." );
1456  fclose(fp);
1457  return ( PAPI_ESYS );
1458  }
1459  len = fread( buffer, 1, BUFFSIZE, fp );
1460  if ( ferror( fp ) ) {
1461  PAPIERROR( "XML read error." );
1462  fclose(fp);
1463  return ( PAPI_ESYS );
1464  }
1465  done = feof( fp );
1466  if ( !XML_ParseBuffer( p, len, len == 0 ) ) {
1467  PAPIERROR( "Parse error at line %d:\n%s",
1468  XML_GetCurrentLineNumber( p ),
1469  XML_ErrorString( XML_GetErrorCode( p ) ) );
1470  fclose(fp);
1471  return ( PAPI_ESYS );
1472  }
1473  if ( error ) {
1474  fclose(fp);
1475  return ( PAPI_ESYS );
1476  }
1477  } while ( !done );
1478  XML_ParserFree( p );
1479  fclose( fp );
1480  return ( PAPI_OK );
1481 }
1482 #endif
char event_name[2][PAPI_MAX_STR_LEN]
Definition: data_range.c:29
#define PAPI_ENOEVNT
Definition: papi.h:260
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
#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
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
#define PAPI_NULL
Definition: papi.h:292
static char * trim_note(char *in)
Definition: papi_preset.c:197
static double array[ARRAYSIZE]
Definition: papi_l1_dca.c:23
#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:497
int count
Definition: iozone.c:22422
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
fclose(thread_wqfd)
void
Definition: iozone.c:18627
return PAPI_EINVAL
Definition: linux-nvml.c:436
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
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
papi_vector_t * _papi_hwd[]
#define PAPI_HUGE_STR_LEN
Definition: papi.h:467
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
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:947
static int cidx
#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
#define PAPI_EVENT_FILE
Definition: papi_preset.c:151
hwi_presets_t _papi_hwi_presets[PAPI_MAX_PRESET_EVENTS]
#define PAPI_ESYS
Definition: papi.h:255
int user_defined_events_count
Definition: papi_internal.c:60
#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:59
static int native
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
void PAPIERROR(char *format,...)
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
char * buffer
Definition: iozone.c:1366
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
int papi_num_components
printf("\tTry: -i 0 -i 1 \n\n")
sscanf(mnc->m_child_port,"%d",&mc.m_child_port)
#define PATH_MAX
Definition: fileop.c:68
static char * infix_to_postfix(char *infix)
Definition: papi_preset.c:839
char * name
Definition: iozone.c:23648
char * long_descr
Definition: papi_preset.h:26
static char stack[2 *PAPI_HUGE_STR_LEN]
Definition: papi_preset.c:791
int
Definition: iozone.c:18528
#define PAPI_MIN_STR_LEN
Definition: papi.h:464
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 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
int _xml_papi_hwi_setup_all_presets(char *arch)
static int preset
#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
pthread_attr_t attr
Definition: iozone.c:18466
int _papi_hwi_native_name_to_code(const char *in, int *out)
#define papi_calloc(a, b)
Definition: papi_memory.h:37
char * postfix
Definition: papi_preset.h:31