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