// Define the papi_avail man page contents.
/**
  * file papi_avail.c
  *	@brief papi_avail utility.
  * @page papi_avail
  *	@section Name
  *	papi_avail - provides availability and detailed information for PAPI preset and user defined events.
  *
  *	@section Synopsis
  *	papi_avail [-adht] [-e event]
  *
  *	@section Description
  *	papi_avail is a PAPI utility program that reports information about the 
  *	current PAPI installation and supported preset and user defined events.
  *
  *	@section Options
  * <ul>
  *		<li>-h	Display help information about this utility.
  *		<li>-a	Display only the available PAPI events.
  *     <li>-c  Display only the available PAPI events after a check.
  *		<li>-d	Display PAPI event information in a more detailed format.
  *		<li>-e < event >	Display detailed event information for the named event. 
  *			This event can be a preset event, a user defined event, or a native event.
  *			If the event is a preset or a user defined event the output shows a list of native
  *			events the event is based on and the formula that is used to compute the events final value.\n
  *	</ul>
  *
  * Event filtering options 
  * <ul>
  *     <li>--br        Display branch related PAPI preset events
  *     <li>--cache     Display cache related PAPI preset events
  *     <li>--cnd       Display conditional PAPI preset events
  *     <li>--fp        Display Floating Point related PAPI preset events
  *     <li>--ins       Display instruction related PAPI preset events
  *     <li>--idl       Display Stalled or Idle PAPI preset events
  *     <li>--l1        Display level 1 cache related PAPI preset events
  *     <li>--l2        Display level 2 cache related PAPI preset events
  *     <li>--l3        Display level 3 cache related PAPI preset events
  *     <li>--mem       Display memory related PAPI preset events
  *     <li>--msc       Display miscellaneous PAPI preset events
  *     <li>--tlb       Display Translation Lookaside Buffer PAPI preset events
  * </ul>
  *	@section Bugs
  *	There are no known bugs in this utility.
  *	If you find a bug, it should be reported to the PAPI Mailing List at <ptools-perfapi@icl.utk.edu>.
  * <br>
  *	@see PAPI_derived_event_files
  *
  */

// Define the PAPI_derived_event_files man page contents.
/**
 *	@page PAPI_derived_event_files
 *	@brief Describes derived event definition file syntax.
 *
 *	@section main Derived Events
 *		PAPI provides the ability to define events whose value will be derived from multiple native events.  The list of native
 *		events to be used in a derived event and a formula which describes how to use them is provided in an event definition file.
 *		The PAPI team provides an event definition file which describes all of the supported PAPI preset events.  PAPI also allows
 *		a user to provide an event definition file that describes a set of user defined events which can extend the events PAPI
 *		normally supports.
 *
 *		This page documents the syntax of the commands which can appear in an event definition file.
 *
 * <br>
 *	@subsection rules General Rules:
 *	<ul>
 *		<li>Blank lines are ignored.</li>
 *		<li>Lines that begin with '#' are comments (they are also ignored).</li>
 *		<li>Names shown inside < > below represent values that must be provided by the user.</li>
 *		<li>If a user provided value contains white space, it must be protected with quotes.</li>
 *	</ul>
 *
 * <br>
 *	@subsection commands Commands:
 *		@par CPU,\<pmuName\>
 *		Specifies a PMU name which controls if the PRESET and EVENT commands that follow this line should
 *		be processed.  Multiple CPU commands can be entered without PRESET or EVENT commands between them to provide
 *		a list of PMU names to which the derived events that follow will apply.  When a PMU name provided in the list
 *		matches a PMU name known to the running system, the events which follow will be created.  If none of the PMU
 *		names provided in the list match a PMU name on the running system, the events which follow will be ignored.
 *		When a new CPU command follows either a PRESET or EVENT command, the PMU list is rebuilt.<br><br>
 *
 *		@par PRESET,\<eventName\>,\<derivedType\>,\<eventAttr\>,LDESC,\"\<longDesc\>\",SDESC,\"\<shortDesc\>\",NOTE,\"\<note\>\"
 *		Declare a PAPI preset derived event.<br><br>
 *
 *		@par EVENT,\<eventName\>,\<derivedType\>,\<eventAttr\>,LDESC,\"\<longDesc\>\",SDESC,\"\<shortDesc\>\",NOTE,\"\<note\>\"
 *		Declare a user defined derived event.<br><br>
 *
 *		@par Where:
 *		@par pmuName:
 *			The PMU which the following events should apply to.  A list of PMU names supported by your
 *			system can be obtained by running papi_component_avail on your system.<br>
 *		@par eventName:
 *			Specifies the name used to identify this derived event.  This name should be unique within the events on your system.<br>
 *		@par derivedType:
 *			Specifies the kind of derived event being defined (see 'Derived Types' below).<br>
 *		@par eventAttr:
 *			Specifies a formula and a list of base events that are used to compute the derived events value.  The syntax
 *			of this field depends on the 'derivedType' specified above (see 'Derived Types' below).<br>
 *		@par longDesc:
 *			Provides the long description of the event.<br>
 *		@par shortDesc:
 *			Provides the short description of the event.<br>
 *		@par note:
 *			Provides an event note.<br>
 *		@par baseEvent (used below):
 *			Identifies an event on which this derived event is based.  This may be a native event (possibly with event masks),
 *			an already known preset event, or an already known user event.<br>
 *
 * <br>
 *	@subsection notes Notes:
 *		The PRESET command has traditionally been used in the PAPI provided preset definition file.
 *		The EVENT command is intended to be used in user defined event definition files.  The code treats them
 *		the same so they are interchangeable and they can both be used in either event definition file.<br>
 *
 * <br>
 *	@subsection types Derived Types:
 *		This describes values allowed in the 'derivedType' field of the PRESET and EVENT commands.  It also
 *		shows the syntax of the 'eventAttr' field for each derived type supported by these commands.
 *		All of the derived events provide a list of one or more events which the derived event is based
 *		on (baseEvent).  Some derived events provide a formula that specifies how to compute the derived
 *		events value using the baseEvents in the list.  The following derived types are supported, the syntax
 *		of the 'eventAttr' parameter for each derived event type is shown in parentheses.<br><br>
 *
 *		@par NOT_DERIVED (\<baseEvent\>):
 *			This derived type defines an alias for the existing event 'baseEvent'.<br>
 *		@par DERIVED_ADD (\<baseEvent1\>,\<baseEvent2\>):
 *			This derived type defines a new event that will be the sum of two other
 *			events.  It has a value of 'baseEvent1' plus 'baseEvent2'.<br>
 *		@par DERIVED_PS (PAPI_TOT_CYC,\<baseEvent1\>):
 *			This derived type defines a new event that will report the number of 'baseEvent1' events which occurred
 *			per second.  It has a value of ((('baseEvent1' * cpu_max_mhz) * 1000000 ) / PAPI_TOT_CYC).  The user must
 *			provide PAPI_TOT_CYC as the first event of two events in the event list for this to work correctly.<br>
 *		@par DERIVED_ADD_PS (PAPI_TOT_CYC,\<baseEvent1\>,\<baseEvent2\>):
 *			This derived type defines a new event that will add together two event counters and then report the number
 *			which occurred per second.  It has a value of (((('baseEvent1' + baseEvent2) * cpu_max_mhz) * 1000000 ) / PAPI_TOT_CYC).
 *			The user must provide PAPI_TOT_CYC as the first event of three events in the event list for this to work correctly.<br>
 *		@par DERIVED_CMPD (\<baseEvent1\>,\<baseEvent2\):
 *			This derived type works much like the NOT_DERIVED type.  It is rarely used and it looks like the code just returns
 *			a single value returned from the kernel.  There is no calculation done to compute this events value.  Not sure why
 *			multiple input events seem to be needed to use this event type.<br>
 *		@par DERIVED_SUB (\<baseEvent1\>,\<baseEvent2\>):
 *			This derived type defines a new event that will be the difference between two other
 *			events.  It has a value of 'baseEvent1' minus 'baseEvent2'.<br>
 *		@par DERIVED_POSTFIX (\<pfFormula\>,\<baseEvent1\>,\<baseEvent2\>, ... ,\<baseEventn\>):
 *			This derived type defines a new event whose value is computed from several native events using
 *			a postfix (reverse polish notation) formula.  Its value is the result of processing the postfix
 *			formula.  The 'pfFormula' is of the form 'N0|N1|N2|5|*|+|-|' where the '|' acts as a token
 *			separator and the tokens N0, N1, and N2 are place holders that represent baseEvent0, baseEvent1,
 *			and baseEvent2 respectively.<br>
 *		@par DERIVED_INFIX (\<ifFormula\>,\<baseEvent1\>,\<baseEvent2\>, ... ,\<baseEventn\>):
 *			This derived type defines a new event whose value is computed from several native events using
 *			an infix (algebraic notation) formula.  Its value is the result of processing the infix
 *			formula.  The 'ifFormula' is of the form 'N0-(N1+(N2*5))' where the tokens N0, N1, and N2
 *			are place holders that represent baseEvent0, baseEvent1, and baseEvent2 respectively.<br>
 *
 * <br>
 *	@subsection example Example:
 *		In the following example, the events PAPI_SP_OPS, USER_SP_OPS, and ALIAS_SP_OPS will all measure the same events and return
 *		the same value.  They just demonstrate different ways to use the PRESET and EVENT event definition commands.<br><br>
 *
 *		<ul>
 *			<li># The following lines define pmu names that all share the following events</li>
 *			<li>CPU nhm</li>
 *			<li>CPU nhm-ex</li>
 *			<li>\# Events which should be defined for either of the above pmu types</li>
 *			<li>PRESET,PAPI_TOT_CYC,NOT_DERIVED,UNHALTED_CORE_CYCLES</li>
 *			<li>PRESET,PAPI_REF_CYC,NOT_DERIVED,UNHALTED_REFERENCE_CYCLES</li>
 *			<li>PRESET,PAPI_SP_OPS,DERIVED_POSTFIX,N0|N1|3|*|+|,FP_COMP_OPS_EXE:SSE_SINGLE_PRECISION,FP_COMP_OPS_EXE:SSE_FP_PACKED,NOTE,"Using a postfix formula"</li>
 *			<li>EVENT,USER_SP_OPS,DERIVED_INFIX,N0+(N1*3),FP_COMP_OPS_EXE:SSE_SINGLE_PRECISION,FP_COMP_OPS_EXE:SSE_FP_PACKED,NOTE,"Using the same formula in infix format"</li>
 *			<li>EVENT,ALIAS_SP_OPS,NOT_DERIVED,PAPI_SP_OPS,LDESC,"Alias for preset event PAPI_SP_OPS"</li>
 *			<li># End of event definitions for above pmu names and start of a section for a new pmu name.</li>
 *			<li>CPU snb</li>
 *		</ul>
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "papi.h"
#include "print_header.h"

static char *
is_derived( PAPI_event_info_t * info )
{
	if ( strlen( info->derived ) == 0 )
		return ( "No" );
	else if ( strcmp( info->derived, "NOT_DERIVED" ) == 0 )
		return ( "No" );
	else if ( strcmp( info->derived, "DERIVED_CMPD" ) == 0 )
		return ( "No" );
	else
		return ( "Yes" );
}

static void
print_help( char **argv )
{
        printf( "This is the PAPI avail program.\n" );
        printf( "It provides availability and details about PAPI Presets and User-defined Events.\n" );
	printf( "PAPI Preset Event filters can be combined in a logical OR.\n" );
	printf( "Usage: %s [options]\n", argv[0] );
	printf( "Options:\n\n" );
	printf( "General command options:\n" );
	printf( "\t-h, --help       Print this help message\n" );
	printf( "\t-a, --avail      Display only available PAPI preset and user defined events\n" );
	printf( "\t-c, --check      Display only available PAPI preset and user defined events after an availability check\n" );
	printf( "\t-d, --detail     Display detailed information about events\n" );
	printf( "\t-e EVENTNAME     Display detail information about specified event\n" );
	printf( "\nEvent filtering options:\n" );
	printf( "\t--br             Display branch related PAPI preset events\n" );
	printf( "\t--cache          Display cache related PAPI preset events\n" );
	printf( "\t--cnd            Display conditional PAPI preset events\n" );
	printf( "\t--fp             Display Floating Point related PAPI preset events\n" );
	printf( "\t--ins            Display instruction related PAPI preset events\n" );
	printf( "\t--idl            Display Stalled or Idle PAPI preset events\n" );
	printf( "\t--l1             Display level 1 cache related PAPI preset events\n" );
	printf( "\t--l2             Display level 2 cache related PAPI preset events\n" );
	printf( "\t--l3             Display level 3 cache related PAPI preset events\n" );
	printf( "\t--mem            Display memory related PAPI preset events\n" );
	printf( "\t--msc            Display miscellaneous PAPI preset events\n" );
	printf( "\t--tlb            Display Translation Lookaside Buffer PAPI preset events\n" );
	printf( "\n" );
}

static int
parse_unit_masks( PAPI_event_info_t * info )
{
	char *pmask;

	if ( ( pmask = strchr( info->symbol, ':' ) ) == NULL ) {
		return ( 0 );
	}
	memmove( info->symbol, pmask, ( strlen( pmask ) + 1 ) * sizeof ( char ) );
	pmask = strchr( info->long_descr, ':' );
	if ( pmask == NULL )
		info->long_descr[0] = 0;
	else
		memmove( info->long_descr, pmask + sizeof ( char ),
				 ( strlen( pmask ) + 1 ) * sizeof ( char ) );
	return 1;
}

static int
checkCounter (int eventcode)
{
	int EventSet = PAPI_NULL;
	if (PAPI_create_eventset(&EventSet) != PAPI_OK)
		return 0;
	if (PAPI_add_event (EventSet, eventcode) != PAPI_OK)
		return 0;
	if (PAPI_cleanup_eventset (EventSet) != PAPI_OK)
		return 0;
	if (PAPI_destroy_eventset (&EventSet) != PAPI_OK)
		return 0;
	return 1;
}

int
main( int argc, char **argv )
{
   int args, i, j, k;
   int retval;
   unsigned int filter = 0;
   int print_event_info = 0;
   char *name = NULL;
   int print_avail_only = PAPI_ENUM_EVENTS;
   int print_tabular = 1;
   PAPI_event_info_t info;
   const PAPI_hw_info_t *hwinfo = NULL;
   int tot_count = 0;
   int avail_count = 0;
   int deriv_count = 0;
   int check_counter = 0;
   int event_code;

   PAPI_event_info_t n_info;

   /* Parse command line arguments */

   for( args = 1; args < argc; args++ ) {
      if ( strstr( argv[args], "-e" ) ) {
	 print_event_info = 1;
	 name = argv[args + 1];
	 if ( ( name == NULL ) || ( strlen( name ) == 0 ) ) {
	    print_help( argv );
	    exit( 1 );
	 }
      }
      else if ( strstr( argv[args], "-c" ) || strstr (argv[args], "--check") )
      {
	 print_avail_only = PAPI_PRESET_ENUM_AVAIL;
         check_counter = 1;
      }
      else if ( strstr( argv[args], "-a" ))
	 print_avail_only = PAPI_PRESET_ENUM_AVAIL;
      else if ( strstr( argv[args], "-d" ) )
	 print_tabular = 0;
      else if ( strstr( argv[args], "-h" ) ) {
	 print_help( argv );
	 exit( 1 );
      } else if ( strstr( argv[args], "--br" ) )
	 filter |= PAPI_PRESET_BIT_BR;
      else if ( strstr( argv[args], "--cache" ) )
	 filter |= PAPI_PRESET_BIT_CACH;
      else if ( strstr( argv[args], "--cnd" ) )
	 filter |= PAPI_PRESET_BIT_CND;
      else if ( strstr( argv[args], "--fp" ) )
	 filter |= PAPI_PRESET_BIT_FP;
      else if ( strstr( argv[args], "--ins" ) )
	 filter |= PAPI_PRESET_BIT_INS;
      else if ( strstr( argv[args], "--idl" ) )
	 filter |= PAPI_PRESET_BIT_IDL;
      else if ( strstr( argv[args], "--l1" ) )
	 filter |= PAPI_PRESET_BIT_L1;
      else if ( strstr( argv[args], "--l2" ) )
	 filter |= PAPI_PRESET_BIT_L2;
      else if ( strstr( argv[args], "--l3" ) )
	 filter |= PAPI_PRESET_BIT_L3;
      else if ( strstr( argv[args], "--mem" ) )
	 filter |= PAPI_PRESET_BIT_BR;
      else if ( strstr( argv[args], "--msc" ) )
	 filter |= PAPI_PRESET_BIT_MSC;
      else if ( strstr( argv[args], "--tlb" ) )
	 filter |= PAPI_PRESET_BIT_TLB;
   }

   if ( filter == 0 ) {
      filter = ( unsigned int ) ( -1 );
   }

   /* Init PAPI */

   retval = PAPI_library_init( PAPI_VER_CURRENT );
   if ( retval != PAPI_VER_CURRENT ) {
	fprintf(stderr,"Error!  PAPI library mismatch!\n");
	return 1;
   }


	retval = PAPI_set_debug( PAPI_VERB_ECONT );
	if ( retval != PAPI_OK ) {
		fprintf(stderr,"Error with PAPI_set debug!\n");
		return 1;
	}

      retval=papi_print_header("Available PAPI preset and user defined events plus hardware information.\n",
			       &hwinfo );
	if ( retval != PAPI_OK ) {
		fprintf(stderr,"Error with PAPI_get_hardware_info!\n");
		return 1;
	}

      /* Code for info on just one event */

      if ( print_event_info ) {

	 if ( PAPI_event_name_to_code( name, &event_code ) == PAPI_OK ) {
	    if ( PAPI_get_event_info( event_code, &info ) == PAPI_OK ) {

	       if ( event_code & PAPI_PRESET_MASK ) {
		  printf( "%-30s%s\n%-30s%#-10x\n%-30s%d\n",
			  "Event name:", info.symbol, "Event Code:",
			  info.event_code, "Number of Native Events:",
			  info.count );
		  printf( "%-29s|%s|\n%-29s|%s|\n%-29s|%s|\n",
			  "Short Description:", info.short_descr,
			  "Long Description:", info.long_descr,
			  "Developer's Notes:", info.note );
		  printf( "%-29s|%s|\n%-29s|%s|\n", "Derived Type:",
			  info.derived, "Postfix Processing String:",
			  info.postfix );

		  for( j = 0; j < ( int ) info.count; j++ ) {
		     printf( " Native Code[%d]: %#x |%s|\n", j,
			     info.code[j], info.name[j] );
		     PAPI_get_event_info( (int) info.code[j], &n_info );
		     printf(" Number of Register Values: %d\n", n_info.count );
		     for( k = 0; k < ( int ) n_info.count; k++ ) {
			printf( " Register[%2d]: %#08x |%s|\n", k,
				n_info.code[k], n_info.name[k] );
		     }
		     printf( " Native Event Description: |%s|\n\n",
			     n_info.long_descr );
		  }
	       } else {	 /* must be a native event code */
		  printf( "%-30s%s\n%-30s%#-10x\n%-30s%d\n",
			  "Event name:", info.symbol, "Event Code:",
			  info.event_code, "Number of Register Values:",
			  info.count );
		  printf( "%-29s|%s|\n", "Description:", info.long_descr );
		  for ( k = 0; k < ( int ) info.count; k++ ) {
		      printf( " Register[%2d]: %#08x |%s|\n", k,
			      info.code[k], info.name[k] );
		  }

		  /* if unit masks exist but none are specified, process all */
		  if ( !strchr( name, ':' ) ) {
		     if ( 1 ) {
			if ( PAPI_enum_event( &event_code, PAPI_NTV_ENUM_UMASKS ) == PAPI_OK ) {
			   printf( "\nUnit Masks:\n" );
			   do {
			      retval = PAPI_get_event_info(event_code, &info );
			      if ( retval == PAPI_OK ) {
				 if ( parse_unit_masks( &info ) ) {
				    printf( "%-29s|%s|%s|\n",
					    " Mask Info:", info.symbol,
					    info.long_descr );
				    for ( k = 0; k < ( int ) info.count;k++ ) {
					printf( "  Register[%2d]:  %#08x  |%s|\n",
						k, info.code[k], info.name[k] );
				    }
				 }
			      }
			   } while ( PAPI_enum_event( &event_code,
					  PAPI_NTV_ENUM_UMASKS ) == PAPI_OK );
			}
		     }
		  }
	       }
	    }
	 } else {
	    printf( "Sorry, an event by the name '%s' could not be found.\n"
                    " Is it typed correctly?\n\n", name );
	 }
      } else {

	 /* Print *ALL* Events */

  for (i=0 ; i<2 ; i++) {
	// set the event code to fetch preset events the first time through loop and user events the second time through the loop
	if (i== 0) {
		event_code = 0 | PAPI_PRESET_MASK;
	} else {
		event_code = 0 | PAPI_UE_MASK;
	}

	/* For consistency, always ASK FOR the first event, if there is not one then nothing to process */
	if (PAPI_enum_event( &event_code, PAPI_ENUM_FIRST ) != PAPI_OK) {
		 continue;
	}

	// print heading to show which kind of events follow
	if (i== 0) {
		printf( "================================================================================\n" );
		printf( "  PAPI Preset Events\n" );
		printf( "================================================================================\n" );
	} else {
		printf( "\n");       // put a blank line after the presets before strarting the user events
		printf( "================================================================================\n" );
		printf( "  User Defined Events\n" );
		printf( "================================================================================\n" );
	}

	 if ( print_tabular ) {
	    printf( "    Name        Code    " );
	    if ( !print_avail_only ) {
	       printf( "Avail " );
	    }
	    printf( "Deriv Description (Note)\n" );
	 } else {
	    printf( "%-13s%-11s%-8s%-16s\n |Long Description|\n"
                    " |Developer's Notes|\n |Derived|\n |PostFix|\n"
                    " Native Code[n]: <hex> |name|\n",
		    "Symbol", "Event Code", "Count", "|Short Description|" );
	 }
	 do {
	    if ( PAPI_get_event_info( event_code, &info ) == PAPI_OK ) {
	       if ( print_tabular ) {
	      // if this is a user defined event or its a preset and matches the preset event filters, display its information
		  if ( (i==1) || (filter & info.event_type)) {
		     if ( print_avail_only ) {
		        if ( info.count ) {
                   if ( (check_counter && checkCounter (event_code)) || !check_counter)
                   {
                      printf( "%-13s%#x  %-5s%s",
                         info.symbol,
                         info.event_code,
                         is_derived( &info ), info.long_descr );
                   }
			}
		        if ( info.note[0] ) {
			   printf( " (%s)", info.note );
			}
			printf( "\n" );
		     } else {
			printf( "%-13s%#x  %-6s%-4s %s",
				info.symbol,
				info.event_code,
				( info.count ? "Yes" : "No" ),
				is_derived( &info ), info.long_descr );
			if ( info.note[0] ) {
			   printf( " (%s)", info.note );
			}
			printf( "\n" );
		     }
		     tot_count++;
		     if ( info.count ) {
	            if ((check_counter && checkCounter (event_code)) || !check_counter )
	              avail_count++;
		     }
		     if ( !strcmp( is_derived( &info ), "Yes" ) ) {
			deriv_count++;
		     }
		  }
	       } else {
		  if ( ( print_avail_only && info.count ) ||
		       ( print_avail_only == 0 ) )
	      {
	         if ((check_counter && checkCounter (event_code)) || !check_counter)
	         {
	           printf( "%s\t%#x\t%d\t|%s|\n |%s|\n"
			     " |%s|\n |%s|\n |%s|\n",
			     info.symbol, info.event_code, info.count,
			     info.short_descr, info.long_descr, info.note,
			     info.derived, info.postfix );
	           for ( j = 0; j < ( int ) info.count; j++ ) {
	              printf( " Native Code[%d]: %#x |%s|\n", j,
	              info.code[j], info.name[j] );
	           }
             }
		  }
		  tot_count++;
		  if ( info.count ) {
	         if ((check_counter && checkCounter (event_code)) || !check_counter )
		        avail_count++;
		  }
		  if ( !strcmp( is_derived( &info ), "Yes" ) ) {
		     deriv_count++;
		  }
	       }
	    }
	 } while (PAPI_enum_event( &event_code, print_avail_only ) == PAPI_OK);
  }
      }
      printf( "--------------------------------------------------------------------------------\n" );
      if ( !print_event_info ) {
	 if ( print_avail_only ) {
	    printf( "Of %d available events, %d ", avail_count, deriv_count );
	 } else {
	    printf( "Of %d possible events, %d are available, of which %d ",
		    tot_count, avail_count, deriv_count );
	 }
	 if ( deriv_count == 1 ) {
	    printf( "is derived.\n\n" );
	 } else {
	    printf( "are derived.\n\n" );
	 }
      }

	return 0;

}
