PAPI  5.4.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
native_avail.c
Go to the documentation of this file.
1 /* This file utility reports hardware info and native event availability */
45 #include "papi_test.h"
46 
47 #define EVT_LINE 80
48 #define EVT_LINE_BUF_SIZE 4096
49 
50 typedef struct command_flags
51 {
52  int help;
53  int details;
54  int named;
55  int include;
56  int xclude;
57  int validate;
58  char *name, *istr, *xstr;
59  int darr;
60  int dear;
61  int iarr;
62  int iear;
63  int opcm;
64  int umask;
65  int groups;
67 
68 static void
69 print_help( char **argv )
70 {
71  printf( "This is the PAPI native avail program.\n" );
72  printf( "It provides availability and detail information for PAPI native events.\n" );
73  printf( "Usage: %s [options]\n", argv[0] );
74  printf( "\nOptions:\n" );
75  printf( " --help, -h print this help message\n" );
76  printf( " -d display detailed information about native events\n" );
77  printf( " --validate attempts to add each event\n");
78  printf( " -e EVENTNAME display detailed information about named native event\n" );
79  printf( " -i EVENTSTR include only event names that contain EVENTSTR\n" );
80  printf( " -x EVENTSTR exclude any event names that contain EVENTSTR\n" );
81  printf( " --noumasks suppress display of Unit Mask information\n" );
82  printf( "\nProcessor-specific options\n");
83  printf( " --darr display events supporting Data Address Range Restriction\n" );
84  printf( " --dear display Data Event Address Register events only\n" );
85  printf( " --iarr display events supporting Instruction Address Range Restriction\n" );
86  printf( " --iear display Instruction Event Address Register events only\n" );
87  printf( " --opcm display events supporting OpCode Matching\n" );
88  printf( " --nogroups suppress display of Event grouping information\n" );
89  printf( "\n" );
90 }
91 
92 static int
93 no_str_arg( char *arg )
94 {
95  return ( ( arg == NULL ) || ( strlen( arg ) == 0 ) || ( arg[0] == '-' ) );
96 }
97 
98 static void
100 {
101  int i;
102 
103  /* Look for all currently defined commands */
104  memset( f, 0, sizeof ( command_flags_t ) );
105  f->umask = 1;
106  f->groups = 1;
107 
108  for ( i = 1; i < argc; i++ ) {
109  if ( !strcmp( argv[i], "--darr" ) )
110  f->darr = 1;
111  else if ( !strcmp( argv[i], "--dear" ) )
112  f->dear = 1;
113  else if ( !strcmp( argv[i], "--iarr" ) )
114  f->iarr = 1;
115  else if ( !strcmp( argv[i], "--iear" ) )
116  f->iear = 1;
117  else if ( !strcmp( argv[i], "--opcm" ) )
118  f->opcm = 1;
119  else if ( !strcmp( argv[i], "--noumasks" ) )
120  f->umask = 0;
121  else if ( !strcmp( argv[i], "--nogroups" ) )
122  f->groups = 0;
123  else if ( !strcmp( argv[i], "-d" ) )
124  f->details = 1;
125  else if ( !strcmp( argv[i], "-e" ) ) {
126  f->named = 1;
127  i++;
128  f->name = argv[i];
129  if ( i >= argc || no_str_arg( f->name ) ) {
130  printf( "Invalid argument for -e\n");
131  exit(1);
132  }
133  } else if ( !strcmp( argv[i], "-i" ) ) {
134  f->include = 1;
135  i++;
136  f->istr = argv[i];
137  if ( i >= argc || no_str_arg( f->istr ) ) {
138  printf( "Invalid argument for -i\n");
139  exit(1);
140  }
141  } else if ( !strcmp( argv[i], "-x" ) ) {
142  f->xclude = 1;
143  i++;
144  f->xstr = argv[i];
145  if ( i >= argc || no_str_arg( f->xstr ) ) {
146  printf( "Invalid argument for -x\n");
147  exit(1);
148  }
149  } else if ( !strcmp( argv[i], "-h" ) || !strcmp( argv[i], "--help" ) ) {
150  f->help = 1;
151  } else if ( !strcmp( argv[i], "--validate" ) ) {
152  f->validate = 1;
153  } else {
154  printf( "%s is not supported\n", argv[i] );
155  exit(1);
156  }
157  }
158 
159  /* if help requested, print and bail */
160  if ( f->help ) {
161  print_help( argv);
162  exit( 1 );
163  }
164 }
165 
166 static void
167 space_pad( char *str, int spaces )
168 {
169  while ( spaces-- > 0 )
170  strcat( str, " " );
171 }
172 
173 unsigned int event_available = 0;
174 unsigned int event_output_buffer_size = 0;
175 char *event_output_buffer = NULL;
176 
177 static void
179 {
180  int EventSet = PAPI_NULL;
181 
182  // if this event has already passed the validate test, no need to try this one again
183  if (event_available) {
184  return;
185  }
186 
187  if (PAPI_create_eventset (&EventSet) == PAPI_OK) {
188  if (PAPI_add_named_event (EventSet, info->symbol) == PAPI_OK) {
189  PAPI_remove_named_event (EventSet, info->symbol);
190  event_available = 1;
191  } // else printf("********** PAPI_add_named_event( %s ) failed: event could not be added \n", info->symbol);
192  if ( PAPI_destroy_eventset( &EventSet ) != PAPI_OK ) {
193  printf("********** Call to destroy eventset failed when trying to validate event '%s' **********\n", info->symbol);
194  }
195  }
196 
197  return;
198 }
199 
200 static void
202 {
203  unsigned int i, j = 0;
204  char event_line_buffer[EVT_LINE_BUF_SIZE];
205 
206  /* indent by offset */
207  if ( offset ) {
208  // this one is used for event masks
209  sprintf(event_line_buffer, "| %-73s|\n", info->symbol);
210  }
211  else {
212  // this one is used for new events
213  sprintf(event_line_buffer, "| %-73s%4s|\n", info->symbol, "<-->");
214  }
215 
216  while ( j <= strlen( info->long_descr ) ) {
217  // The event_line_buffer is used to collect an event or mask name and its description.
218  // The description will be folded to keep the length of output lines reasonable. So this
219  // buffer may contain multiple lines of print output. Check to make sure there is room
220  // for another line of print output. If there is not enough room for another output line
221  // just exit the loop and truncate the description field (the buffer is big enough this
222  // should not happen).
223  if ((EVT_LINE_BUF_SIZE - strlen(event_line_buffer)) < EVT_LINE) {
224  printf ("Event or mask description has been truncated.\n");
225  break;
226  }
227 
228  // get amount of description that will fit in an output line
229  i = EVT_LINE - 12 - 2;
230  // start of a description line
231  strcat(event_line_buffer,"| " );
232  // if we need to copy less than what fits in this line, move it and exit loop
233  if (i > strlen(&info->long_descr[j])) {
234  strcat( event_line_buffer, &info->long_descr[j]);
235  space_pad( event_line_buffer, i - strlen(&info->long_descr[j]));
236  strcat( event_line_buffer, "|\n" );
237  break;
238  }
239 
240  // move what will fit into the line then loop back to do the rest in a new line
241  int k = strlen(event_line_buffer);
242  strncat( event_line_buffer, &info->long_descr[j], i );
243  event_line_buffer[k+i] = '\0';
244  strcat( event_line_buffer, "|\n" );
245 
246  // bump index past what we copied
247  j += i;
248  }
249 
250  // get the amount of used space in the output buffer
251  int out_buf_used = 0;
252  if ((event_output_buffer_size > 0) && (event_output_buffer != NULL)) {
253  out_buf_used = strlen(event_output_buffer);
254  }
255 
256  // if this will not fit in output buffer, make it bigger
257  if (event_output_buffer_size < out_buf_used + strlen(event_line_buffer) + 1) {
258  if (event_output_buffer_size == 0) {
261  } else {
262  event_output_buffer_size += 1024;
264  }
265  }
266 
267  // make sure we got the memory we asked for
268  if (event_output_buffer == NULL) {
269  test_fail( __FILE__, __LINE__, "Allocation of output buffer memory failed.\n", errno );
270  }
271 
272  strcat(event_output_buffer, event_line_buffer);
273  return;
274 }
275 
276 static void
277 print_event_output(int val_flag)
278 {
279  // first we need to update the available flag at the beginning of the buffer
280  // this needs to reflect if this event name by itself or the event name with one of the masks worked
281  // if none of the combinations worked then we will show the event as not available
282  char *val_flag_ptr = strstr(event_output_buffer, "<-->");
283  if (val_flag_ptr != NULL) {
284  if ((val_flag) && (event_available == 0)) {
285  // event is not available, update the place holder (replace the <--> with <NA>)
286  *(val_flag_ptr+1) = 'N';
287  *(val_flag_ptr+2) = 'A';
288  } else {
289  event_available = 0; // reset this flag for next event
290  // event is available, just remove the place holder (replace the <--> with spaces)
291  *val_flag_ptr = ' ';
292  *(val_flag_ptr+1) = ' ';
293  *(val_flag_ptr+2) = ' ';
294  *(val_flag_ptr+3) = ' ';
295  }
296  }
297 
298  // now we can finally send this events output to the user
299  printf( "%s", event_output_buffer);
300 // printf( "--------------------------------------------------------------------------------\n" );
301 
302  event_output_buffer[0] = '\0'; // start the next event with an empty buffer
303  return;
304 }
305 
306 static int
308 {
309  char *pmask,*ptr;
310 
311  /* handle the PAPI component-style events which have a component:::event type */
312  if ((ptr=strstr(info->symbol, ":::"))) {
313  ptr+=3;
314  /* handle libpfm4-style events which have a pmu::event type event name */
315  } else if ((ptr=strstr(info->symbol, "::"))) {
316  ptr+=2;
317  }
318  else {
319  ptr=info->symbol;
320  }
321 
322  if ( ( pmask = strchr( ptr, ':' ) ) == NULL ) {
323  return ( 0 );
324  }
325  memmove( info->symbol, pmask, ( strlen(pmask) + 1 ) * sizeof(char) );
326 
327  // The description field contains the event description followed by a tag 'masks:'
328  // and then the mask description (if there was a mask with this event). The following
329  // code isolates the mask description part of this information.
330 
331  pmask = strstr( info->long_descr, "masks:" );
332  if ( pmask == NULL ) {
333  info->long_descr[0] = 0;
334  } else {
335  pmask += 6; // bump pointer past 'masks:' identifier in description
336  memmove( info->long_descr, pmask, (strlen(pmask) + 1) * sizeof(char) );
337  }
338  return ( 1 );
339 }
340 
341 int
342 main( int argc, char **argv )
343 {
344  int i, k;
345  int num_events;
346  int num_cmp_events = 0;
347  int retval;
348  PAPI_event_info_t info;
349  const PAPI_hw_info_t *hwinfo = NULL;
351  int enum_modifier;
352  int numcmp, cid;
353 
354  /* Set TESTS_QUIET variable */
355  tests_quiet( argc, argv );
356 
357  /* Initialize before parsing the input arguments */
359  if ( retval != PAPI_VER_CURRENT ) {
360  test_fail( __FILE__, __LINE__, "PAPI_library_init", retval );
361  }
362 
363  /* Parse the command-line arguments */
364  parse_args( argc, argv, &flags );
365 
366  /* Set enum modifier mask */
367  if ( flags.dear )
368  enum_modifier = PAPI_NTV_ENUM_DEAR;
369  else if ( flags.darr )
370  enum_modifier = PAPI_NTV_ENUM_DARR;
371  else if ( flags.iear )
372  enum_modifier = PAPI_NTV_ENUM_IEAR;
373  else if ( flags.iarr )
374  enum_modifier = PAPI_NTV_ENUM_IARR;
375  else if ( flags.opcm )
376  enum_modifier = PAPI_NTV_ENUM_OPCM;
377  else
378  enum_modifier = PAPI_ENUM_EVENTS;
379 
380 
381  if ( !TESTS_QUIET ) {
382  retval = PAPI_set_debug( PAPI_VERB_ECONT );
383  if ( retval != PAPI_OK ) {
384  test_fail( __FILE__, __LINE__, "PAPI_set_debug", retval );
385  }
386  }
387 
388  retval = papi_print_header( "Available native events and hardware information.\n", &hwinfo );
389  if ( retval != PAPI_OK ) {
390  test_fail( __FILE__, __LINE__, "PAPI_get_hardware_info", 2 );
391  }
392 
393  /* Do this code if the event name option was specified on the commandline */
394  if ( flags.named ) {
395  if ( PAPI_event_name_to_code( flags.name, &i ) == PAPI_OK ) {
396  if ( PAPI_get_event_info( i, &info ) == PAPI_OK ) {
397  printf( "Event name: %s\n", info.symbol);
398  printf( "Description: %s\n", info.long_descr );
399 
400  /* handle the PAPI component-style events which have a component:::event type */
401  char *ptr;
402  if ((ptr=strstr(flags.name, ":::"))) {
403  ptr+=3;
404  /* handle libpfm4-style events which have a pmu::event type event name */
405  } else if ((ptr=strstr(flags.name, "::"))) {
406  ptr+=2;
407  }
408  else {
409  ptr=flags.name;
410  }
411 
412  /* if unit masks exist but none specified, process all */
413  if ( !strchr( ptr, ':' ) ) {
414  if ( PAPI_enum_event( &i, PAPI_NTV_ENUM_UMASKS ) == PAPI_OK ) {
415  printf( "\nUnit Masks: Mask Name -- Description\n" );
416  do {
417  retval = PAPI_get_event_info( i, &info );
418  if ( retval == PAPI_OK ) {
419  if ( parse_unit_masks( &info ) ) {
420  printf( " Mask Info: %10s -- %s\n", info.symbol, info.long_descr );
421  }
422  }
423  } while ( PAPI_enum_event( &i, PAPI_NTV_ENUM_UMASKS ) == PAPI_OK );
424  }
425  }
426  }
427  } else {
428  printf("Sorry, an event by the name '%s' could not be found.\n",
429  flags.name);
430  printf("Is it typed correctly?\n\n");
431  exit( 1 );
432  }
433  test_pass( __FILE__, NULL, 0 );
434  exit( 0 );
435  }
436 
437  // Look at all the events and masks and print the information the user has asked for */
438 
439  numcmp = PAPI_num_components( );
440 
441  num_events = 0;
442 
443  for ( cid = 0; cid < numcmp; cid++ ) {
444  const PAPI_component_info_t *component;
445  component=PAPI_get_component_info(cid);
446 
447  /* Skip disabled components */
448  if (component->disabled) continue;
449 
450  printf( "===============================================================================\n" );
451  printf( " Native Events in Component: %s\n",component->name);
452  printf( "===============================================================================\n" );
453 
454  // show this component has not found any events yet
455  num_cmp_events = 0;
456 
457  /* Always ASK FOR the first event */
458  /* Don't just assume it'll be the first numeric value */
459  i = 0 | PAPI_NATIVE_MASK;
460 
461  retval=PAPI_enum_cmp_event( &i, PAPI_ENUM_FIRST, cid );
462 
463  if (retval==PAPI_OK) {
464  do {
465  memset( &info, 0, sizeof ( info ) );
466  retval = PAPI_get_event_info( i, &info );
467 
468  /* This event may not exist */
469  if ( retval != PAPI_OK ) continue;
470 
471  /* Bail if event name doesn't contain include string */
472  if ( flags.include && !strstr( info.symbol, flags.istr ) ) continue;
473 
474  /* Bail if event name does contain exclude string */
475  if ( flags.xclude && strstr( info.symbol, flags.xstr ) ) continue;
476 
477  // if not the first event in this component, put out a divider
478  if (num_cmp_events) {
479  printf( "--------------------------------------------------------------------------------\n" );
480  }
481 
482  /* count only events that are actually processed */
483  num_events++;
484  num_cmp_events++;
485 
486  if (flags.validate){
487  validate_event(&info);
488  }
489 
490  format_event_output( &info, 0);
491 
492  if (flags.details) {
493  if (info.units[0]) printf( "| Units: %-67s|\n",
494  info.units );
495  }
496 
497  /* modifier = PAPI_NTV_ENUM_GROUPS returns event codes with a
498  groups id for each group in which this
499  native event lives, in bits 16 - 23 of event code
500  terminating with PAPI_ENOEVNT at the end of the list.
501  */
502 
503  /* This is an IBM Power issue */
504  if ( flags.groups ) {
505  k = i;
506  if ( PAPI_enum_cmp_event( &k, PAPI_NTV_ENUM_GROUPS, cid ) == PAPI_OK ) {
507  printf( "Groups: " );
508  do {
509  printf( "%4d", ( ( k & PAPI_NTV_GROUP_AND_MASK ) >>
510  PAPI_NTV_GROUP_SHIFT ) - 1 );
511  } while ( PAPI_enum_cmp_event( &k, PAPI_NTV_ENUM_GROUPS, cid ) ==PAPI_OK );
512  printf( "\n" );
513  }
514  }
515 
516  // If the user has asked us to validate the events then we need to
517  // walk the list of masks and try to validate the event with each one.
518  // Even if the user does not want to display the masks this is necessary
519  // to be able to correctly report which events can be used on this system.
520  //
521  // We also need to walk the list if the user wants to see the masks.
522 
523  if (flags.umask || flags.validate){
524  k = i;
525  if ( PAPI_enum_cmp_event( &k, PAPI_NTV_ENUM_UMASKS, cid ) == PAPI_OK ) {
526  // clear event string using first mask
527  char first_event_mask_string[PAPI_HUGE_STR_LEN] = "";
528 
529  do {
530  retval = PAPI_get_event_info( k, &info );
531  if ( retval == PAPI_OK ) {
532  // if first event mask string not set yet, set it now
533  if (strlen(first_event_mask_string) == 0) {
534  strcpy (first_event_mask_string, info.symbol);
535  }
536 
537  if ( flags.validate ) {
538  validate_event(&info);
539  }
540  // now test if the masks should be displayed to the user
541  if ( flags.umask ) {
542  if ( parse_unit_masks( &info ) )
543  format_event_output( &info, 2);
544  }
545  }
546  } while ( PAPI_enum_cmp_event( &k, PAPI_NTV_ENUM_UMASKS, cid ) == PAPI_OK );
547  // if we are validating events and the event_available flag is not set yet, try a few more combinations
548  if (flags.validate && (event_available == 0)) {
549  // try using the event with the first mask defined for the event and the cpu mask
550  // this is a kludge but many of the uncore events require an event specific mask (usually
551  // the first one defined will do) and they all require the cpu mask
552  strcpy (info.symbol, first_event_mask_string);
553  strcat (info.symbol, ":cpu=1");
554  validate_event(&info);
555  }
556  if (flags.validate && (event_available == 0)) {
557  // an even bigger kludge is that there are 4 snpep_unc_pcu events which require the 'ff' and 'cpu' masks to work correctly.
558  // if nothing else has worked, this code will try those two masks with the current event name to see if it works
559  strcpy (info.symbol, first_event_mask_string);
560  char *wptr = strrchr (info.symbol, ':');
561  if (wptr != NULL) {
562  *wptr = '\0';
563  strcat (info.symbol, ":ff=64:cpu=1");
564  validate_event(&info);
565  }
566  }
567  }
568  }
570  } while (PAPI_enum_cmp_event( &i, enum_modifier, cid ) == PAPI_OK );
571  }
572  }
573 
574  if (num_cmp_events != 0) {
575  printf( "--------------------------------------------------------------------------------\n" );
576  }
577  printf( "\nTotal events reported: %d\n", num_events );
578 
579  test_pass( __FILE__, NULL, 0 );
580  exit( 0 );
581 }
static void print_event_output(int val_flag)
Definition: native_avail.c:277
char name[PAPI_MAX_STR_LEN]
Definition: papi.h:626
sprintf(splash[splash_line++],"\tIozone: Performance Test of File I/O\n")
memset(eventId, 0, size)
#define PAPI_NATIVE_MASK
int errno
double f(double a)
Definition: cpi.c:23
const PAPI_component_info_t * PAPI_get_component_info(int cidx)
Definition: papi.c:807
#define PAPI_VERB_ECONT
Definition: papi.h:387
Hardware info structure.
Definition: papi.h:777
long long flags
Definition: iozone.c:12330
#define EVT_LINE_BUF_SIZE
Definition: native_avail.c:48
unsigned int event_output_buffer_size
Definition: native_avail.c:174
int papi_print_header(char *prompt, const PAPI_hw_info_t **hwinfo)
Definition: test_utils.c:21
#define PAPI_NULL
Definition: papi.h:290
off64_t offset
Definition: iozone.c:1279
char long_descr[PAPI_HUGE_STR_LEN]
Definition: papi.h:966
int EventSet
Definition: data_range.c:25
int PAPI_num_components(void)
Definition: papi.c:4326
int num_events
int PAPI_enum_event(int *EventCode, int modifier)
Definition: papi.c:1150
char symbol[PAPI_HUGE_STR_LEN]
Definition: papi.h:963
return PAPI_OK
Definition: linux-nvml.c:458
tests_quiet(argc, argv)
static void space_pad(char *str, int spaces)
Definition: native_avail.c:167
#define printf
Definition: papi_test.h:125
static int no_str_arg(char *arg)
Definition: native_avail.c:93
test_pass(__FILE__, NULL, 0)
int int argc
Definition: iozone.c:1609
#define PAPI_HUGE_STR_LEN
Definition: papi.h:465
int PAPI_get_event_info(int EventCode, PAPI_event_info_t *info)
Definition: papi.c:846
add PAPI preset or native hardware event by name to an EventSet
int TESTS_QUIET
Definition: test_utils.c:11
char ** argv
Definition: iozone.c:1610
static void parse_args(int argc, char **argv, command_flags_t *f)
Definition: native_avail.c:99
test_fail(__FILE__, __LINE__,"PAPI_library_init", retval)
int PAPI_library_init(int version)
Definition: papi.c:497
Create a new empty PAPI EventSet.
int i
Definition: fileop.c:140
#define PAPI_NTV_GROUP_SHIFT
Definition: papi.h:524
int k
Definition: iozone.c:19136
static void print_help(char **argv)
Definition: native_avail.c:69
#define EVT_LINE
Definition: native_avail.c:47
strcat(command, mountname)
int PAPI_enum_cmp_event(int *EventCode, int modifier, int cidx)
Definition: papi.c:1324
strcpy(filename, default_filename)
int PAPI_event_name_to_code(char *in, int *out)
Definition: papi.c:1010
char * event_output_buffer
Definition: native_avail.c:175
char * help[]
Definition: iozone.c:129
#define PAPI_NTV_GROUP_AND_MASK
Definition: papi.h:523
char * name
Definition: iozone.c:23648
unsigned int event_available
Definition: native_avail.c:173
static int parse_unit_masks(PAPI_event_info_t *info)
Definition: native_avail.c:307
int PAPI_destroy_eventset(int *EventSet)
Definition: papi.c:1971
static void format_event_output(PAPI_event_info_t *info, int offset)
Definition: native_avail.c:201
static void validate_event(PAPI_event_info_t *info)
Definition: native_avail.c:178
long j
Definition: iozone.c:19135
ssize_t retval
Definition: libasync.c:338
#define PAPI_VER_CURRENT
Definition: papi.h:223
int PAPI_remove_named_event(int EventSet, char *EventName)
Definition: papi.c:1919
int main(int argc, char **argv)
List all appio events codes and names.
void exit()
char units[PAPI_MIN_STR_LEN]
Definition: papi.h:972
int PAPI_set_debug(int level)
Definition: papi.c:3070
char * ptr
Definition: iozone.c:23586