PAPI  5.0.1.0
linux-coretemp.c
Go to the documentation of this file.
00001 #include <string.h>
00002 
00003 /* Headers required by PAPI */
00004 #include "papi.h"
00005 #include "papi_internal.h"
00006 #include "papi_vector.h"
00007 #include "papi_memory.h"
00008 
00009 #include "linux-coretemp.h"
00010 
00011 /* this is what I found on my core2 machine 
00012  * but I have not explored this widely yet*/
00013 #define REFRESH_LAT 4000
00014 
00015 #define INVALID_RESULT -1000000L
00016 
00017 papi_vector_t _coretemp_vector;
00018 
00019 /* temporary event */
00020 struct temp_event {
00021   char name[PAPI_MAX_STR_LEN];
00022   char units[PAPI_MIN_STR_LEN];
00023   char description[PAPI_MAX_STR_LEN];
00024   char location[PAPI_MAX_STR_LEN];
00025   char path[PATH_MAX];
00026   int stone;
00027   long count;
00028   struct temp_event *next;
00029 };
00030 
00031 
00032 static CORETEMP_native_event_entry_t * _coretemp_native_events;
00033 static int num_events       = 0;
00034 static int is_initialized   = 0;
00035 
00036 /***************************************************************************/
00037 /******  BEGIN FUNCTIONS  USED INTERNALLY SPECIFIC TO THIS COMPONENT *******/
00038 /***************************************************************************/
00039 
00040 static struct temp_event* root = NULL;
00041 static struct temp_event *last = NULL;
00042 
00043 static int
00044 insert_in_list(char *name, char *units,
00045            char *description, char *filename) {
00046 
00047 
00048     struct temp_event *temp;
00049 
00050 
00051     /* new_event   path, events->d_name */
00052     temp = (struct temp_event *) papi_calloc(sizeof(struct temp_event),1);
00053     if (temp==NULL) {
00054        PAPIERROR("out of memory!");
00055        /* We should also free any previously allocated data */
00056        return PAPI_ENOMEM;
00057     }
00058 
00059     temp->next = NULL;
00060 
00061     if (root == NULL) {
00062        root = temp;
00063     }
00064     else if (last) {
00065        last->next = temp;
00066     }
00067     else {
00068            /* Because this is a function, it is possible */
00069            /* we are called with root!=NULL but no last  */
00070            /* so add this to keep coverity happy         */
00071            free(temp);
00072            PAPIERROR("This shouldn't be possible\n");
00073 
00074            return PAPI_ECMP;
00075     }
00076 
00077     last = temp;
00078 
00079     snprintf(temp->name, PAPI_MAX_STR_LEN, "%s", name);
00080     snprintf(temp->units, PAPI_MIN_STR_LEN, "%s", units);
00081     snprintf(temp->description, PAPI_MAX_STR_LEN, "%s", description);
00082     snprintf(temp->path, PATH_MAX, "%s", filename);
00083 
00084     return PAPI_OK;
00085 }
00086 
00087 /*
00088  * find all coretemp information reported by the kernel
00089  */
00090 static int 
00091 generateEventList(char *base_dir)
00092 {
00093     char path[PATH_MAX],filename[PATH_MAX];
00094     char modulename[PAPI_MIN_STR_LEN],
00095          location[PAPI_MIN_STR_LEN],
00096          units[PAPI_MIN_STR_LEN],
00097          description[PAPI_MAX_STR_LEN],
00098          name[PAPI_MAX_STR_LEN];
00099     DIR *dir,*d;
00100     FILE *fff;
00101     int count = 0;
00102     struct dirent *hwmonx;
00103     int i,pathnum;
00104 
00105 #define NUM_PATHS 2
00106     char paths[NUM_PATHS][PATH_MAX]={
00107       "device","."
00108     };
00109 
00110     /* Open "/sys/class/hwmon" */
00111     dir = opendir(base_dir);
00112     if ( dir == NULL ) {
00113        SUBDBG("Can't find %s, are you sure the coretemp module is loaded?\n", 
00114            base_dir);
00115        return 0;
00116     }
00117 
00118     /* Iterate each /sys/class/hwmonX/device directory */
00119     while( (hwmonx = readdir(dir) ) ) {
00120        if ( !strncmp("hwmon", hwmonx->d_name, 5) ) {
00121 
00122      /* Found a hwmon directory */
00123 
00124      /* Sometimes the files are in ./, sometimes in device/ */
00125      for(pathnum=0;pathnum<NUM_PATHS;pathnum++) {
00126 
00127         snprintf(path, PATH_MAX, "%s/%s/%s", 
00128              base_dir, hwmonx->d_name,paths[pathnum]);
00129 
00130         SUBDBG("Trying to open %s\n",path);
00131         d = opendir(path);
00132         if (d==NULL) {
00133            continue;
00134         }
00135 
00136         /* Get the name of the module */
00137 
00138         snprintf(filename, PAPI_MAX_STR_LEN, "%s/name",path);
00139         fff=fopen(filename,"r");
00140         if (fff==NULL) {
00141            snprintf(modulename, PAPI_MIN_STR_LEN, "Unknown");
00142         } else {
00143            if (fgets(modulename,PAPI_MIN_STR_LEN,fff)!=NULL) {
00144               modulename[strlen(modulename)-1]='\0';
00145            }
00146            fclose(fff);
00147         }
00148 
00149         SUBDBG("Found module %s\n",modulename);
00150 
00151       /******************************************************/
00152       /* Try handling all events starting with in (voltage) */
00153       /******************************************************/
00154 
00155 
00156         /* arbitrary maximum */
00157         /* the problem is the numbering can be sparse */
00158         /* should probably go back to dirent listing  */
00159         
00160       for(i=0;i<32;i++) {
00161 
00162          /* Try looking for a location label */
00163          snprintf(filename, PAPI_MAX_STR_LEN, "%s/in%d_label", 
00164               path,i);
00165          fff=fopen(filename,"r");
00166          if (fff==NULL) {
00167             strncpy(location,"?",PAPI_MIN_STR_LEN);
00168          }
00169          else {
00170             if (fgets(location,PAPI_MIN_STR_LEN,fff)!=NULL) {
00171                location[strlen(location)-1]='\0';
00172             }
00173             fclose(fff);
00174          }
00175 
00176          /* Look for input temperature */
00177          snprintf(filename, PAPI_MAX_STR_LEN, "%s/in%d_input", 
00178               path,i);
00179          fff=fopen(filename,"r");
00180          if (fff==NULL) continue;
00181          fclose(fff);
00182 
00183          snprintf(name, PAPI_MAX_STR_LEN, "%s:in%i_input", 
00184              hwmonx->d_name, i);
00185          snprintf(units, PAPI_MIN_STR_LEN, "V");
00186          snprintf(description, PAPI_MAX_STR_LEN, "%s, %s module, label %s",
00187               units,modulename,
00188               location);
00189 
00190          if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
00191             goto done_error;
00192          }
00193 
00194          count++;
00195 
00196       }
00197 
00198       /************************************************************/
00199       /* Try handling all events starting with temp (temperature) */
00200       /************************************************************/
00201 
00202       for(i=0;i<32;i++) {
00203 
00204          /* Try looking for a location label */
00205          snprintf(filename, PAPI_MAX_STR_LEN, "%s/temp%d_label", 
00206               path,i);
00207          fff=fopen(filename,"r");
00208          if (fff==NULL) {
00209             strncpy(location,"?",PAPI_MIN_STR_LEN);
00210          }
00211          else {
00212             if (fgets(location,PAPI_MIN_STR_LEN,fff)!=NULL) {
00213                location[strlen(location)-1]='\0';
00214             }
00215             fclose(fff);
00216          }
00217 
00218          /* Look for input temperature */
00219          snprintf(filename, PAPI_MAX_STR_LEN, "%s/temp%d_input", 
00220               path,i);
00221          fff=fopen(filename,"r");
00222          if (fff==NULL) continue;
00223          fclose(fff);
00224 
00225          snprintf(name, PAPI_MAX_STR_LEN, "%s:temp%i_input", 
00226              hwmonx->d_name, i);
00227          snprintf(units, PAPI_MIN_STR_LEN, "degrees C");
00228          snprintf(description, PAPI_MAX_STR_LEN, "%s, %s module, label %s",
00229               units,modulename,
00230               location);
00231 
00232          if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
00233             goto done_error;
00234          }
00235 
00236          count++;
00237       }
00238 
00239       /************************************************************/
00240       /* Try handling all events starting with fan (fan)          */
00241       /************************************************************/
00242 
00243       for(i=0;i<32;i++) {
00244 
00245          /* Try looking for a location label */
00246          snprintf(filename, PAPI_MAX_STR_LEN, "%s/fan%d_label", 
00247               path,i);
00248          fff=fopen(filename,"r");
00249          if (fff==NULL) {
00250             strncpy(location,"?",PAPI_MIN_STR_LEN);
00251          }
00252          else {
00253             if (fgets(location,PAPI_MIN_STR_LEN,fff)!=NULL) {
00254                location[strlen(location)-1]='\0';
00255             }
00256             fclose(fff);
00257          }
00258 
00259          /* Look for input fan */
00260          snprintf(filename, PAPI_MAX_STR_LEN, "%s/fan%d_input", 
00261               path,i);
00262          fff=fopen(filename,"r");
00263          if (fff==NULL) continue;
00264          fclose(fff);
00265 
00266          snprintf(name, PAPI_MAX_STR_LEN, "%s:fan%i_input", 
00267              hwmonx->d_name, i);
00268          snprintf(units, PAPI_MIN_STR_LEN, "RPM");
00269          snprintf(description, PAPI_MAX_STR_LEN, "%s, %s module, label %s",
00270               units,modulename,
00271               location);
00272 
00273          if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
00274             goto done_error;
00275          }
00276 
00277          count++;
00278 
00279       }
00280       closedir(d);
00281      }
00282        }
00283     }
00284 
00285     closedir(dir);
00286     return count;
00287 
00288 done_error:
00289     closedir(d);
00290     closedir(dir);
00291     return PAPI_ECMP;
00292 }
00293 
00294 static long long
00295 getEventValue( int index ) 
00296 {
00297     char buf[PAPI_MAX_STR_LEN];
00298     FILE* fp;
00299     long result;
00300 
00301     if (_coretemp_native_events[index].stone) {
00302        return _coretemp_native_events[index].value;
00303     }
00304 
00305     fp = fopen(_coretemp_native_events[index].path, "r");
00306     if (fp==NULL) {
00307        return INVALID_RESULT;
00308     }
00309 
00310     if (fgets(buf, PAPI_MAX_STR_LEN, fp)==NULL) {
00311         result=INVALID_RESULT;
00312     }
00313     else {
00314         result=strtoll(buf, NULL, 10);
00315     }
00316     fclose(fp);
00317 
00318     return result;
00319 }
00320 
00321 /*****************************************************************************
00322  *******************  BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS  *************
00323  *****************************************************************************/
00324 
00325 /*
00326  * This is called whenever a thread is initialized
00327  */
00328 int 
00329 _coretemp_init_thread( hwd_context_t *ctx )
00330 {
00331   ( void ) ctx;
00332   return PAPI_OK;
00333 }
00334 
00335 
00336 
00337 /* Initialize hardware counters, setup the function vector table
00338  * and get hardware information, this routine is called when the 
00339  * PAPI process is initialized (IE PAPI_library_init)
00340  */
00341 int 
00342 _coretemp_init_component( int cidx )
00343 {
00344      int i = 0;
00345      struct temp_event *t,*last;
00346 
00347      if ( is_initialized )
00348     return (PAPI_OK );
00349 
00350      is_initialized = 1;
00351 
00352      /* This is the prefered method, all coretemp sensors are symlinked here
00353       * see $(kernel_src)/Documentation/hwmon/sysfs-interface */
00354   
00355      num_events = generateEventList("/sys/class/hwmon");
00356 
00357      if ( num_events < 0 ) {
00358         strncpy(_coretemp_vector.cmp_info.disabled_reason,
00359         "Cannot open /sys/class/hwmon",PAPI_MAX_STR_LEN);
00360     return PAPI_ENOCMP;
00361      }
00362 
00363      if ( num_events == 0 ) {
00364         strncpy(_coretemp_vector.cmp_info.disabled_reason,
00365         "No coretemp events found",PAPI_MAX_STR_LEN);
00366     return PAPI_ENOCMP;
00367      }
00368 
00369      t = root;
00370   
00371      _coretemp_native_events = (CORETEMP_native_event_entry_t*)
00372           papi_calloc(sizeof(CORETEMP_native_event_entry_t),num_events);
00373 
00374      do {
00375     strncpy(_coretemp_native_events[i].name,t->name,PAPI_MAX_STR_LEN);
00376     strncpy(_coretemp_native_events[i].path,t->path,PATH_MAX);
00377     strncpy(_coretemp_native_events[i].units,t->units,PAPI_MIN_STR_LEN);
00378     strncpy(_coretemp_native_events[i].description,t->description,
00379             PAPI_MAX_STR_LEN);
00380     _coretemp_native_events[i].stone = 0;
00381     _coretemp_native_events[i].resources.selector = i + 1;
00382     last    = t;
00383     t       = t->next;
00384     papi_free(last);
00385     i++;
00386      } while (t != NULL);
00387      root = NULL;
00388 
00389      /* Export the total number of events available */
00390      _coretemp_vector.cmp_info.num_native_events = num_events;
00391 
00392      /* Export the component id */
00393      _coretemp_vector.cmp_info.CmpIdx = cidx;
00394 
00395      return PAPI_OK;
00396 }
00397 
00398 
00399 
00400 
00401 /*
00402  * Control of counters (Reading/Writing/Starting/Stopping/Setup)
00403  * functions
00404  */
00405 int 
00406 _coretemp_init_control_state( hwd_control_state_t * ctl)
00407 {
00408     int i;
00409 
00410     CORETEMP_control_state_t *coretemp_ctl = (CORETEMP_control_state_t *) ctl;
00411 
00412     for ( i=0; i < num_events; i++ ) {
00413     coretemp_ctl->counts[i] = getEventValue(i);
00414     }
00415 
00416     /* Set last access time for caching results */
00417     coretemp_ctl->lastupdate = PAPI_get_real_usec();
00418 
00419     return PAPI_OK;
00420 }
00421 
00422 int 
00423 _coretemp_start( hwd_context_t *ctx, hwd_control_state_t *ctl)
00424 {
00425   ( void ) ctx;
00426   ( void ) ctl;
00427 
00428   return PAPI_OK;
00429 }
00430 
00431 int 
00432 _coretemp_read( hwd_context_t *ctx, hwd_control_state_t *ctl,
00433             long long ** events, int flags)
00434 {
00435     (void) flags;
00436     (void) ctx;
00437 
00438     CORETEMP_control_state_t* control = (CORETEMP_control_state_t*) ctl;
00439     long long now = PAPI_get_real_usec();
00440     int i;
00441 
00442     /* Only read the values from the kernel if enough time has passed */
00443     /* since the last read.  Otherwise return cached values.          */
00444 
00445     if ( now - control->lastupdate > REFRESH_LAT ) {
00446     for ( i = 0; i < num_events; i++ ) {
00447        control->counts[i] = getEventValue( i );
00448     }
00449     control->lastupdate = now;
00450     }
00451 
00452     /* Pass back a pointer to our results */
00453     *events = control->counts;
00454 
00455     return PAPI_OK;
00456 }
00457 
00458 int 
00459 _coretemp_stop( hwd_context_t *ctx, hwd_control_state_t *ctl )
00460 {
00461     (void) ctx;
00462     /* read values */
00463     CORETEMP_control_state_t* control = (CORETEMP_control_state_t*) ctl;
00464     int i;
00465 
00466     for ( i = 0; i < num_events; i++ ) {
00467     control->counts[i] = getEventValue( i );
00468     }
00469 
00470     return PAPI_OK;
00471 }
00472 
00473 /* Shutdown a thread */
00474 int
00475 _coretemp_shutdown_thread( hwd_context_t * ctx )
00476 {
00477   ( void ) ctx;
00478   return PAPI_OK;
00479 }
00480 
00481 
00482 /*
00483  * Clean up what was setup in  coretemp_init_component().
00484  */
00485 int 
00486 _coretemp_shutdown_component( ) 
00487 {
00488     if ( is_initialized ) {
00489        is_initialized = 0;
00490        papi_free(_coretemp_native_events);
00491        _coretemp_native_events = NULL;
00492     }
00493     return PAPI_OK;
00494 }
00495 
00496 
00497 /* This function sets various options in the component
00498  * The valid codes being passed in are PAPI_SET_DEFDOM,
00499  * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT
00500  */
00501 int
00502 _coretemp_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option )
00503 {
00504     ( void ) ctx;
00505     ( void ) code;
00506     ( void ) option;
00507 
00508     return PAPI_OK;
00509 }
00510 
00511 
00512 int
00513 _coretemp_update_control_state( hwd_control_state_t *ptr,
00514                 NativeInfo_t * native, int count,
00515                 hwd_context_t * ctx )
00516 {
00517     int i, index;
00518     ( void ) ctx;
00519     ( void ) ptr;
00520 
00521     for ( i = 0; i < count; i++ ) {
00522     index = native[i].ni_event;
00523     native[i].ni_position = _coretemp_native_events[index].resources.selector - 1;
00524     }
00525     return PAPI_OK;
00526 }
00527 
00528 
00529 /*
00530  * This function has to set the bits needed to count different domains
00531  * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
00532  * By default return PAPI_EINVAL if none of those are specified
00533  * and PAPI_OK with success
00534  * PAPI_DOM_USER is only user context is counted
00535  * PAPI_DOM_KERNEL is only the Kernel/OS context is counted
00536  * PAPI_DOM_OTHER  is Exception/transient mode (like user TLB misses)
00537  * PAPI_DOM_ALL   is all of the domains
00538  */
00539 int
00540 _coretemp_set_domain( hwd_control_state_t * cntl, int domain )
00541 {
00542     int found = 0;
00543     ( void ) cntl;
00544     
00545     if ( PAPI_DOM_USER & domain )
00546        found = 1;
00547 
00548        if ( PAPI_DOM_KERNEL & domain )
00549         found = 1;
00550 
00551        if ( PAPI_DOM_OTHER & domain )
00552         found = 1;
00553 
00554        if ( !found )
00555         return PAPI_EINVAL;
00556 
00557        return PAPI_OK;
00558 }
00559 
00560 
00561 int
00562 _coretemp_reset( hwd_context_t *ctx, hwd_control_state_t *ctl )
00563 {
00564     ( void ) ctx;
00565     ( void ) ctl;
00566     
00567     return PAPI_OK;
00568 }
00569 
00570 
00571 /*
00572  * Native Event functions
00573  */
00574 int
00575 _coretemp_ntv_enum_events( unsigned int *EventCode, int modifier )
00576 {
00577 
00578      int index;
00579 
00580      switch ( modifier ) {
00581 
00582     case PAPI_ENUM_FIRST:
00583 
00584        if (num_events==0) {
00585           return PAPI_ENOEVNT;
00586        }
00587        *EventCode = 0;
00588 
00589        return PAPI_OK;
00590         
00591 
00592     case PAPI_ENUM_EVENTS:
00593     
00594        index = *EventCode;
00595 
00596        if ( index < num_events - 1 ) {
00597           *EventCode = *EventCode + 1;
00598           return PAPI_OK;
00599        } else {
00600           return PAPI_ENOEVNT;
00601        }
00602        break;
00603     
00604     default:
00605         return PAPI_EINVAL;
00606     }
00607     return PAPI_EINVAL;
00608 }
00609 
00610 /*
00611  *
00612  */
00613 int
00614 _coretemp_ntv_code_to_name( unsigned int EventCode, char *name, int len )
00615 {
00616      int index = EventCode;
00617 
00618      if ( index >= 0 && index < num_events ) {
00619     strncpy( name, _coretemp_native_events[index].name, len );
00620     return PAPI_OK;
00621      }
00622      return PAPI_ENOEVNT;
00623 }
00624 
00625 /*
00626  *
00627  */
00628 int
00629 _coretemp_ntv_code_to_descr( unsigned int EventCode, char *name, int len )
00630 {
00631      int index = EventCode;
00632 
00633      if ( index >= 0 && index < num_events ) {
00634     strncpy( name, _coretemp_native_events[index].description, len );
00635     return PAPI_OK;
00636      }
00637      return PAPI_ENOEVNT;
00638 }
00639 
00640 int
00641 _coretemp_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info) 
00642 {
00643 
00644   int index = EventCode;
00645 
00646   if ( ( index < 0) || (index >= num_events )) return PAPI_ENOEVNT;
00647 
00648   strncpy( info->symbol, _coretemp_native_events[index].name, 
00649        sizeof(info->symbol));
00650 
00651   strncpy( info->long_descr, _coretemp_native_events[index].description, 
00652        sizeof(info->long_descr));
00653 
00654   strncpy( info->units, _coretemp_native_events[index].units, 
00655        sizeof(info->units));
00656 
00657 
00658   return PAPI_OK;
00659 }
00660 
00661 
00662 
00663 /*
00664  *
00665  */
00666 papi_vector_t _coretemp_vector = {
00667     .cmp_info = {
00668                  /* default component information (unspecified values are initialized to 0) */
00669                  .name = "coretemp",
00670                  .short_name = "coretemp",
00671                  .description = "Linux hwmon temperature and other info",
00672                  .version = "4.2.1",
00673                  .num_mpx_cntrs = CORETEMP_MAX_COUNTERS,
00674                  .num_cntrs = CORETEMP_MAX_COUNTERS,
00675                  .default_domain = PAPI_DOM_USER,
00676                  //.available_domains = PAPI_DOM_USER,
00677                  .default_granularity = PAPI_GRN_THR,
00678                  .available_granularities = PAPI_GRN_THR,
00679                  .hardware_intr_sig = PAPI_INT_SIGNAL,
00680 
00681                  /* component specific cmp_info initializations */
00682                  .fast_real_timer = 0,
00683                  .fast_virtual_timer = 0,
00684                  .attach = 0,
00685                  .attach_must_ptrace = 0,
00686                  .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL,
00687                  }
00688     ,
00689 
00690     /* sizes of framework-opaque component-private structures */
00691     .size = {
00692              .context = sizeof ( CORETEMP_context_t ),
00693              .control_state = sizeof ( CORETEMP_control_state_t ),
00694              .reg_value = sizeof ( CORETEMP_register_t ),
00695              .reg_alloc = sizeof ( CORETEMP_reg_alloc_t ),
00696              }
00697     ,
00698     /* function pointers in this component */
00699     .init_thread =          _coretemp_init_thread,
00700     .init_component =       _coretemp_init_component,
00701     .init_control_state =   _coretemp_init_control_state,
00702     .start =                _coretemp_start,
00703     .stop =                 _coretemp_stop,
00704     .read =                 _coretemp_read,
00705     .shutdown_thread =      _coretemp_shutdown_thread,
00706     .shutdown_component =   _coretemp_shutdown_component,
00707     .ctl =                  _coretemp_ctl,
00708 
00709     .update_control_state = _coretemp_update_control_state,
00710     .set_domain =           _coretemp_set_domain,
00711     .reset =                _coretemp_reset,
00712 
00713     .ntv_enum_events =      _coretemp_ntv_enum_events,
00714     .ntv_code_to_name =     _coretemp_ntv_code_to_name,
00715     .ntv_code_to_descr =    _coretemp_ntv_code_to_descr,
00716     .ntv_code_to_info =     _coretemp_ntv_code_to_info,
00717 };
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines