PAPI 7.1.0.0
Loading...
Searching...
No Matches
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
28
29static 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*/
43int
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;
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
113int
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
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 */
156static inline char *
157trim_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: () <> {} [] */
196static inline char *
197trim_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
224static 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 */
245static 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 */
272static int
273get_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".
303static void
304update_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[16];
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//
362static void
363ops_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.
463static void
464ops_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//
616static int
617check_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
703static int
704check_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
738static int
739is_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
768static char *papi_events_table = NULL;
769#endif
770
771int _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
791static char stack[2*PAPI_HUGE_STR_LEN]; // stack
792static int stacktop = -1; // stack length
793
794// priority: This function returns the priority of the operator
795static
796int 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
814static
815int 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
825static
826char 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 */
838static char *
839infix_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
946static int
947papi_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;
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
1314char buffer[BUFFSIZE], *xml_arch;
1315int 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 */
1325static 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 */
1409static 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 */
1433static 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
1451int
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
double tmp
int i
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
Definition: appio.c:279
static long count
Convert a name to a numeric hardware event code.
struct papi_vectors * _papi_hwd[]
char event_name[2][PAPI_MAX_STR_LEN]
Definition: data_range.c:29
#define PAPI_OK
Definition: f90papi.h:73
#define PAPI_MIN_STR_LEN
Definition: f90papi.h:208
#define PAPI_NULL
Definition: f90papi.h:78
#define PAPI_ENOEVNT
Definition: f90papi.h:139
#define PAPI_EINVAL
Definition: f90papi.h:115
#define PAPI_ESYS
Definition: f90papi.h:136
#define PAPI_HUGE_STR_LEN
Definition: f90papi.h:120
static struct timeval start
uint16_t location
uint16_t type
#define PAPI_UE_MASK
#define PAPI_MAX_USER_EVENTS
#define PAPI_PRESET_MASK
#define PAPI_PRESET_AND_MASK
#define PAPI_MAX_PRESET_EVENTS
Return codes and api definitions.
hwi_presets_t _papi_hwi_presets[PAPI_MAX_PRESET_EVENTS]
#define INTDBG(format, args...)
Definition: papi_debug.h:66
#define SUBDBG(format, args...)
Definition: papi_debug.h:64
int fclose(FILE *__stream)
void PAPIERROR(char *format,...)
int _papi_hwi_derived_type(char *tmp, int *code)
int _papi_hwi_native_name_to_code(const char *in, int *out)
int _papi_hwi_component_index(int event_code)
int papi_num_components
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
#define PAPI_EVENTS_IN_DERIVED_EVENT
#define DERIVED_POSTFIX
Definition: papi_internal.h:74
#define DERIVED_INFIX
Definition: papi_internal.h:75
#define NOT_DERIVED
Definition: papi_internal.h:68
#define DERIVED_SUB
Definition: papi_internal.h:73
#define DERIVED_ADD
Definition: papi_internal.h:69
static double array[ARRAYSIZE]
Definition: papi_l1_dca.c:23
#define papi_valid_free(a)
Definition: papi_memory.h:38
#define papi_calloc(a, b)
Definition: papi_memory.h:37
#define papi_free(a)
Definition: papi_memory.h:35
#define papi_strdup(a)
Definition: papi_memory.h:39
#define papi_malloc(a)
Definition: papi_memory.h:34
static FILE * fp
static int push(char symbol)
Definition: papi_preset.c:815
static int check_native_events(char *target, hwi_presets_t *results)
Definition: papi_preset.c:704
static void ops_string_merge(char **original, char *insertion, int replaces, int start_index)
Definition: papi_preset.c:464
static void update_ops_string(char **formula, int old_index, int new_index)
Definition: papi_preset.c:304
int _papi_hwi_cleanup_all_presets(void)
Definition: papi_preset.c:114
static char stack[2 *PAPI_HUGE_STR_LEN]
Definition: papi_preset.c:791
static int is_event(char *event_name, int derived_type, hwi_presets_t *results, int token_index)
Definition: papi_preset.c:739
static char * papi_events_table
Definition: papi_preset.c:768
static char * infix_to_postfix(char *infix)
Definition: papi_preset.c:839
int _papi_hwi_setup_all_presets(hwi_search_t *findem, int cidx)
Definition: papi_preset.c:44
static int get_event_line(char *line, FILE *table, char **tmp_perfmon_events_table)
Definition: papi_preset.c:273
static void ops_string_append(hwi_presets_t *results, hwi_presets_t *depends_on, int addition)
Definition: papi_preset.c:363
int _papi_load_preset_table(char *pmu_str, int pmu_type, int cidx)
Definition: papi_preset.c:771
static int stacktop
Definition: papi_preset.c:792
hwi_presets_t user_defined_events[]
Definition: papi_internal.c:59
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 int papi_load_derived_events(char *pmu_str, int pmu_type, int cidx, int preset_flag)
Definition: papi_preset.c:947
static int priority(char symbol)
Definition: papi_preset.c:796
int user_defined_events_count
Definition: papi_internal.c:60
#define PAPI_EVENT_FILE
Definition: papi_preset.c:151
static char * trim_string(char *in)
Definition: papi_preset.c:157
static char * trim_note(char *in)
Definition: papi_preset.c:197
static int find_event_index(hwi_presets_t *array, int size, char *tmp)
Definition: papi_preset.c:225
static char pop()
Definition: papi_preset.c:826
static FILE * open_event_table(char *name)
Definition: papi_preset.c:246
int _xml_papi_hwi_setup_all_presets(char *arch)
static void work(int EventSet, int sleep_test, int quiet)
Definition: papi_ref_cyc.c:56
static int preset
static int native
static int cidx
hwi_search_t * preset_search_map
static const int event_count[]
const char * name
Definition: rocs.c:225
int
Definition: sde_internal.h:89
char * symbol
Definition: papi_preset.h:24
unsigned int code[PAPI_MAX_INFO_TERMS]
Definition: papi_preset.h:32
unsigned int count
Definition: papi_preset.h:29
char * postfix
Definition: papi_preset.h:31
char * short_descr
Definition: papi_preset.h:25
char * name[PAPI_MAX_INFO_TERMS]
Definition: papi_preset.h:33
char * long_descr
Definition: papi_preset.h:26
unsigned int event_code
Definition: papi_preset.h:14
int native[PAPI_EVENTS_IN_DERIVED_EVENT]
Definition: papi_preset.h:16
static int get_events(ntv_event_t *events, int num_events)
int retval
Definition: zero_fork.c:53