PAPI  5.1.0.2
linux-micpower.c
Go to the documentation of this file.
00001 #include <string.h>
00002 #include <unistd.h>
00003 
00004 /* Headers required by PAPI */
00005 #include "papi.h"
00006 #include "papi_internal.h"
00007 #include "papi_vector.h"
00008 #include "papi_memory.h"
00009 
00010 #include "linux-micpower.h"
00011 
00012 /* Intel says
00013 ----
00014 The power measurements can be obtained from the host as well as the MIC card 
00015 over a 50msec interval. The SMC is designed to sample power consumption only 
00016 every 50mSecs.
00017 ----
00018 **/
00019 #define REFRESH_LAT 50000
00020 
00021 #define INVALID_RESULT -1000000L
00022 #define MICPOWER_NUMBER_OF_NATIVE_EVENTS 16 
00023 
00024 papi_vector_t _micpower_vector;
00025 
00026 static MICPOWER_native_event_entry_t _micpower_native_events[] = {
00027         {   .name               = "tot0",
00028                 .units              = "uW",
00029                 .description        = "Total power, win 0", 
00030                 .resources.selector = 1
00031         },
00032         {   .name               = "tot1",
00033                 .units              = "uW",
00034                 .description        = "Total power, win 1", 
00035                 .resources.selector = 2
00036         },
00037         {   .name               = "pcie",
00038                 .units              = "uW",
00039                 .description        = "PCI-E connector power", 
00040                 .resources.selector = 3
00041         },
00042         {   .name               = "inst",
00043                 .units              = "uW",
00044                 .description        = "Instantaneous power", 
00045                 .resources.selector = 4
00046         },
00047         {   .name               = "imax",
00048                 .units              = "uW",
00049                 .description        = "Max Instantaneous power", 
00050                 .resources.selector = 5
00051         },
00052         {   .name               = "c2x3",
00053                 .units              = "uW",
00054                 .description        = "2x3 connector power", 
00055                 .resources.selector = 6
00056         },
00057         {   .name               = "c2x4",
00058                 .units              = "uW",
00059                 .description        = "2x4 connector power", 
00060                 .resources.selector = 7
00061         },
00062         {   .name               = "vccp:pwr",
00063                 .units              = "uW",
00064                 .description        = "Core rail; Power reading", 
00065                 .resources.selector = 8
00066         },
00067         {   .name               = "vccp:cur",
00068                 .units              = "uA",
00069                 .description        = "Core rail; Current", 
00070                 .resources.selector = 9
00071         },
00072         {   .name               = "vccp:volt",
00073                 .units              = "uV",
00074                 .description        = "Core rail; Voltage", 
00075                 .resources.selector = 10
00076         },
00077         {   .name               = "vddg:pwr",
00078                 .units              = "uW",
00079                 .description        = "Uncore rail; Power reading", 
00080                 .resources.selector = 11
00081         },
00082         {   .name               = "vddg:cur",
00083                 .units              = "uA",
00084                 .description        = "Uncore rail; Current", 
00085                 .resources.selector = 12
00086         },
00087         {   .name               = "vddg:volt",
00088                 .units              = "uV",
00089                 .description        = "Uncore rail; Voltage", 
00090                 .resources.selector = 13
00091         },
00092         {   .name               = "vddq:pwr",
00093                 .units              = "uW",
00094                 .description        = "Memory sybsystem rail; Power reading", 
00095                 .resources.selector = 14
00096         },
00097         {   .name               = "vddq:cur",
00098                 .units              = "uA",
00099                 .description        = "Memory sybsystem rail; Current", 
00100                 .resources.selector = 15
00101         },
00102         {   .name               = "vddq:volt",
00103                 .units              = "uV",
00104                 .description        = "Memory sybsystem rail; Voltage", 
00105                 .resources.selector = 16
00106         }
00107 };
00108 
00109 static int num_events       = 0;
00110 static int is_initialized   = 0;
00111 
00112 /***************************************************************************/
00113 /******  BEGIN FUNCTIONS  USED INTERNALLY SPECIFIC TO THIS COMPONENT *******/
00114 /***************************************************************************/
00115 
00116 #if 0
00117 From Intel docs, power readings are exported via sysfs at
00118 /sys/class/micras/power
00119 
00120 typedeftruct mr_rsp_pws {   /* Power status */
00121   uint32_t  prr;                /* Current reading, in uW */
00122   uint8_t p_val;                /* Valid bits, power */
00123 } MrRspPws;
00124 
00125 typedef struct mr_rsp_vrr { /* Voltage regulator status */
00126   uint32_t pwr;                 /* Power reading, in uW */
00127   uint32_t cur;                 /* Current, in uA */
00128   uint32_t volt;                /* Voltage, in uV */
00129   uint8_t p_val;                /* Valid bits, power */
00130   uint8_t c_val;                /* Valid bits, current */
00131   uint8_t v_val;                /* Valid bits, voltage */
00132 } MrRspVrr;
00133 
00134 
00135 I am assuming for the purposes of this component that only
00136 the readings are exported.
00137 typedef struct mr_rsp_power {
00138   MrRspPws tot0;                /* Total power, win 0 */
00139   MrRspPws tot1;                /* Total power, win 1 */
00140   MrRspPws  pcie;               /* PCI-E connector power */
00141   MrRspPws  inst;               /* Instantaneous power */
00142   MrRspPws  imax;               /* Max Instantaneous power */
00143   MrRspPws  c2x3;               /* 2x3 connector power */
00144   MrRspPws  c2x4;               /* 2x4 connector power */
00145   MrRspVrr  vccp;               /* Core rail */
00146   MrRspVrr  vddg;               /* Uncore rail */
00147   MrRspVrr  vddq;               /* Memory subsystem rail */
00148 } MrRspPower;
00149 
00150 #endif
00151         static int 
00152 read_sysfs_file( long long* counts) 
00153 {
00154         FILE* fp = NULL;
00155         int i;
00156         int retval = 1;
00157         fp = fopen( "/sys/class/micras/power", "r" );
00158 
00159         for (i=0; i < MICPOWER_MAX_COUNTERS-9; i++) {
00160                 retval&= fscanf(fp, "%lld", &counts[i]);
00161         }
00162         for (i=MICPOWER_MAX_COUNTERS-9; i < MICPOWER_MAX_COUNTERS; i+=3) {
00163                 retval&= fscanf(fp, "%lld %lld %lld", &counts[i], &counts[i+1], &counts[i+2] );
00164         }
00165 
00166         return !retval;
00167 }
00168 
00169 /*****************************************************************************
00170  *******************  BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS  *************
00171  *****************************************************************************/
00172 
00173 /*
00174  * This is called whenever a thread is initialized
00175  */
00176         int 
00177 _micpower_init_thread( hwd_context_t *ctx )
00178 {
00179         ( void ) ctx;
00180         return PAPI_OK;
00181 }
00182 
00183 
00184 
00185 /* Initialize hardware counters, setup the function vector table
00186  * and get hardware information, this routine is called when the 
00187  * PAPI process is initialized (IE PAPI_library_init)
00188  */
00189         int 
00190 _micpower_init_component( int cidx )
00191 {
00192         if ( is_initialized )
00193                 return (PAPI_OK );
00194 
00195         is_initialized = 1;
00196 
00197         /* Check that /sys/class/micras/power is readable */
00198         if ( 0 != access( "/sys/class/micras/power", R_OK ) ) {
00199                 strncpy(_micpower_vector.cmp_info.disabled_reason,
00200                                 "Cannot read /sys/class/micras/power",PAPI_MAX_STR_LEN);
00201                 return PAPI_ENOCMP;
00202         }
00203 
00204 
00205         /* Export the total number of events available */
00206         num_events =
00207                 _micpower_vector.cmp_info.num_native_events = MICPOWER_NUMBER_OF_NATIVE_EVENTS;
00208 
00209         /* Export the component id */
00210         _micpower_vector.cmp_info.CmpIdx = cidx;
00211 
00212         return PAPI_OK;
00213 }
00214 
00215 
00216 
00217 
00218 /*
00219  * Control of counters (Reading/Writing/Starting/Stopping/Setup)
00220  * functions
00221  */
00222         int 
00223 _micpower_init_control_state( hwd_control_state_t * ctl)
00224 {
00225         int retval = 0;
00226         MICPOWER_control_state_t *micpower_ctl = (MICPOWER_control_state_t *) ctl;
00227 
00228         retval = read_sysfs_file(micpower_ctl->counts);
00229 
00230         /* Set last access time for caching results */
00231         micpower_ctl->lastupdate = PAPI_get_real_usec();
00232 
00233         return (retval)?PAPI_OK:PAPI_ESYS;
00234 }
00235 
00236         int 
00237 _micpower_start( hwd_context_t *ctx, hwd_control_state_t *ctl)
00238 {
00239         ( void ) ctx;
00240         ( void ) ctl;
00241 
00242         return PAPI_OK;
00243 }
00244 
00245         int 
00246 _micpower_read( hwd_context_t *ctx, hwd_control_state_t *ctl,
00247                 long long ** events, int flags)
00248 {
00249         (void) flags;
00250         (void) ctx;
00251         int retval = 0;
00252 
00253         MICPOWER_control_state_t* control = (MICPOWER_control_state_t*) ctl;
00254         long long now = PAPI_get_real_usec();
00255 
00256         /* Only read the values from the kernel if enough time has passed */
00257         /* since the last read.  Otherwise return cached values.          */
00258 
00259         if ( now - control->lastupdate > REFRESH_LAT ) {
00260                 retval = read_sysfs_file(control->counts);
00261                 control->lastupdate = now;
00262         }
00263 
00264         /* Pass back a pointer to our results */
00265         *events = control->counts;
00266 
00267         return (retval)?PAPI_OK:PAPI_ESYS;
00268 }
00269 
00270         int 
00271 _micpower_stop( hwd_context_t *ctx, hwd_control_state_t *ctl )
00272 {
00273         (void) ctx;
00274         int retval = 0;
00275         /* read values */
00276         MICPOWER_control_state_t* control = (MICPOWER_control_state_t*) ctl;
00277 
00278         retval = read_sysfs_file(control->counts);
00279         control->lastupdate = PAPI_get_real_usec();
00280         return (retval)?PAPI_OK:PAPI_ESYS;
00281 }
00282 
00283 /* Shutdown a thread */
00284         int
00285 _micpower_shutdown_thread( hwd_context_t * ctx )
00286 {
00287         ( void ) ctx;
00288         return PAPI_OK;
00289 }
00290 
00291 
00292 /*
00293  * Clean up what was setup in  micpower_init_component().
00294  */
00295         int 
00296 _micpower_shutdown_component( ) 
00297 {
00298         if ( is_initialized ) {
00299                 is_initialized = 0;
00300                 num_events = 0;
00301         }
00302         return PAPI_OK;
00303 }
00304 
00305 
00306 /* This function sets various options in the component
00307  * The valid codes being passed in are PAPI_SET_DEFDOM,
00308  * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT
00309  */
00310         int
00311 _micpower_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option )
00312 {
00313         ( void ) ctx;
00314         ( void ) code;
00315         ( void ) option;
00316 
00317         return PAPI_OK;
00318 }
00319 
00320 
00321         int
00322 _micpower_update_control_state( hwd_control_state_t *ptr,
00323                 NativeInfo_t * native, int count,
00324                 hwd_context_t * ctx )
00325 {
00326         int i, index;
00327         ( void ) ctx;
00328         ( void ) ptr;
00329 
00330         for ( i = 0; i < count; i++ ) {
00331                 index = native[i].ni_event;
00332                 native[i].ni_position = _micpower_native_events[index].resources.selector - 1;
00333         }
00334         return PAPI_OK;
00335 }
00336 
00337 
00338 /*
00339  * This function has to set the bits needed to count different domains
00340  * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
00341  * By default return PAPI_EINVAL if none of those are specified
00342  * and PAPI_OK with success
00343  * PAPI_DOM_USER is only user context is counted
00344  * PAPI_DOM_KERNEL is only the Kernel/OS context is counted
00345  * PAPI_DOM_OTHER  is Exception/transient mode (like user TLB misses)
00346  * PAPI_DOM_ALL   is all of the domains
00347  */
00348         int
00349 _micpower_set_domain( hwd_control_state_t * cntl, int domain )
00350 {
00351         int found = 0;
00352         ( void ) cntl;
00353 
00354         if ( PAPI_DOM_USER & domain )
00355                 found = 1;
00356 
00357         if ( PAPI_DOM_KERNEL & domain )
00358                 found = 1;
00359 
00360         if ( PAPI_DOM_OTHER & domain )
00361                 found = 1;
00362 
00363         if ( !found )
00364                 return PAPI_EINVAL;
00365 
00366         return PAPI_OK;
00367 }
00368 
00369 
00370         int
00371 _micpower_reset( hwd_context_t *ctx, hwd_control_state_t *ctl )
00372 {
00373         ( void ) ctx;
00374         ( void ) ctl;
00375 
00376         return PAPI_OK;
00377 }
00378 
00379 
00380 /*
00381  * Native Event functions
00382  */
00383         int
00384 _micpower_ntv_enum_events( unsigned int *EventCode, int modifier )
00385 {
00386 
00387         int index;
00388 
00389         switch ( modifier ) {
00390 
00391                 case PAPI_ENUM_FIRST:
00392 
00393                         if (num_events==0) {
00394                                 return PAPI_ENOEVNT;
00395                         }
00396                         *EventCode = 0;
00397 
00398                         return PAPI_OK;
00399 
00400 
00401                 case PAPI_ENUM_EVENTS:
00402 
00403                         index = *EventCode;
00404 
00405                         if ( index < num_events - 1 ) {
00406                                 *EventCode = *EventCode + 1;
00407                                 return PAPI_OK;
00408                         } else {
00409                                 return PAPI_ENOEVNT;
00410                         }
00411                         break;
00412 
00413                 default:
00414                         return PAPI_EINVAL;
00415         }
00416         return PAPI_EINVAL;
00417 }
00418 
00419 /*
00420  *
00421  */
00422         int
00423 _micpower_ntv_code_to_name( unsigned int EventCode, char *name, int len )
00424 {
00425         int index = EventCode;
00426 
00427         if ( index >= 0 && index < num_events ) {
00428                 strncpy( name, _micpower_native_events[index].name, len );
00429                 return PAPI_OK;
00430         }
00431         return PAPI_ENOEVNT;
00432 }
00433 
00434 /*
00435  *
00436  */
00437         int
00438 _micpower_ntv_code_to_descr( unsigned int EventCode, char *name, int len )
00439 {
00440         int index = EventCode;
00441 
00442         if ( index >= 0 && index < num_events ) {
00443                 strncpy( name, _micpower_native_events[index].description, len );
00444                 return PAPI_OK;
00445         }
00446         return PAPI_ENOEVNT;
00447 }
00448 
00449         int
00450 _micpower_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info) 
00451 {
00452 
00453         int index = EventCode;
00454 
00455         if ( ( index < 0) || (index >= num_events )) return PAPI_ENOEVNT;
00456 
00457         strncpy( info->symbol, _micpower_native_events[index].name, 
00458                         sizeof(info->symbol));
00459 
00460         strncpy( info->long_descr, _micpower_native_events[index].description, 
00461                         sizeof(info->long_descr));
00462 
00463         strncpy( info->units, _micpower_native_events[index].units, 
00464                         sizeof(info->units));
00465 
00466 
00467         return PAPI_OK;
00468 }
00469 
00470 
00471 
00472 /*
00473  *
00474  */
00475 papi_vector_t _micpower_vector = {
00476         .cmp_info = {
00477                 /* default component information (unspecified values are initialized to 0) */
00478                 .name = "mic-power",
00479                 .short_name = "micpower",
00480                 .description = "Component for reading power on Intel Xeon Phi (MIC)",
00481                 .version = "5.1",
00482                 .num_mpx_cntrs = MICPOWER_NUMBER_OF_NATIVE_EVENTS,
00483                 .num_cntrs = MICPOWER_NUMBER_OF_NATIVE_EVENTS,
00484                 .default_domain = PAPI_DOM_USER,
00485                 //.available_domains = PAPI_DOM_USER,
00486                 .default_granularity = PAPI_GRN_THR,
00487                 .available_granularities = PAPI_GRN_THR,
00488                 .hardware_intr_sig = PAPI_INT_SIGNAL,
00489 
00490                 /* component specific cmp_info initializations */
00491                 .fast_real_timer = 0,
00492                 .fast_virtual_timer = 0,
00493                 .attach = 0,
00494                 .attach_must_ptrace = 0,
00495                 .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL,
00496         }
00497         ,
00498 
00499                 /* sizes of framework-opaque component-private structures */
00500                 .size = {
00501                         .context = sizeof ( MICPOWER_context_t ),
00502                         .control_state = sizeof ( MICPOWER_control_state_t ),
00503                         .reg_value = sizeof ( MICPOWER_register_t ),
00504                         .reg_alloc = sizeof ( MICPOWER_reg_alloc_t ),
00505                 }
00506         ,
00507                 /* function pointers in this component */
00508                 .init_thread =          _micpower_init_thread,
00509                 .init_component =       _micpower_init_component,
00510                 .init_control_state =   _micpower_init_control_state,
00511                 .start =                _micpower_start,
00512                 .stop =                 _micpower_stop,
00513                 .read =                 _micpower_read,
00514                 .shutdown_thread =      _micpower_shutdown_thread,
00515                 .shutdown_component =   _micpower_shutdown_component,
00516                 .ctl =                  _micpower_ctl,
00517 
00518                 .update_control_state = _micpower_update_control_state,
00519                 .set_domain =           _micpower_set_domain,
00520                 .reset =                _micpower_reset,
00521 
00522                 .ntv_enum_events =      _micpower_ntv_enum_events,
00523                 .ntv_code_to_name =     _micpower_ntv_code_to_name,
00524                 .ntv_code_to_descr =    _micpower_ntv_code_to_descr,
00525                 .ntv_code_to_info =     _micpower_ntv_code_to_info,
00526 };
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines