/****************************/
/* THIS IS OPEN SOURCE CODE */
/****************************/
/**
* @file appio.c
*
* @author Philip Mucci
* phil.mucci@samaratechnologygroup.com
*
* @author Tushar Mohan
* tusharmohan@gmail.com
*
* Credit to:
* Jose Pedro Oliveira
* jpo@di.uminho.pt
* whose code in the linux net component was used as a template for
* many sections of code in this component.
*
* @ingroup papi_components
*
* @brief appio component
* This file contains the source code for a component that enables
* PAPI to access application level file and socket I/O information.
* It does this through function replacement in the first person and
* by trapping syscalls in the third person.
*/
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
/* Headers required by PAPI */
#include "papi.h"
#include "papi_internal.h"
#include "papi_vector.h"
#include "papi_memory.h"
#include "appio.h"
// The PIC test implies it's built for shared linkage
#ifdef PIC
# include "dlfcn.h"
#endif
/*
#pragma weak dlerror
static void *_dlsym_fake(void *handle, const char* symbol) { (void) handle; (void) symbol; return NULL; }
void *dlsym(void *handle, const char* symbol) __attribute__ ((weak, alias ("_dlsym_fake")));
*/
papi_vector_t _appio_vector;
/*********************************************************************
* Private
********************************************************************/
//#define APPIO_FOO 1
static APPIO_native_event_entry_t * _appio_native_events;
/* If you modify the appio_stats_t below, you MUST update APPIO_MAX_COUNTERS */
static __thread long long _appio_register_current[APPIO_MAX_COUNTERS];
typedef enum {
READ_BYTES = 0,
READ_CALLS,
READ_ERR,
READ_INTERRUPTED,
READ_WOULD_BLOCK,
READ_SHORT,
READ_EOF,
READ_BLOCK_SIZE,
READ_USEC,
WRITE_BYTES,
WRITE_CALLS,
WRITE_ERR,
WRITE_SHORT,
WRITE_INTERRUPTED,
WRITE_WOULD_BLOCK,
WRITE_BLOCK_SIZE,
WRITE_USEC,
OPEN_CALLS,
OPEN_ERR,
OPEN_FDS,
SELECT_USEC,
RECV_BYTES,
RECV_CALLS,
RECV_ERR,
RECV_INTERRUPTED,
RECV_WOULD_BLOCK,
RECV_SHORT,
RECV_EOF,
RECV_BLOCK_SIZE,
RECV_USEC,
SOCK_READ_BYTES,
SOCK_READ_CALLS,
SOCK_READ_ERR,
SOCK_READ_SHORT,
SOCK_READ_WOULD_BLOCK,
SOCK_READ_USEC,
SOCK_WRITE_BYTES,
SOCK_WRITE_CALLS,
SOCK_WRITE_ERR,
SOCK_WRITE_SHORT,
SOCK_WRITE_WOULD_BLOCK,
SOCK_WRITE_USEC,
SEEK_CALLS,
SEEK_ABS_STRIDE_SIZE,
SEEK_USEC
} _appio_stats_t ;
static const struct appio_counters {
const char *name;
const char *description;
} _appio_counter_info[APPIO_MAX_COUNTERS] = {
{ "READ_BYTES", "Bytes read"},
{ "READ_CALLS", "Number of read calls"},
{ "READ_ERR", "Number of read calls that resulted in an error"},
{ "READ_INTERRUPTED","Number of read calls that timed out or were interruped"},
{ "READ_WOULD_BLOCK","Number of read calls that would have blocked"},
{ "READ_SHORT", "Number of read calls that returned less bytes than requested"},
{ "READ_EOF", "Number of read calls that returned an EOF"},
{ "READ_BLOCK_SIZE", "Average block size of reads"},
{ "READ_USEC", "Real microseconds spent in reads"},
{ "WRITE_BYTES", "Bytes written"},
{ "WRITE_CALLS", "Number of write calls"},
{ "WRITE_ERR", "Number of write calls that resulted in an error"},
{ "WRITE_SHORT", "Number of write calls that wrote less bytes than requested"},
{ "WRITE_INTERRUPTED","Number of write calls that timed out or were interrupted"},
{ "WRITE_WOULD_BLOCK","Number of write calls that would have blocked"},
{ "WRITE_BLOCK_SIZE","Mean block size of writes"},
{ "WRITE_USEC", "Real microseconds spent in writes"},
{ "OPEN_CALLS", "Number of open calls"},
{ "OPEN_ERR", "Number of open calls that resulted in an error"},
{ "OPEN_FDS", "Number of currently open descriptors"},
{ "SELECT_USEC", "Real microseconds spent in select calls"},
{ "RECV_BYTES", "Bytes read in recv/recvmsg/recvfrom"},
{ "RECV_CALLS", "Number of recv/recvmsg/recvfrom calls"},
{ "RECV_ERR", "Number of recv/recvmsg/recvfrom calls that resulted in an error"},
{ "RECV_INTERRUPTED","Number of recv/recvmsg/recvfrom calls that timed out or were interruped"},
{ "RECV_WOULD_BLOCK","Number of recv/recvmsg/recvfrom calls that would have blocked"},
{ "RECV_SHORT", "Number of recv/recvmsg/recvfrom calls that returned less bytes than requested"},
{ "RECV_EOF", "Number of recv/recvmsg/recvfrom calls that returned an EOF"},
{ "RECV_BLOCK_SIZE", "Average block size of recv/recvmsg/recvfrom"},
{ "RECV_USEC", "Real microseconds spent in recv/recvmsg/recvfrom"},
{ "SOCK_READ_BYTES", "Bytes read from socket"},
{ "SOCK_READ_CALLS", "Number of read calls on socket"},
{ "SOCK_READ_ERR", "Number of read calls on socket that resulted in an error"},
{ "SOCK_READ_SHORT", "Number of read calls on socket that returned less bytes than requested"},
{ "SOCK_READ_WOULD_BLOCK", "Number of read calls on socket that would have blocked"},
{ "SOCK_READ_USEC", "Real microseconds spent in read(s) on socket(s)"},
{ "SOCK_WRITE_BYTES","Bytes written to socket"},
{ "SOCK_WRITE_CALLS","Number of write calls to socket"},
{ "SOCK_WRITE_ERR", "Number of write calls to socket that resulted in an error"},
{ "SOCK_WRITE_SHORT","Number of write calls to socket that wrote less bytes than requested"},
{ "SOCK_WRITE_WOULD_BLOCK","Number of write calls to socket that would have blocked"},
{ "SOCK_WRITE_USEC", "Real microseconds spent in write(s) to socket(s)"},
{ "SEEK_CALLS", "Number of seek calls"},
{ "SEEK_ABS_STRIDE_SIZE", "Average absolute stride size of seeks"},
{ "SEEK_USEC", "Real microseconds spent in seek calls"}
};
/*********************************************************************
*** BEGIN FUNCTIONS USED INTERNALLY SPECIFIC TO THIS COMPONENT ****
********************************************************************/
int __close(int fd);
int close(int fd) {
int retval;
SUBDBG("appio: intercepted close(%d)\n", fd);
retval = __close(fd);
if ((retval == 0) && (_appio_register_current[OPEN_FDS]>0)) _appio_register_current[OPEN_FDS]--;
return retval;
}
int __open(const char *pathname, int flags, mode_t mode);
int open(const char *pathname, int flags, mode_t mode) {
int retval;
SUBDBG("appio: intercepted open(%s,%d,%d)\n", pathname, flags, mode);
retval = __open(pathname,flags,mode);
_appio_register_current[OPEN_CALLS]++;
if (retval < 0) _appio_register_current[OPEN_ERR]++;
else _appio_register_current[OPEN_FDS]++;
return retval;
}
/* we use timeval as a zero value timeout to select in read/write
for polling if the operation would block */
struct timeval zerotv; /* this has to be zero, so define it here */
int __select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
int retval;
SUBDBG("appio: intercepted select(%d,%p,%p,%p,%p)\n", nfds,readfds,writefds,exceptfds,timeout);
long long start_ts = PAPI_get_real_usec();
retval = __select(nfds,readfds,writefds,exceptfds,timeout);
long long duration = PAPI_get_real_usec() - start_ts;
_appio_register_current[SELECT_USEC] += duration;
return retval;
}
off_t __lseek(int fd, off_t offset, int whence);
off_t lseek(int fd, off_t offset, int whence) {
off_t retval;
SUBDBG("appio: intercepted lseek(%d,%ld,%d)\n", fd, offset, whence);
long long start_ts = PAPI_get_real_usec();
retval = __lseek(fd, offset, whence);
long long duration = PAPI_get_real_usec() - start_ts;
int n = _appio_register_current[SEEK_CALLS]++;
_appio_register_current[SEEK_USEC] += duration;
if (offset < 0) offset = -offset; // get abs offset
_appio_register_current[SEEK_ABS_STRIDE_SIZE]= (n * _appio_register_current[SEEK_ABS_STRIDE_SIZE] + offset)/(n+1); // mean absolute stride size
return retval;
}
extern int errno;
ssize_t __read(int fd, void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count) {
int retval;
SUBDBG("appio: intercepted read(%d,%p,%lu)\n", fd, buf, (unsigned long)count);
struct stat st;
int issocket = 0;
if (fstat(fd, &st) == 0) {
if ((st.st_mode & S_IFMT) == S_IFSOCK) issocket = 1;
}
// check if read would block on descriptor
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
int ready = __select(fd+1, &readfds, NULL, NULL, &zerotv);
if (ready == 0) {
_appio_register_current[READ_WOULD_BLOCK]++;
if (issocket) _appio_register_current[SOCK_READ_WOULD_BLOCK]++;
}
long long start_ts = PAPI_get_real_usec();
retval = __read(fd,buf, count);
long long duration = PAPI_get_real_usec() - start_ts;
int n = _appio_register_current[READ_CALLS]++; // read calls
if (issocket) _appio_register_current[SOCK_READ_CALLS]++; // read calls
if (retval > 0) {
_appio_register_current[READ_BLOCK_SIZE]= (n * _appio_register_current[READ_BLOCK_SIZE] + count)/(n+1); // mean size
_appio_register_current[READ_BYTES] += retval; // read bytes
if (issocket) _appio_register_current[SOCK_READ_BYTES] += retval;
if (retval < (int)count) {
_appio_register_current[READ_SHORT]++; // read short
if (issocket) _appio_register_current[SOCK_READ_SHORT]++; // read short
}
_appio_register_current[READ_USEC] += duration;
if (issocket) _appio_register_current[SOCK_READ_USEC] += duration;
}
if (retval < 0) {
_appio_register_current[READ_ERR]++; // read err
if (issocket) _appio_register_current[SOCK_READ_ERR]++; // read err
if (EINTR == errno)
_appio_register_current[READ_INTERRUPTED]++; // signal interrupted the read
//if ((EAGAIN == errno) || (EWOULDBLOCK == errno)) {
// _appio_register_current[READ_WOULD_BLOCK]++; //read would block on descriptor marked as non-blocking
// if (issocket) _appio_register_current[SOCK_READ_WOULD_BLOCK]++; //read would block on descriptor marked as non-blocking
//}
}
if (retval == 0) _appio_register_current[READ_EOF]++; // read eof
return retval;
}
size_t _IO_fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t retval;
SUBDBG("appio: intercepted fread(%p,%lu,%lu,%p)\n", ptr, (unsigned long) size, (unsigned long) nmemb, (void*) stream);
long long start_ts = PAPI_get_real_usec();
retval = _IO_fread(ptr,size,nmemb,stream);
long long duration = PAPI_get_real_usec() - start_ts;
int n = _appio_register_current[READ_CALLS]++; // read calls
if (retval > 0) {
_appio_register_current[READ_BLOCK_SIZE]= (n * _appio_register_current[READ_BLOCK_SIZE]+ size*nmemb)/(n+1);//mean size
_appio_register_current[READ_BYTES]+= retval * size; // read bytes
if (retval < nmemb) _appio_register_current[READ_SHORT]++; // read short
_appio_register_current[READ_USEC] += duration;
}
/* A value of zero returned means one of two things..*/
if (retval == 0) {
if (feof(stream)) _appio_register_current[READ_EOF]++; // read eof
else _appio_register_current[READ_ERR]++; // read err
}
return retval;
}
ssize_t __write(int fd, const void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count) {
int retval;
SUBDBG("appio: intercepted write(%d,%p,%lu)\n", fd, buf, (unsigned long)count);
struct stat st;
int issocket = 0;
if (fstat(fd, &st) == 0) {
if ((st.st_mode & S_IFMT) == S_IFSOCK) issocket = 1;
}
// check if write would block on descriptor
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
int ready = __select(fd+1, NULL, &writefds, NULL, &zerotv);
if (ready == 0) {
_appio_register_current[WRITE_WOULD_BLOCK]++;
if (issocket) _appio_register_current[SOCK_WRITE_WOULD_BLOCK]++;
}
long long start_ts = PAPI_get_real_usec();
retval = __write(fd,buf, count);
long long duration = PAPI_get_real_usec() - start_ts;
int n = _appio_register_current[WRITE_CALLS]++; // write calls
if (issocket) _appio_register_current[SOCK_WRITE_CALLS]++; // socket write
if (retval >= 0) {
_appio_register_current[WRITE_BLOCK_SIZE]= (n * _appio_register_current[WRITE_BLOCK_SIZE] + count)/(n+1); // mean size
_appio_register_current[WRITE_BYTES]+= retval; // write bytes
if (issocket) _appio_register_current[SOCK_WRITE_BYTES] += retval;
if (retval < (int)count) {
_appio_register_current[WRITE_SHORT]++; // short write
if (issocket) _appio_register_current[SOCK_WRITE_SHORT]++;
}
_appio_register_current[WRITE_USEC] += duration;
if (issocket) _appio_register_current[SOCK_WRITE_USEC] += duration;
}
if (retval < 0) {
_appio_register_current[WRITE_ERR]++; // err
if (issocket) _appio_register_current[SOCK_WRITE_ERR]++;
if (EINTR == errno)
_appio_register_current[WRITE_INTERRUPTED]++; // signal interrupted the op
//if ((EAGAIN == errno) || (EWOULDBLOCK == errno)) {
// _appio_register_current[WRITE_WOULD_BLOCK]++; //op would block on descriptor marked as non-blocking
// if (issocket) _appio_register_current[SOCK_WRITE_WOULD_BLOCK]++;
//}
}
return retval;
}
// The PIC test implies it's built for shared linkage
#ifdef PIC
static ssize_t (*__recv)(int sockfd, void *buf, size_t len, int flags) = NULL;
ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
int retval;
SUBDBG("appio: intercepted recv(%d,%p,%lu,%d)\n", sockfd, buf, (unsigned long)len, flags);
if (!__recv) __recv = dlsym(RTLD_NEXT, "recv");
if (!__recv) {
fprintf(stderr, "appio,c Internal Error: Could not obtain handle for real recv\n");
exit(1);
}
// check if recv would block on descriptor
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
int ready = __select(sockfd+1, &readfds, NULL, NULL, &zerotv);
if (ready == 0) _appio_register_current[RECV_WOULD_BLOCK]++;
long long start_ts = PAPI_get_real_usec();
retval = __recv(sockfd, buf, len, flags);
long long duration = PAPI_get_real_usec() - start_ts;
int n = _appio_register_current[RECV_CALLS]++; // read calls
if (retval > 0) {
_appio_register_current[RECV_BLOCK_SIZE]= (n * _appio_register_current[RECV_BLOCK_SIZE] + len)/(n+1); // mean size
_appio_register_current[RECV_BYTES] += retval; // read bytes
if (retval < (int)len) _appio_register_current[RECV_SHORT]++; // read short
_appio_register_current[RECV_USEC] += duration;
}
if (retval < 0) {
_appio_register_current[RECV_ERR]++; // read err
if (EINTR == errno)
_appio_register_current[RECV_INTERRUPTED]++; // signal interrupted the read
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
_appio_register_current[RECV_WOULD_BLOCK]++; //read would block on descriptor marked as non-blocking
}
if (retval == 0) _appio_register_current[RECV_EOF]++; // read eof
return retval;
}
#endif /* PIC */
size_t _IO_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t retval;
SUBDBG("appio: intercepted fwrite(%p,%lu,%lu,%p)\n", ptr, (unsigned long) size, (unsigned long) nmemb, (void*) stream);
long long start_ts = PAPI_get_real_usec();
retval = _IO_fwrite(ptr,size,nmemb,stream);
long long duration = PAPI_get_real_usec() - start_ts;
int n = _appio_register_current[WRITE_CALLS]++; // write calls
if (retval > 0) {
_appio_register_current[WRITE_BLOCK_SIZE]= (n * _appio_register_current[WRITE_BLOCK_SIZE] + size*nmemb)/(n+1); // mean block size
_appio_register_current[WRITE_BYTES]+= retval * size; // write bytes
if (retval < nmemb) _appio_register_current[WRITE_SHORT]++; // short write
_appio_register_current[WRITE_USEC] += duration;
}
if (retval == 0) _appio_register_current[WRITE_ERR]++; // err
return retval;
}
/*********************************************************************
*************** BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS *********
*********************************************************************/
/*
* This is called whenever a thread is initialized
*/
static int
_appio_init_thread( hwd_context_t *ctx )
{
( void ) ctx;
SUBDBG("_appio_init_thread %p\n", ctx);
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)
*/
static int
_appio_init_component( int cidx )
{
SUBDBG("_appio_component %d\n", cidx);
_appio_native_events = (APPIO_native_event_entry_t *) papi_calloc(APPIO_MAX_COUNTERS, sizeof(APPIO_native_event_entry_t));
if (_appio_native_events == NULL ) {
PAPIERROR( "malloc():Could not get memory for events table" );
return PAPI_ENOMEM;
}
int i;
for (i=0; i<APPIO_MAX_COUNTERS; i++) {
_appio_native_events[i].name = _appio_counter_info[i].name;
_appio_native_events[i].description = _appio_counter_info[i].description;
_appio_native_events[i].resources.selector = i + 1;
}
/* Export the total number of events available */
_appio_vector.cmp_info.num_native_events = APPIO_MAX_COUNTERS;;
/* Export the component id */
_appio_vector.cmp_info.CmpIdx = cidx;
return PAPI_OK;
}
/*
* Control of counters (Reading/Writing/Starting/Stopping/Setup)
* functions
*/
static int
_appio_init_control_state( hwd_control_state_t *ctl )
{
( void ) ctl;
return PAPI_OK;
}
static int
_appio_start( hwd_context_t *ctx, hwd_control_state_t *ctl )
{
( void ) ctx;
SUBDBG("_appio_start %p %p\n", ctx, ctl);
APPIO_control_state_t *appio_ctl = (APPIO_control_state_t *) ctl;
/* this memset needs to move to thread_init */
memset(_appio_register_current, 0, APPIO_MAX_COUNTERS * sizeof(_appio_register_current[0]));
/* set initial values to 0 */
memset(appio_ctl->values, 0, APPIO_MAX_COUNTERS*sizeof(appio_ctl->values[0]));
return PAPI_OK;
}
static int
_appio_read( hwd_context_t *ctx, hwd_control_state_t *ctl,
long long ** events, int flags )
{
(void) flags;
(void) ctx;
SUBDBG("_appio_read %p %p\n", ctx, ctl);
APPIO_control_state_t *appio_ctl = (APPIO_control_state_t *) ctl;
int i;
for ( i=0; i<appio_ctl->num_events; i++ ) {
int index = appio_ctl->counter_bits[i];
SUBDBG("event=%d, index=%d, val=%lld\n", i, index, _appio_register_current[index]);
appio_ctl->values[index] = _appio_register_current[index];
}
*events = appio_ctl->values;
return PAPI_OK;
}
static int
_appio_stop( hwd_context_t *ctx, hwd_control_state_t *ctl )
{
(void) ctx;
SUBDBG("_appio_stop ctx=%p ctl=%p\n", ctx, ctl);
APPIO_control_state_t *appio_ctl = (APPIO_control_state_t *) ctl;
int i;
for ( i=0; i<appio_ctl->num_events; i++ ) {
int index = appio_ctl->counter_bits[i];
SUBDBG("event=%d, index=%d, val=%lld\n", i, index, _appio_register_current[index]);
appio_ctl->values[i] = _appio_register_current[index];
}
return PAPI_OK;
}
/*
* Thread shutdown
*/
static int
_appio_shutdown_thread( hwd_context_t *ctx )
{
( void ) ctx;
return PAPI_OK;
}
/*
* Clean up what was setup in appio_init_component().
*/
static int
_appio_shutdown_component( void )
{
papi_free( _appio_native_events );
return PAPI_OK;
}
/* This function sets various options in the component
* The valid codes being passed in are PAPI_SET_DEFDOM,
* PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL and
* PAPI_SET_INHERIT
*/
static int
_appio_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option )
{
( void ) ctx;
( void ) code;
( void ) option;
return PAPI_OK;
}
static int
_appio_update_control_state( hwd_control_state_t *ctl,
NativeInfo_t *native, int count, hwd_context_t *ctx )
{
( void ) ctx;
( void ) ctl;
SUBDBG("_appio_update_control_state ctx=%p ctl=%p num_events=%d\n", ctx, ctl, count);
int i, index;
APPIO_control_state_t *appio_ctl = (APPIO_control_state_t *) ctl;
(void) ctx;
for ( i = 0; i < count; i++ ) {
index = native[i].ni_event;
appio_ctl->counter_bits[i] = index;
native[i].ni_position = index;
}
appio_ctl->num_events = count;
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
*/
static int
_appio_set_domain( hwd_control_state_t *ctl, int domain )
{
( void ) ctl;
int found = 0;
if ( PAPI_DOM_USER == domain ) found = 1;
if ( !found )
return PAPI_EINVAL;
return PAPI_OK;
}
static int
_appio_reset( hwd_context_t *ctx, hwd_control_state_t *ctl )
{
( void ) ctx;
( void ) ctl;
return PAPI_OK;
}
/*
* Native Event functions
*/
static int
_appio_ntv_enum_events( unsigned int *EventCode, int modifier )
{
int index;
switch ( modifier ) {
case PAPI_ENUM_FIRST:
*EventCode = 0;
return PAPI_OK;
break;
case PAPI_ENUM_EVENTS:
index = *EventCode;
if ( index < APPIO_MAX_COUNTERS - 1 ) {
*EventCode = *EventCode + 1;
return PAPI_OK;
} else {
return PAPI_ENOEVNT;
}
break;
default:
return PAPI_EINVAL;
break;
}
return PAPI_EINVAL;
}
/*
*
*/
static int
_appio_ntv_name_to_code( const char *name, unsigned int *EventCode )
{
int i;
for ( i=0; i<APPIO_MAX_COUNTERS; i++) {
if (strcmp(name, _appio_counter_info[i].name) == 0) {
*EventCode = i;
return PAPI_OK;
}
}
return PAPI_ENOEVNT;
}
/*
*
*/
static int
_appio_ntv_code_to_name( unsigned int EventCode, char *name, int len )
{
int index = EventCode;
if ( index >= 0 && index < APPIO_MAX_COUNTERS ) {
strncpy( name, _appio_counter_info[index].name, len );
return PAPI_OK;
}
return PAPI_ENOEVNT;
}
/*
*
*/
static int
_appio_ntv_code_to_descr( unsigned int EventCode, char *desc, int len )
{
int index = EventCode;
if ( index >= 0 && index < APPIO_MAX_COUNTERS ) {
strncpy(desc, _appio_counter_info[index].description, len );
return PAPI_OK;
}
return PAPI_ENOEVNT;
}
/*
*
*/
static int
_appio_ntv_code_to_bits( unsigned int EventCode, hwd_register_t *bits )
{
int index = EventCode;
if ( index >= 0 && index < APPIO_MAX_COUNTERS ) {
memcpy( ( APPIO_register_t * ) bits,
&( _appio_native_events[index].resources ),
sizeof ( APPIO_register_t ) );
return PAPI_OK;
}
return PAPI_ENOEVNT;
}
/*
*
*/
papi_vector_t _appio_vector = {
.cmp_info = {
/* default component information (unspecified values are initialized to 0) */
.name = "appio",
.short_name = "appio",
.version = "1.1.2.4",
.CmpIdx = 0, /* set by init_component */
.num_mpx_cntrs = APPIO_MAX_COUNTERS,
.num_cntrs = APPIO_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,
},
/* sizes of framework-opaque component-private structures */
.size = {
.context = sizeof ( APPIO_context_t ),
.control_state = sizeof ( APPIO_control_state_t ),
.reg_value = sizeof ( APPIO_register_t ),
.reg_alloc = sizeof ( APPIO_reg_alloc_t ),
},
/* function pointers in this component */
.init_thread = _appio_init_thread,
.init_component = _appio_init_component,
.init_control_state = _appio_init_control_state,
.start = _appio_start,
.stop = _appio_stop,
.read = _appio_read,
.shutdown_thread = _appio_shutdown_thread,
.shutdown_component = _appio_shutdown_component,
.ctl = _appio_ctl,
.update_control_state = _appio_update_control_state,
.set_domain = _appio_set_domain,
.reset = _appio_reset,
.ntv_enum_events = _appio_ntv_enum_events,
.ntv_name_to_code = _appio_ntv_name_to_code,
.ntv_code_to_name = _appio_ntv_code_to_name,
.ntv_code_to_descr = _appio_ntv_code_to_descr,
.ntv_code_to_bits = _appio_ntv_code_to_bits
/* .ntv_bits_to_info = NULL, */
};
/* vim:set ts=4 sw=4 sts=4 et: */