PAPIC:Component Development Cookbook
From PAPIDocs
Jump to: navigation, search

Contents

PAPI-C Component Development Cookbook

General Flow of Implementation

  1. Create new directory in the components directory: /components/your_component_name
  2. Create source and header files
  3. Create a Rules.your_component_name file
  4. Fill out a papi_vector_t structure named dummy_vector
  5. Test compile
    1. Iterate until successful
  6. Add functionality as needed and go to #4
  7. Rinse and repeat

Example of Implementation

A 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 Order

Initialization routines

You 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_* routines

For feedback on events
Also requires implementation of event resources
Works by copy&paste&rename in most cases:

/*
 * 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_state

For 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 routines

if 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 needed

often 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/Profile

if relevant

Allocate/bpt

if 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.dummy

COMPSRCS += 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