/** * @file linux-stealtime.c * @author Vince Weaver * vweaver1@eecs.utk.edu * @brief A component that gather info on VM stealtime */ #include #include #include #include #include #include #include #include "papi.h" #include "papi_internal.h" #include "papi_vector.h" #include "papi_memory.h" struct counter_info { char *name; char *description; char *units; unsigned long long value; }; typedef struct counter_info STEALTIME_register_t; typedef struct counter_info STEALTIME_native_event_entry_t; typedef struct counter_info STEALTIME_reg_alloc_t; struct STEALTIME_control_state { long long *values; int *which_counter; int num_events; }; struct STEALTIME_context { long long *start_count; long long *current_count; long long *value; }; static int num_events = 0; static struct counter_info *event_info=NULL; /* Advance declaration of buffer */ papi_vector_t _stealtime_vector; /****************************************************************************** ******** BEGIN FUNCTIONS USED INTERNALLY SPECIFIC TO THIS COMPONENT ******** *****************************************************************************/ struct statinfo { long long user; long long nice; long long system; long long idle; long long iowait; long long irq; long long softirq; long long steal; long long guest; }; static int read_stealtime( struct STEALTIME_context *context, int starting) { FILE *fff; char buffer[BUFSIZ],*result; int i,count; struct statinfo our_stat; int hz=sysconf(_SC_CLK_TCK); fff=fopen("/proc/stat","r"); if (fff==NULL) { return PAPI_ESYS; } for(i=0;istart_count[i]=our_stat.steal; } context->current_count[i]=our_stat.steal; /* convert to us */ context->value[i]=(context->current_count[i]-context->start_count[i])* (1000000/hz); } fclose(fff); return PAPI_OK; } /***************************************************************************** ******************* BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS ************* *****************************************************************************/ /* * Component setup and shutdown */ static int _stealtime_init_component( int cidx ) { (void)cidx; FILE *fff; char buffer[BUFSIZ],*result,string[BUFSIZ]; int i; /* Make sure /proc/stat exists */ fff=fopen("/proc/stat","r"); if (fff==NULL) { strncpy(_stealtime_vector.cmp_info.disabled_reason, "Cannot open /proc/stat",PAPI_MAX_STR_LEN); return PAPI_ESYS; } num_events=0; while(1) { result=fgets(buffer,BUFSIZ,fff); if (result==NULL) break; /* /proc/stat line with cpu stats always starts with "cpu" */ if (!strncmp(buffer,"cpu",3)) { num_events++; } else { break; } } fclose(fff); if (num_events<1) { strncpy(_stealtime_vector.cmp_info.disabled_reason, "Cannot find enough CPU lines in /proc/stat", PAPI_MAX_STR_LEN); return PAPI_ESYS; } event_info=calloc(num_events,sizeof(struct counter_info)); if (event_info==NULL) { return PAPI_ENOMEM; } sysconf(_SC_CLK_TCK); event_info[0].name=strdup("TOTAL"); event_info[0].description=strdup("Total amount of steal time"); event_info[0].units=strdup("us"); for(i=1;istart_count=calloc(num_events,sizeof(long long)); if (context->start_count==NULL) return PAPI_ENOMEM; context->current_count=calloc(num_events,sizeof(long long)); if (context->current_count==NULL) return PAPI_ENOMEM; context->value=calloc(num_events,sizeof(long long)); if (context->value==NULL) return PAPI_ENOMEM; return PAPI_OK; } /* * */ static int _stealtime_shutdown_component( void ) { int i; int num_events = _stealtime_vector.cmp_info.num_native_events; if (event_info!=NULL) { for (i=0; istart_count!=NULL) free(context->start_count); if (context->current_count!=NULL) free(context->current_count); if (context->value!=NULL) free(context->value); return PAPI_OK; } /* * Control of counters (Reading/Writing/Starting/Stopping/Setup) functions */ static int _stealtime_init_control_state( hwd_control_state_t *ctl ) { struct STEALTIME_control_state *control = (struct STEALTIME_control_state *)ctl; control->values=NULL; control->which_counter=NULL; control->num_events=0; return PAPI_OK; } /* * */ static int _stealtime_update_control_state( hwd_control_state_t *ctl, NativeInfo_t *native, int count, hwd_context_t *ctx ) { struct STEALTIME_control_state *control; ( void ) ctx; int i, index; control= (struct STEALTIME_control_state *)ctl; if (count!=control->num_events) { // printf("Resizing %d to %d\n",control->num_events,count); control->which_counter=realloc(control->which_counter, count*sizeof(int)); control->values=realloc(control->values, count*sizeof(long long)); } for ( i = 0; i < count; i++ ) { index = native[i].ni_event; control->which_counter[i]=index; native[i].ni_position = i; } control->num_events=count; return PAPI_OK; } /* * */ static int _stealtime_start( hwd_context_t *ctx, hwd_control_state_t *ctl ) { (void)ctl; // struct STEALTIME_control_state *control; struct STEALTIME_context *context; //control = (struct STEALTIME_control_state *)ctl; context = (struct STEALTIME_context *)ctx; read_stealtime( context, 1 ); /* no need to update control, as we assume only one EventSet */ /* is active at once, so starting things at the context level */ /* is fine, since stealtime is system-wide */ return PAPI_OK; } /* * */ static int _stealtime_stop( hwd_context_t *ctx, hwd_control_state_t *ctl ) { (void) ctl; // struct STEALTIME_control_state *control; struct STEALTIME_context *context; //control = (struct STEALTIME_control_state *)ctl; context = (struct STEALTIME_context *)ctx; read_stealtime( context, 0 ); return PAPI_OK; } /* * */ static int _stealtime_read( hwd_context_t *ctx, hwd_control_state_t *ctl, long long **events, int flags ) { ( void ) flags; struct STEALTIME_control_state *control; struct STEALTIME_context *context; int i; control = (struct STEALTIME_control_state *)ctl; context = (struct STEALTIME_context *)ctx; read_stealtime( context, 0 ); for(i=0;inum_events;i++) { control->values[i]= context->value[control->which_counter[i]]; } *events = control->values; return PAPI_OK; } /* * */ static int _stealtime_reset( hwd_context_t * ctx, hwd_control_state_t * ctrl ) { /* re-initializes counter_start values to current */ _stealtime_start(ctx,ctrl); return PAPI_OK; } /* * Unused stealtime write function */ /* static int */ /* _stealtime_write( hwd_context_t * ctx, hwd_control_state_t * ctrl, long long *from ) */ /* { */ /* ( void ) ctx; */ /* ( void ) ctrl; */ /* ( void ) from; */ /* return PAPI_OK; */ /* } */ /* * Functions for setting up various options */ /* 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 _stealtime_ctl( hwd_context_t * ctx, int code, _papi_int_option_t * option ) { ( void ) ctx; ( void ) code; ( void ) option; 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 _stealtime_set_domain( hwd_control_state_t * cntrl, int domain ) { ( void ) cntrl; int found = 0; if ( PAPI_DOM_USER & domain ) { found = 1; } if ( PAPI_DOM_KERNEL & domain ) { found = 1; } if ( PAPI_DOM_OTHER & domain ) { found = 1; } if ( !found ) return PAPI_EINVAL; return PAPI_OK; } /* * */ static int _stealtime_ntv_code_to_name( unsigned int EventCode, char *name, int len ) { int event=EventCode; if (event >=0 && event < num_events) { strncpy( name, event_info[event].name, len ); return PAPI_OK; } return PAPI_ENOEVNT; } /* * */ static int _stealtime_ntv_code_to_descr( unsigned int EventCode, char *name, int len ) { int event=EventCode; if (event >=0 && event < num_events) { strncpy( name, event_info[event].description, len ); return PAPI_OK; } return PAPI_ENOEVNT; } static int _stealtime_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info) { int index = EventCode; if ( ( index < 0) || (index >= num_events )) return PAPI_ENOEVNT; strncpy( info->symbol, event_info[index].name,sizeof(info->symbol)); info->symbol[sizeof(info->symbol)-1] = '\0'; strncpy( info->long_descr, event_info[index].description,sizeof(info->symbol)); info->long_descr[sizeof(info->symbol)-1] = '\0'; strncpy( info->units, event_info[index].units,sizeof(info->units)); info->units[sizeof(info->units)-1] = '\0'; return PAPI_OK; } /* * */ static int _stealtime_ntv_enum_events( unsigned int *EventCode, int modifier ) { if ( modifier == PAPI_ENUM_FIRST ) { if (num_events==0) return PAPI_ENOEVNT; *EventCode = 0; return PAPI_OK; } if ( modifier == PAPI_ENUM_EVENTS ) { int index; index = *EventCode; if ( (index+1) < num_events ) { *EventCode = *EventCode + 1; return PAPI_OK; } else { return PAPI_ENOEVNT; } } return PAPI_EINVAL; } /* * */ papi_vector_t _stealtime_vector = { .cmp_info = { /* component information (unspecified values initialized to 0) */ .name = "stealtime", .short_name="stealtime", .version = "5.0", .description = "Stealtime filesystem statistics", .default_domain = 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 ( struct STEALTIME_context ), .control_state = sizeof ( struct STEALTIME_control_state ), .reg_value = sizeof ( STEALTIME_register_t ), .reg_alloc = sizeof ( STEALTIME_reg_alloc_t ), }, /* function pointers in this component */ .init_thread = _stealtime_init_thread, .init_component = _stealtime_init_component, .init_control_state = _stealtime_init_control_state, .start = _stealtime_start, .stop = _stealtime_stop, .read = _stealtime_read, .shutdown_thread = _stealtime_shutdown_thread, .shutdown_component = _stealtime_shutdown_component, .ctl = _stealtime_ctl, .update_control_state = _stealtime_update_control_state, .set_domain = _stealtime_set_domain, .reset = _stealtime_reset, .ntv_enum_events = _stealtime_ntv_enum_events, .ntv_code_to_name = _stealtime_ntv_code_to_name, .ntv_code_to_descr = _stealtime_ntv_code_to_descr, .ntv_code_to_info = _stealtime_ntv_code_to_info, };