PAPI  5.3.0.0
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 subsystem rail; Power reading", 
00095                 .resources.selector = 14
00096         },
00097         {   .name               = "vddq:cur",
00098                 .units              = "uA",
00099                 .description        = "Memory subsystem rail; Current", 
00100                 .resources.selector = 15
00101         },
00102         {   .name               = "vddq:volt",
00103                 .units              = "uV",
00104                 .description        = "Memory subsystem 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         if (!fp)
00159             return 0;
00160 
00161         for (i=0; i < MICPOWER_MAX_COUNTERS-9; i++) {
00162                 retval&= fscanf(fp, "%lld", &counts[i]);
00163         }
00164         for (i=MICPOWER_MAX_COUNTERS-9; i < MICPOWER_MAX_COUNTERS; i+=3) {
00165                 retval&= fscanf(fp, "%lld %lld %lld", &counts[i], &counts[i+1], &counts[i+2] );
00166         }
00167 
00168         fclose(fp);
00169         return retval;
00170 }
00171 
00172 /*****************************************************************************
00173  *******************  BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS  *************
00174  *****************************************************************************/
00175 
00176 /*
00177  * This is called whenever a thread is initialized
00178  */
00179         int 
00180 _micpower_init_thread( hwd_context_t *ctx )
00181 {
00182         ( void ) ctx;
00183         return PAPI_OK;
00184 }
00185 
00186 
00187 
00188 /* Initialize hardware counters, setup the function vector table
00189  * and get hardware information, this routine is called when the 
00190  * PAPI process is initialized (IE PAPI_library_init)
00191  */
00192         int 
00193 _micpower_init_component( int cidx )
00194 {
00195         if ( is_initialized )
00196                 return (PAPI_OK );
00197 
00198         is_initialized = 1;
00199 
00200         /* Check that /sys/class/micras/power is readable */
00201         if ( 0 != access( "/sys/class/micras/power", R_OK ) ) {
00202                 strncpy(_micpower_vector.cmp_info.disabled_reason,
00203                                 "Cannot read /sys/class/micras/power",PAPI_MAX_STR_LEN);
00204                 return PAPI_ENOCMP;
00205         }
00206 
00207 
00208         /* Export the total number of events available */
00209         num_events =
00210                 _micpower_vector.cmp_info.num_native_events = MICPOWER_NUMBER_OF_NATIVE_EVENTS;
00211 
00212         /* Export the component id */
00213         _micpower_vector.cmp_info.CmpIdx = cidx;
00214 
00215         return PAPI_OK;
00216 }
00217 
00218 
00219 
00220 
00221 /*
00222  * Control of counters (Reading/Writing/Starting/Stopping/Setup)
00223  * functions
00224  */
00225         int 
00226 _micpower_init_control_state( hwd_control_state_t * ctl)
00227 {
00228         int retval = 0;
00229         MICPOWER_control_state_t *micpower_ctl = (MICPOWER_control_state_t *) ctl;
00230 
00231         retval = read_sysfs_file(micpower_ctl->counts);
00232 
00233         /* Set last access time for caching results */
00234         micpower_ctl->lastupdate = PAPI_get_real_usec();
00235 
00236         return (retval)?PAPI_OK:PAPI_ESYS;
00237 }
00238 
00239         int 
00240 _micpower_start( hwd_context_t *ctx, hwd_control_state_t *ctl)
00241 {
00242         ( void ) ctx;
00243         ( void ) ctl;
00244 
00245         return PAPI_OK;
00246 }
00247 
00248         int 
00249 _micpower_read( hwd_context_t *ctx, hwd_control_state_t *ctl,
00250                 long long ** events, int flags)
00251 {
00252         (void) flags;
00253         (void) ctx;
00254         int retval = 1;
00255 
00256         MICPOWER_control_state_t* control = (MICPOWER_control_state_t*) ctl;
00257         long long now = PAPI_get_real_usec();
00258 
00259         /* Only read the values from the kernel if enough time has passed */
00260         /* since the last read.  Otherwise return cached values.          */
00261 
00262         if ( now - control->lastupdate > REFRESH_LAT ) {
00263                 retval = read_sysfs_file(control->counts);
00264                 control->lastupdate = now;
00265         }
00266 
00267         /* Pass back a pointer to our results */
00268         *events = control->counts;
00269 
00270         return (retval)?PAPI_OK:PAPI_ESYS;
00271 }
00272 
00273         int 
00274 _micpower_stop( hwd_context_t *ctx, hwd_control_state_t *ctl )
00275 {
00276         (void) ctx;
00277         int retval = 1;
00278         long long now = PAPI_get_real_usec();
00279         /* read values */
00280         MICPOWER_control_state_t* control = (MICPOWER_control_state_t*) ctl;
00281 
00282         if ( now - control->lastupdate > REFRESH_LAT ) {
00283                 retval = read_sysfs_file(control->counts);
00284                 control->lastupdate = now;
00285         }
00286         return (retval)?PAPI_OK:PAPI_ESYS;
00287 }
00288 
00289 /* Shutdown a thread */
00290         int
00291 _micpower_shutdown_thread( hwd_context_t * ctx )
00292 {
00293         ( void ) ctx;
00294         return PAPI_OK;
00295 }
00296 
00297 
00298 /*
00299  * Clean up what was setup in  micpower_init_component().
00300  */
00301         int 
00302 _micpower_shutdown_component( ) 
00303 {
00304         if ( is_initialized ) {
00305                 is_initialized = 0;
00306                 num_events = 0;
00307         }
00308         return PAPI_OK;
00309 }
00310 
00311 
00312 /* This function sets various options in the component
00313  * The valid codes being passed in are PAPI_SET_DEFDOM,
00314  * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT
00315  */
00316         int
00317 _micpower_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option )
00318 {
00319         ( void ) ctx;
00320         ( void ) code;
00321         ( void ) option;
00322 
00323         return PAPI_OK;
00324 }
00325 
00326 
00327         int
00328 _micpower_update_control_state( hwd_control_state_t *ptr,
00329                 NativeInfo_t * native, int count,
00330                 hwd_context_t * ctx )
00331 {
00332         int i, index;
00333         ( void ) ctx;
00334         ( void ) ptr;
00335 
00336         for ( i = 0; i < count; i++ ) {
00337                 index = native[i].ni_event&PAPI_NATIVE_AND_MASK;
00338                 native[i].ni_position = _micpower_native_events[index].resources.selector - 1;
00339         }
00340         return PAPI_OK;
00341 }
00342 
00343 
00344 /*
00345  * This function has to set the bits needed to count different domains
00346  * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
00347  * By default return PAPI_EINVAL if none of those are specified
00348  * and PAPI_OK with success
00349  * PAPI_DOM_USER is only user context is counted
00350  * PAPI_DOM_KERNEL is only the Kernel/OS context is counted
00351  * PAPI_DOM_OTHER  is Exception/transient mode (like user TLB misses)
00352  * PAPI_DOM_ALL   is all of the domains
00353  */
00354         int
00355 _micpower_set_domain( hwd_control_state_t * cntl, int domain )
00356 {
00357         int found = 0;
00358         ( void ) cntl;
00359 
00360         if ( PAPI_DOM_USER & domain )
00361                 found = 1;
00362 
00363         if ( PAPI_DOM_KERNEL & domain )
00364                 found = 1;
00365 
00366         if ( PAPI_DOM_OTHER & domain )
00367                 found = 1;
00368 
00369         if ( !found )
00370                 return PAPI_EINVAL;
00371 
00372         return PAPI_OK;
00373 }
00374 
00375 
00376         int
00377 _micpower_reset( hwd_context_t *ctx, hwd_control_state_t *ctl )
00378 {
00379         ( void ) ctx;
00380         ( void ) ctl;
00381 
00382         return PAPI_OK;
00383 }
00384 
00385 
00386 /*
00387  * Native Event functions
00388  */
00389         int
00390 _micpower_ntv_enum_events( unsigned int *EventCode, int modifier )
00391 {
00392 
00393         int index;
00394 
00395         switch ( modifier ) {
00396 
00397                 case PAPI_ENUM_FIRST:
00398 
00399                         if (num_events==0) {
00400                                 return PAPI_ENOEVNT;
00401                         }
00402                         *EventCode = 0;
00403 
00404                         return PAPI_OK;
00405 
00406 
00407                 case PAPI_ENUM_EVENTS:
00408 
00409                         index = *EventCode&PAPI_NATIVE_AND_MASK;
00410 
00411                         if ( index < num_events - 1 ) {
00412                                 *EventCode = *EventCode + 1;
00413                                 return PAPI_OK;
00414                         } else {
00415                                 return PAPI_ENOEVNT;
00416                         }
00417                         break;
00418 
00419                 default:
00420                         return PAPI_EINVAL;
00421         }
00422         return PAPI_EINVAL;
00423 }
00424 
00425 /*
00426  *
00427  */
00428         int
00429 _micpower_ntv_code_to_name( unsigned int EventCode, char *name, int len )
00430 {
00431         int index = EventCode&PAPI_NATIVE_AND_MASK;
00432 
00433         if ( index >= 0 && index < num_events ) {
00434                 strncpy( name, _micpower_native_events[index].name, len );
00435                 return PAPI_OK;
00436         }
00437         return PAPI_ENOEVNT;
00438 }
00439 
00440 /*
00441  *
00442  */
00443         int
00444 _micpower_ntv_code_to_descr( unsigned int EventCode, char *name, int len )
00445 {
00446         int index = EventCode&PAPI_NATIVE_AND_MASK;
00447 
00448         if ( index >= 0 && index < num_events ) {
00449                 strncpy( name, _micpower_native_events[index].description, len );
00450                 return PAPI_OK;
00451         }
00452         return PAPI_ENOEVNT;
00453 }
00454 
00455         int
00456 _micpower_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info) 
00457 {
00458 
00459         int index = EventCode&PAPI_NATIVE_AND_MASK;
00460 
00461         if ( ( index < 0) || (index >= num_events )) return PAPI_ENOEVNT;
00462 
00463         strncpy( info->symbol, _micpower_native_events[index].name, 
00464                         sizeof(info->symbol));
00465 
00466         strncpy( info->long_descr, _micpower_native_events[index].description, 
00467                         sizeof(info->long_descr));
00468 
00469         strncpy( info->units, _micpower_native_events[index].units, 
00470                         sizeof(info->units));
00471 
00472 
00473         return PAPI_OK;
00474 }
00475 
00476 
00477 
00478 /*
00479  *
00480  */
00481 papi_vector_t _micpower_vector = {
00482         .cmp_info = {
00483                 /* default component information (unspecified values are initialized to 0) */
00484                 .name = "micpower",
00485                 .short_name = "micpower",
00486                 .description = "Component for reading power on Intel Xeon Phi (MIC)",
00487                 .version = "5.1",
00488                 .num_mpx_cntrs = MICPOWER_NUMBER_OF_NATIVE_EVENTS,
00489                 .num_cntrs = MICPOWER_NUMBER_OF_NATIVE_EVENTS,
00490                 .default_domain = PAPI_DOM_USER,
00491                 //.available_domains = PAPI_DOM_USER,
00492                 .default_granularity = PAPI_GRN_THR,
00493                 .available_granularities = PAPI_GRN_THR,
00494                 .hardware_intr_sig = PAPI_INT_SIGNAL,
00495 
00496                 /* component specific cmp_info initializations */
00497                 .fast_real_timer = 0,
00498                 .fast_virtual_timer = 0,
00499                 .attach = 0,
00500                 .attach_must_ptrace = 0,
00501                 .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL,
00502         }
00503         ,
00504 
00505                 /* sizes of framework-opaque component-private structures */
00506                 .size = {
00507                         .context = sizeof ( MICPOWER_context_t ),
00508                         .control_state = sizeof ( MICPOWER_control_state_t ),
00509                         .reg_value = sizeof ( MICPOWER_register_t ),
00510                         .reg_alloc = sizeof ( MICPOWER_reg_alloc_t ),
00511                 }
00512         ,
00513                 /* function pointers in this component */
00514                 .init_thread =          _micpower_init_thread,
00515                 .init_component =       _micpower_init_component,
00516                 .init_control_state =   _micpower_init_control_state,
00517                 .start =                _micpower_start,
00518                 .stop =                 _micpower_stop,
00519                 .read =                 _micpower_read,
00520                 .shutdown_thread =      _micpower_shutdown_thread,
00521                 .shutdown_component =   _micpower_shutdown_component,
00522                 .ctl =                  _micpower_ctl,
00523 
00524                 .update_control_state = _micpower_update_control_state,
00525                 .set_domain =           _micpower_set_domain,
00526                 .reset =                _micpower_reset,
00527 
00528                 .ntv_enum_events =      _micpower_ntv_enum_events,
00529                 .ntv_code_to_name =     _micpower_ntv_code_to_name,
00530                 .ntv_code_to_descr =    _micpower_ntv_code_to_descr,
00531                 .ntv_code_to_info =     _micpower_ntv_code_to_info,
00532 };
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines