|
  PAPIC:Component Development Cookbook
| |
ViewsFrom PAPIDocs
PAPI-C Component Development CookbookGeneral Flow of Implementation
Example of ImplementationA working component example: Head/************************* INCLUDES SECTION ********************************* *******************************************************************************/ /* Headers required by PAPI */ #include "papi.h" #include "papi_internal.h" #include "papi_vector.h" #include "papi_memory.h" #include <stdio.h> #include <string.h> #include <stdlib.h>
/************************* DEFINES SECTION ***********************************
*******************************************************************************/
/* this number assumes that there will never be more events than indicated */
#define DUMMY_MAX_COUNTERS 8
/* Structure that stores private information of each event */
typedef struct DUMMY_register {
/* This is used by the framework.It likes it to be !=0 to do somehting*/
unsigned int selector;
} DUMMY_register_t;
/*
* The following structures mimic the ones used by other components. It is more
* convenient to use them like that as programming with PAPI makes specific
* assumptions for them.
*/
/* This structure is used to build the table of events */
typedef struct DUMMY_native_event_entry {
DUMMY_register_t resources;
char name[PAPI_MAX_STR_LEN];
char description[PAPI_MAX_STR_LEN];
} DUMMY_native_event_entry_t;
typedef struct DUMMY_reg_alloc {
DUMMY_register_t ra_bits;
} DUMMY_reg_alloc_t;
typedef struct DUMMY_control_state {
long_long counter[DUMMY_MAX_COUNTERS]; // may be used for caching
long_long lastupdate;
} DUMMY_control_state_t;
typedef struct DUMMY_context {
DUMMY_control_state_t state;
} DUMMY_context_t;
/************************* GLOBALS SECTION *********************************** *******************************************************************************/ /* This table contains the DUMMY native events */ static DUMMY_native_event_entry_t *dummy_native_table; /* number of events in the table*/ static unsigned NUM_EVENTS = 0; Function Implementation OrderInitialization routinesYou may prefer a dynamic way of generating your native_table ;)
/*
* This is called whenever a thread is initialized
*/
int DUMMY_init(hwd_context_t *ctx)
{
printf("DUMMY_init...");
printf(" OK\n");
return PAPI_OK;
}
/* Initialize hardware counters, setup the function vector table
* and get hardware information, this routine is called when the
* PAPI process is initialized (IE PAPI_library_init)
*/
int DUMMY_init_substrate()
{
printf("DUMMY_init_substrate...");
NUM_EVENTS = 2;
if ((dummy_native_table = (DUMMY_native_event_entry_t *)malloc(sizeof(DUMMY_native_event_entry_t)*NUM_EVENTS)) == NULL) {
perror("malloc():Could not get memory for events table");
return EXIT_FAILURE;
}
strcpy(dummy_native_table[0].name, "dummy-const-value");
strcpy(dummy_native_table[1].name , "dummy-autoinc-value");
strcpy(dummy_native_table[0].description , "This is an dummy counter, that reports a constant value");
strcpy(dummy_native_table[1].description , "This is an dummy counter, that reports an auto-increasing value");
/* The selector has to be !=0 . Starts with 1*/
dummy_native_table[0].resources.selector = 1;
dummy_native_table[1].resources.selector = 2;
printf(" OK\n");
return(PAPI_OK);
}
/*
* Control of counters (Reading/Writing/Starting/Stopping/Setup)
* functions
*/
int DUMMY_init_control_state(hwd_control_state_t *ctrl)
{
printf("DUMMY_init_control_state...");
((DUMMY_control_state_t *)ctrl)->counter[0] = 1;
((DUMMY_control_state_t *)ctrl)->counter[1] = 1;
((DUMMY_control_state_t *)ctrl)->lastupdate=PAPI_get_real_usec();
printf(" OK\n");
return PAPI_OK;
}
ntv_* routinesFor feedback on events
/*
* Native Event functions
*/
int DUMMY_ntv_enum_events(unsigned int *EventCode, int modifier)
{
int cidx = PAPI_COMPONENT_INDEX(*EventCode);
switch (modifier) {
case PAPI_ENUM_FIRST:
*EventCode = PAPI_NATIVE_MASK|PAPI_COMPONENT_MASK(cidx);
return (PAPI_OK);
break;
case PAPI_ENUM_EVENTS: {
int index = *EventCode & PAPI_NATIVE_AND_MASK & PAPI_COMPONENT_AND_MASK;
if (index < NUM_EVENTS-1) {
*EventCode = *EventCode + 1;
return (PAPI_OK);
} else {
return (PAPI_ENOEVNT);
}
break;
}
default:
return (PAPI_EINVAL);
}
return (PAPI_EINVAL);
}
/*
*
*/
int DUMMY_ntv_code_to_name(unsigned int EventCode, char *name, int len)
{
int index = EventCode & PAPI_NATIVE_AND_MASK & PAPI_COMPONENT_AND_MASK;
strncpy(name, dummy_native_table[index].name, len);
return(PAPI_OK);
}
/*
*
*/
int DUMMY_ntv_code_to_descr(unsigned int EventCode, char *name, int len)
{
int index = EventCode & PAPI_NATIVE_AND_MASK & PAPI_COMPONENT_AND_MASK;
strncpy(name, dummy_native_table[index].description, len);
return(PAPI_OK);
}
/*
*
*/
int DUMMY_ntv_code_to_bits(unsigned int EventCode, hwd_register_t * bits)
{
int index = EventCode & PAPI_NATIVE_AND_MASK & PAPI_COMPONENT_AND_MASK;
memcpy( ( DUMMY_register_t *) bits,
&(dummy_native_table[index].resources),
sizeof(DUMMY_register_t) );
return (PAPI_OK);
}
Update_control_stateFor adding/removing events
/*
* Triggered by eventset operations like add or remove
*/
int DUMMY_update_control_state(hwd_control_state_t *ptr, NativeInfo_t *native, int count, hwd_context_t *ctx)
{
printf("DUMMY_update_control_state...");
int i, index;
for (i = 0; i < count; i++) {
index = native[i].ni_event & PAPI_NATIVE_AND_MASK & PAPI_COMPONENT_AND_MASK;
native[i].ni_position = dummy_native_table[index].resources.selector-1;
printf("\nnative[%i].ni_position = dummy_native_table[%i].resources.selector-1 = %i;",i,index,native[i].ni_position);
}
printf("\n OK\n");
return(PAPI_OK);
}
Timer routinesif cpu component Start/stop/read/write routines
/*
* Triggered by PAPI_start()
*/
int DUMMY_start(hwd_context_t *ctx, hwd_control_state_t *ctrl)
{
printf("DUMMY_start...");
printf(" OK\n");
return(PAPI_OK);
}
/*
* Triggered by PAPI_stop()
*/
int DUMMY_stop(hwd_context_t *ctx, hwd_control_state_t *ctrl)
{
printf("DUMMY_stop...");
printf(" OK\n");
return(PAPI_OK);
}
/*
* Triggered by PAPI_read()
*/
int DUMMY_read(hwd_context_t *ctx, hwd_control_state_t *ctrl, long_long **events, int flags)
{
//printf("DUMMY_read...");
//if (we want to update our cache - probably every 50ms?)
((DUMMY_control_state_t *)ctrl)->counter[1]++; // autoincrement
*events = ((DUMMY_control_state_t *)ctrl)->counter; // serve cached data
//printf(" OK\n");
return(PAPI_OK);
}
/*
* Triggered by PAPI_reset
*/
int DUMMY_reset(hwd_context_t *ctx, hwd_control_state_t *ctrl)
{
printf("DUMMY_reset...");
((DUMMY_control_state_t *)ctrl)->counter[0] = 1;
((DUMMY_control_state_t *)ctrl)->counter[1] = 1;
((DUMMY_control_state_t *)ctrl)->lastupdate=PAPI_get_real_usec();
printf(" OK\n");
return(PAPI_OK);
}
Shutdown routines
/*
* Triggered by PAPI_shutdown()
*/
int DUMMY_shutdown(hwd_context_t *ctx)
{
printf("DUMMY_shutdown...");
/* Last chance to clean up*/
printf(" OK\n");
return(PAPI_OK);
}
Information routines as neededoften only cpu component
/* This function sets various options in the substrate
* The valid codes being passed in are PAPI_SET_DEFDOM,
* PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT
*/
int DUMMY_ctl(hwd_context_t *ctx, int code, _papi_int_option_t *option)
{
printf("DUMMY_ctl...");
printf(" OK\n");
return(PAPI_OK);
}
/*
* This function has to set the bits needed to count different domains
* In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
* By default return PAPI_EINVAL if none of those are specified
* and PAPI_OK with success
* PAPI_DOM_USER is only user context is counted
* PAPI_DOM_KERNEL is only the Kernel/OS context is counted
* PAPI_DOM_OTHER is Exception/transient mode (like user TLB misses)
* PAPI_DOM_ALL is all of the domains
*/
int DUMMY_set_domain(hwd_control_state_t *cntrl, int domain)
{
printf("DUMMY_set_domain...");
int found = 0;
if ( PAPI_DOM_USER & domain ) {
printf(" PAPI_DOM_USER ");
found = 1;
}
if ( PAPI_DOM_KERNEL & domain ) {
printf(" PAPI_DOM_KERNEL ");
found = 1;
}
if ( PAPI_DOM_OTHER & domain ) {
printf(" PAPI_DOM_OTHER ");
found = 1;
}
if ( PAPI_DOM_ALL & domain ) {
printf(" PAPI_DOM_ALL ");
found = 1;
}
if ( !found )
return(PAPI_EINVAL);
printf(" OK\n");
return(PAPI_OK);
}
Overflow/Profileif relevant Allocate/bptif relevant Papi-Vector Example
/*
*
*/
papi_vector_t _dummy_vector = {
.cmp_info = {
/* default component information (unspecified values are initialized to 0)*/
.name = "$Id: DUMMY component 07/08/2009$",
.version = "$Revision: 0.5$",
.num_mpx_cntrs = PAPI_MPX_DEF_DEG,
.num_cntrs = DUMMY_MAX_COUNTERS,
.default_domain = PAPI_DOM_USER,
.available_domains = PAPI_DOM_USER,
.default_granularity = PAPI_GRN_THR,
.available_granularities=PAPI_GRN_THR,
.hardware_intr_sig = PAPI_INT_SIGNAL,
/* component specific cmp_info initializations */
.fast_real_timer = 0,
.fast_virtual_timer = 0,
.attach = 0,
.attach_must_ptrace = 0,
.available_domains = PAPI_DOM_USER|PAPI_DOM_KERNEL,
},
/* sizes of framework-opaque component-private structures */
.size = {
.context = sizeof(DUMMY_context_t),
.control_state = sizeof(DUMMY_control_state_t),
.reg_value = sizeof(DUMMY_register_t),
.reg_alloc = sizeof(DUMMY_reg_alloc_t),
},
/* function pointers in this component */
.init = DUMMY_init,
.init_substrate = DUMMY_init_substrate,
.init_control_state = DUMMY_init_control_state,
.start = DUMMY_start,
.stop = DUMMY_stop,
.read = DUMMY_read,
.shutdown = DUMMY_shutdown,
.ctl = DUMMY_ctl,
.bpt_map_set = NULL,
.bpt_map_avail = NULL,
.bpt_map_exclusive = NULL,
.bpt_map_shared = NULL,
.bpt_map_preempt = NULL,
.bpt_map_update = NULL,
.update_control_state = DUMMY_update_control_state,
.set_domain = DUMMY_set_domain,
.reset = DUMMY_reset,
.ntv_enum_events = DUMMY_ntv_enum_events,
.ntv_code_to_name = DUMMY_ntv_code_to_name,
.ntv_code_to_descr = DUMMY_ntv_code_to_descr,
.ntv_code_to_bits = DUMMY_ntv_code_to_bits,
.ntv_bits_to_info = NULL,
};
Rules.dummyCOMPSRCS += components/dummy/dummy.c COMPOBJS += dummy.o dummy.o: components/dummy/dummy.c components/dummy/dummy.h $(HEADERS) $(CC) $(LIBCFLAGS) $(OPTFLAGS) -c components/dummy/dummy.c -o dummy.o |