|
PAPI
5.0.1.0
|
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 };