PAPI  5.7.0.0
linux-coretemp.c
Go to the documentation of this file.
1 #include <string.h>
2 
3 /* Headers required by PAPI */
4 #include "papi.h"
5 #include "papi_internal.h"
6 #include "papi_vector.h"
7 #include "papi_memory.h"
8 
9 #include "linux-coretemp.h"
10 
11 /* this is what I found on my core2 machine
12  * but I have not explored this widely yet*/
13 #define REFRESH_LAT 4000
14 
15 #define INVALID_RESULT -1000000L
16 
18 
19 /* temporary event */
20 struct temp_event {
25  char path[PATH_MAX];
26  int stone;
27  long count;
28  struct temp_event *next;
29 };
30 
31 
33 static int num_events = 0;
34 static int is_initialized = 0;
35 
36 /***************************************************************************/
37 /****** BEGIN FUNCTIONS USED INTERNALLY SPECIFIC TO THIS COMPONENT *******/
38 /***************************************************************************/
39 
40 static struct temp_event* root = NULL;
41 static struct temp_event *last = NULL;
42 
43 static int
44 insert_in_list(char *name, char *units,
45  char *description, char *filename) {
46 
47 
48  struct temp_event *temp;
49 
50 
51  /* new_event path, events->d_name */
52  temp = (struct temp_event *) papi_calloc(1, sizeof(struct temp_event));
53  if (temp==NULL) {
54  PAPIERROR("out of memory!");
55  /* We should also free any previously allocated data */
56  return PAPI_ENOMEM;
57  }
58 
59  temp->next = NULL;
60 
61  if (root == NULL) {
62  root = temp;
63  }
64  else if (last) {
65  last->next = temp;
66  }
67  else {
68  /* Because this is a function, it is possible */
69  /* we are called with root!=NULL but no last */
70  /* so add this to keep coverity happy */
71  free(temp);
72  PAPIERROR("This shouldn't be possible\n");
73 
74  return PAPI_ECMP;
75  }
76 
77  last = temp;
78 
79  snprintf(temp->name, PAPI_MAX_STR_LEN, "%s", name);
80  snprintf(temp->units, PAPI_MIN_STR_LEN, "%s", units);
81  snprintf(temp->description, PAPI_MAX_STR_LEN, "%s", description);
82  snprintf(temp->path, PATH_MAX, "%s", filename);
83 
84  return PAPI_OK;
85 }
86 
87 /*
88  * find all coretemp information reported by the kernel
89  */
90 static int
91 generateEventList(char *base_dir)
92 {
94  char modulename[PAPI_MIN_STR_LEN],
99  DIR *dir,*d;
100  FILE *fff;
101  int count = 0;
102  struct dirent *hwmonx;
103  int i,pathnum;
104  int retlen;
105 
106 #define NUM_PATHS 2
107  char paths[NUM_PATHS][PATH_MAX]={
108  "device","."
109  };
110 
111  /* Open "/sys/class/hwmon" */
112  dir = opendir(base_dir);
113  if ( dir == NULL ) {
114  SUBDBG("Can't find %s, are you sure the coretemp module is loaded?\n",
115  base_dir);
116  return 0;
117  }
118 
119  /* Iterate each /sys/class/hwmonX/device directory */
120  while( (hwmonx = readdir(dir) ) ) {
121  if ( !strncmp("hwmon", hwmonx->d_name, 5) ) {
122 
123  /* Found a hwmon directory */
124 
125  /* Sometimes the files are in ./, sometimes in device/ */
126  for(pathnum=0;pathnum<NUM_PATHS;pathnum++) {
127 
128  snprintf(path, PATH_MAX, "%s/%s/%s",
129  base_dir, hwmonx->d_name,paths[pathnum]);
130 
131  SUBDBG("Trying to open %s\n",path);
132  d = opendir(path);
133  if (d==NULL) {
134  continue;
135  }
136 
137  /* Get the name of the module */
138 
139  snprintf(filename, PAPI_MAX_STR_LEN, "%s/name",path);
140  fff=fopen(filename,"r");
141  if (fff==NULL) {
142  snprintf(modulename, PAPI_MIN_STR_LEN, "Unknown");
143  } else {
144  if (fgets(modulename,PAPI_MIN_STR_LEN,fff)!=NULL) {
145  modulename[strlen(modulename)-1]='\0';
146  }
147  fclose(fff);
148  }
149 
150  SUBDBG("Found module %s\n",modulename);
151 
152  /******************************************************/
153  /* Try handling all events starting with in (voltage) */
154  /******************************************************/
155 
156 
157  /* arbitrary maximum */
158  /* the problem is the numbering can be sparse */
159  /* should probably go back to dirent listing */
160 
161  for(i=0;i<32;i++) {
162 
163  /* Try looking for a location label */
164  snprintf(filename, PAPI_MAX_STR_LEN, "%s/in%d_label",
165  path,i);
166  fff=fopen(filename,"r");
167  if (fff==NULL) {
168  strncpy(location,"?",PAPI_MIN_STR_LEN);
169  }
170  else {
171  if (fgets(location,PAPI_MIN_STR_LEN,fff)!=NULL) {
172  location[strlen(location)-1]='\0';
173  }
174  fclose(fff);
175  }
176 
177  /* Look for input temperature */
178  snprintf(filename, PAPI_MAX_STR_LEN, "%s/in%d_input",
179  path,i);
180  fff=fopen(filename,"r");
181  if (fff==NULL) continue;
182  fclose(fff);
183 
184  retlen = snprintf(name, PAPI_MAX_STR_LEN, "%s:in%i_input", hwmonx->d_name, i);
185  if (retlen <= 0 || PAPI_MAX_STR_LEN <= retlen) {
186  SUBDBG("Unable to generate name %s:in%i_input\n", hwmonx->d_name, i);
187  return ( PAPI_EINVAL );
188  }
189 
190  snprintf(units, PAPI_MIN_STR_LEN, "V");
191  snprintf(description, PAPI_MAX_STR_LEN, "%s, %s module, label %s",
192  units,modulename,
193  location);
194 
195  if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
196  goto done_error;
197  }
198 
199  count++;
200 
201  }
202 
203  /************************************************************/
204  /* Try handling all events starting with temp (temperature) */
205  /************************************************************/
206 
207  for(i=0;i<32;i++) {
208 
209  /* Try looking for a location label */
210  snprintf(filename, PAPI_MAX_STR_LEN, "%s/temp%d_label",
211  path,i);
212  fff=fopen(filename,"r");
213  if (fff==NULL) {
214  strncpy(location,"?",PAPI_MIN_STR_LEN);
215  }
216  else {
217  if (fgets(location,PAPI_MIN_STR_LEN,fff)!=NULL) {
218  location[strlen(location)-1]='\0';
219  }
220  fclose(fff);
221  }
222 
223  /* Look for input temperature */
224  snprintf(filename, PAPI_MAX_STR_LEN, "%s/temp%d_input",
225  path,i);
226  fff=fopen(filename,"r");
227  if (fff==NULL) continue;
228  fclose(fff);
229 
230  retlen = snprintf(name, PAPI_MAX_STR_LEN, "%s:temp%i_input", hwmonx->d_name, i);
231  if (retlen <= 0 || PAPI_MAX_STR_LEN <= retlen) {
232  SUBDBG("Unable to generate name %s:temp%i_input\n", hwmonx->d_name, i);
233  return ( PAPI_EINVAL );
234  }
235 
236  snprintf(units, PAPI_MIN_STR_LEN, "degrees C");
237  snprintf(description, PAPI_MAX_STR_LEN, "%s, %s module, label %s",
238  units,modulename,
239  location);
240 
241  if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
242  goto done_error;
243  }
244 
245  count++;
246  }
247 
248  /************************************************************/
249  /* Try handling all events starting with fan (fan) */
250  /************************************************************/
251 
252  for(i=0;i<32;i++) {
253 
254  /* Try looking for a location label */
255  snprintf(filename, PAPI_MAX_STR_LEN, "%s/fan%d_label",
256  path,i);
257  fff=fopen(filename,"r");
258  if (fff==NULL) {
259  strncpy(location,"?",PAPI_MIN_STR_LEN);
260  }
261  else {
262  if (fgets(location,PAPI_MIN_STR_LEN,fff)!=NULL) {
263  location[strlen(location)-1]='\0';
264  }
265  fclose(fff);
266  }
267 
268  /* Look for input fan */
269  retlen = snprintf(filename, PAPI_MAX_STR_LEN, "%s/fan%d_input", path,i);
270  if (retlen <= 0 || PAPI_MAX_STR_LEN <= retlen) {
271  SUBDBG("Unable to generate filename %s/fan%d_input\n", path,i);
272  return ( PAPI_EINVAL );
273  }
274 
275  fff=fopen(filename,"r");
276  if (fff==NULL) continue;
277  fclose(fff);
278 
279  retlen = snprintf(name, PAPI_MAX_STR_LEN, "%s:fan%i_input", hwmonx->d_name, i);
280  if (retlen <= 0 || PAPI_MAX_STR_LEN <= retlen) {
281  SUBDBG("Unable to generate name %s:fan%i_input\n", hwmonx->d_name, i);
282  return ( PAPI_EINVAL );
283  }
284 
285  snprintf(units, PAPI_MIN_STR_LEN, "RPM");
286  snprintf(description, PAPI_MAX_STR_LEN, "%s, %s module, label %s",
287  units,modulename,
288  location);
289 
290  if (insert_in_list(name,units,description,filename)!=PAPI_OK) {
291  goto done_error;
292  }
293 
294  count++;
295 
296  }
297  closedir(d);
298  }
299  }
300  }
301 
302  closedir(dir);
303  return count;
304 
305 done_error:
306  closedir(d);
307  closedir(dir);
308  return PAPI_ECMP;
309 }
310 
311 static long long
312 getEventValue( int index )
313 {
314  char buf[PAPI_MAX_STR_LEN];
315  FILE* fp;
316  long result;
317 
318  if (_coretemp_native_events[index].stone) {
319  return _coretemp_native_events[index].value;
320  }
321 
322  fp = fopen(_coretemp_native_events[index].path, "r");
323  if (fp==NULL) {
324  return INVALID_RESULT;
325  }
326 
327  if (fgets(buf, PAPI_MAX_STR_LEN, fp)==NULL) {
328  result=INVALID_RESULT;
329  }
330  else {
331  result=strtoll(buf, NULL, 10);
332  }
333  fclose(fp);
334 
335  return result;
336 }
337 
338 /*****************************************************************************
339  ******************* BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS *************
340  *****************************************************************************/
341 
342 /*
343  * This is called whenever a thread is initialized
344  */
345 static int
347 {
348  ( void ) ctx;
349  return PAPI_OK;
350 }
351 
352 
353 
354 /* Initialize hardware counters, setup the function vector table
355  * and get hardware information, this routine is called when the
356  * PAPI process is initialized (IE PAPI_library_init)
357  */
358 static int
360 {
361  int i = 0;
362  struct temp_event *t,*last;
363 
364  if ( is_initialized )
365  return (PAPI_OK );
366 
367  is_initialized = 1;
368 
369  /* This is the prefered method, all coretemp sensors are symlinked here
370  * see $(kernel_src)/Documentation/hwmon/sysfs-interface */
371 
372  num_events = generateEventList("/sys/class/hwmon");
373 
374  if ( num_events < 0 ) {
376  "Cannot open /sys/class/hwmon",PAPI_MAX_STR_LEN);
377  return PAPI_ENOCMP;
378  }
379 
380  if ( num_events == 0 ) {
382  "No coretemp events found",PAPI_MAX_STR_LEN);
383  return PAPI_ENOCMP;
384  }
385 
386  t = root;
387 
390 
391  do {
402  last = t;
403  t = t->next;
404  papi_free(last);
405  i++;
406  } while (t != NULL);
407  root = NULL;
408 
409  /* Export the total number of events available */
411 
412  /* Export the component id */
414 
415  return PAPI_OK;
416 }
417 
418 
419 
420 
421 /*
422  * Control of counters (Reading/Writing/Starting/Stopping/Setup)
423  * functions
424  */
425 static int
427 {
428  int i;
429 
431 
432  for ( i=0; i < num_events; i++ ) {
433  coretemp_ctl->counts[i] = getEventValue(i);
434  }
435 
436  /* Set last access time for caching results */
437  coretemp_ctl->lastupdate = PAPI_get_real_usec();
438 
439  return PAPI_OK;
440 }
441 
442 static int
444 {
445  ( void ) ctx;
446  ( void ) ctl;
447 
448  return PAPI_OK;
449 }
450 
451 static int
453  long long ** events, int flags)
454 {
455  (void) flags;
456  (void) ctx;
457 
459  long long now = PAPI_get_real_usec();
460  int i;
461 
462  /* Only read the values from the kernel if enough time has passed */
463  /* since the last read. Otherwise return cached values. */
464 
465  if ( now - control->lastupdate > REFRESH_LAT ) {
466  for ( i = 0; i < num_events; i++ ) {
467  control->counts[i] = getEventValue( i );
468  }
469  control->lastupdate = now;
470  }
471 
472  /* Pass back a pointer to our results */
473  *events = control->counts;
474 
475  return PAPI_OK;
476 }
477 
478 static int
480 {
481  (void) ctx;
482  /* read values */
484  int i;
485 
486  for ( i = 0; i < num_events; i++ ) {
487  control->counts[i] = getEventValue( i );
488  }
489 
490  return PAPI_OK;
491 }
492 
493 /* Shutdown a thread */
494 static int
496 {
497  ( void ) ctx;
498  return PAPI_OK;
499 }
500 
501 
502 /*
503  * Clean up what was setup in coretemp_init_component().
504  */
505 static int
507 {
508  if ( is_initialized ) {
509  is_initialized = 0;
512  }
513  return PAPI_OK;
514 }
515 
516 
517 /* This function sets various options in the component
518  * The valid codes being passed in are PAPI_SET_DEFDOM,
519  * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT
520  */
521 static int
523 {
524  ( void ) ctx;
525  ( void ) code;
526  ( void ) option;
527 
528  return PAPI_OK;
529 }
530 
531 
532 static int
534  NativeInfo_t * native, int count,
535  hwd_context_t * ctx )
536 {
537  int i, index;
538  ( void ) ctx;
539  ( void ) ptr;
540 
541  for ( i = 0; i < count; i++ ) {
542  index = native[i].ni_event;
543  native[i].ni_position = _coretemp_native_events[index].resources.selector - 1;
544  }
545  return PAPI_OK;
546 }
547 
548 
549 /*
550  * This function has to set the bits needed to count different domains
551  * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
552  * By default return PAPI_EINVAL if none of those are specified
553  * and PAPI_OK with success
554  * PAPI_DOM_USER is only user context is counted
555  * PAPI_DOM_KERNEL is only the Kernel/OS context is counted
556  * PAPI_DOM_OTHER is Exception/transient mode (like user TLB misses)
557  * PAPI_DOM_ALL is all of the domains
558  */
559 static int
561 {
562  (void) cntl;
563  if ( PAPI_DOM_ALL != domain )
564  return PAPI_EINVAL;
565 
566  return PAPI_OK;
567 }
568 
569 
570 static int
572 {
573  ( void ) ctx;
574  ( void ) ctl;
575 
576  return PAPI_OK;
577 }
578 
579 
580 /*
581  * Native Event functions
582  */
583 static int
584 _coretemp_ntv_enum_events( unsigned int *EventCode, int modifier )
585 {
586 
587  int index;
588 
589  switch ( modifier ) {
590 
591  case PAPI_ENUM_FIRST:
592 
593  if (num_events==0) {
594  return PAPI_ENOEVNT;
595  }
596  *EventCode = 0;
597 
598  return PAPI_OK;
599 
600 
601  case PAPI_ENUM_EVENTS:
602 
603  index = *EventCode;
604 
605  if ( index < num_events - 1 ) {
606  *EventCode = *EventCode + 1;
607  return PAPI_OK;
608  } else {
609  return PAPI_ENOEVNT;
610  }
611  break;
612 
613  default:
614  return PAPI_EINVAL;
615  }
616  return PAPI_EINVAL;
617 }
618 
619 /*
620  *
621  */
622 static int
623 _coretemp_ntv_code_to_name( unsigned int EventCode, char *name, int len )
624 {
625  int index = EventCode;
626 
627  if ( index >= 0 && index < num_events ) {
628  strncpy( name, _coretemp_native_events[index].name, len );
629  return PAPI_OK;
630  }
631  return PAPI_ENOEVNT;
632 }
633 
634 /*
635  *
636  */
637 static int
638 _coretemp_ntv_code_to_descr( unsigned int EventCode, char *name, int len )
639 {
640  int index = EventCode;
641 
642  if ( index >= 0 && index < num_events ) {
643  strncpy( name, _coretemp_native_events[index].description, len );
644  return PAPI_OK;
645  }
646  return PAPI_ENOEVNT;
647 }
648 
649 static int
650 _coretemp_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info)
651 {
652 
653  int index = EventCode;
654 
655  if ( ( index < 0) || (index >= num_events )) return PAPI_ENOEVNT;
656 
657  strncpy( info->symbol, _coretemp_native_events[index].name, sizeof(info->symbol));
658  strncpy( info->long_descr, _coretemp_native_events[index].description, sizeof(info->long_descr));
659  strncpy( info->units, _coretemp_native_events[index].units, sizeof(info->units));
660  info->units[sizeof(info->units)-1] = '\0';
661 
662  return PAPI_OK;
663 }
664 
665 
666 
667 /*
668  *
669  */
671  .cmp_info = {
672  /* default component information (unspecified values are initialized to 0) */
673  .name = "coretemp",
674  .short_name = "coretemp",
675  .description = "Linux hwmon temperature and other info",
676  .version = "4.2.1",
677  .num_mpx_cntrs = CORETEMP_MAX_COUNTERS,
678  .num_cntrs = CORETEMP_MAX_COUNTERS,
679  .default_domain = PAPI_DOM_ALL,
680  .available_domains = PAPI_DOM_ALL,
681  .default_granularity = PAPI_GRN_SYS,
682  .available_granularities = PAPI_GRN_SYS,
683  .hardware_intr_sig = PAPI_INT_SIGNAL,
684 
685  /* component specific cmp_info initializations */
686  .fast_real_timer = 0,
687  .fast_virtual_timer = 0,
688  .attach = 0,
689  .attach_must_ptrace = 0,
690  }
691  ,
692 
693  /* sizes of framework-opaque component-private structures */
694  .size = {
695  .context = sizeof ( CORETEMP_context_t ),
696  .control_state = sizeof ( CORETEMP_control_state_t ),
697  .reg_value = sizeof ( CORETEMP_register_t ),
698  .reg_alloc = sizeof ( CORETEMP_reg_alloc_t ),
699  }
700  ,
701  /* function pointers in this component */
702  .init_thread = _coretemp_init_thread,
703  .init_component = _coretemp_init_component,
704  .init_control_state = _coretemp_init_control_state,
705  .start = _coretemp_start,
706  .stop = _coretemp_stop,
707  .read = _coretemp_read,
708  .shutdown_thread = _coretemp_shutdown_thread,
709  .shutdown_component = _coretemp_shutdown_component,
710  .ctl = _coretemp_ctl,
711 
712  .update_control_state = _coretemp_update_control_state,
713  .set_domain = _coretemp_set_domain,
714  .reset = _coretemp_reset,
715 
716  .ntv_enum_events = _coretemp_ntv_enum_events,
717  .ntv_code_to_name = _coretemp_ntv_code_to_name,
718  .ntv_code_to_descr = _coretemp_ntv_code_to_descr,
719  .ntv_code_to_info = _coretemp_ntv_code_to_info,
720 };
char description[PAPI_MAX_STR_LEN]
#define PAPI_OK
Definition: fpapi.h:105
static int _coretemp_update_control_state(hwd_control_state_t *ptr, NativeInfo_t *native, int count, hwd_context_t *ctx)
char disabled_reason[PAPI_MAX_STR_LEN]
Definition: papi.h:637
#define PAPI_ENOMEM
Definition: fpapi.h:107
static const char * name
Definition: fork_overflow.c:31
#define PAPI_EINVAL
Definition: fpapi.h:106
char units[PAPI_MIN_STR_LEN]
Definition: papi.h:976
#define papi_free(a)
Definition: papi_memory.h:35
static int _coretemp_set_domain(hwd_control_state_t *cntl, int domain)
int coretemp_ctl(hwd_context_t *ctx, int code, _papi_int_option_t *option)
static int _coretemp_shutdown_thread(hwd_context_t *ctx)
#define INVALID_RESULT
static int num_events
static int _coretemp_stop(hwd_context_t *ctx, hwd_control_state_t *ctl)
#define PAPI_GRN_SYS
Definition: fpapi.h:71
char long_descr[PAPI_HUGE_STR_LEN]
Definition: papi.h:970
static struct temp_event * root
char filename[MAXNAMESIZE]
Definition: iozone.c:1360
static CORETEMP_native_event_entry_t * _coretemp_native_events
char units[MAX_EVENTS][BUFSIZ]
Definition: powercap_plot.c:15
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
static FILE * fp
Return codes and api definitions.
static int _coretemp_ntv_code_to_name(unsigned int EventCode, char *name, int len)
FILE * fff[MAX_EVENTS]
unsigned int selector
struct temp_event * next
char events[MAX_EVENTS][BUFSIZ]
#define PAPI_ECMP
Definition: fpapi.h:109
char name[PAPI_MAX_STR_LEN]
static int _coretemp_init_thread(hwd_context_t *ctx)
coretemp component This file has the source code for a component that enables PAPI-C to access hardwa...
#define PAPI_ENOCMP
Definition: fpapi.h:122
static int cidx
static int _coretemp_shutdown_component()
char units[PAPI_MIN_STR_LEN]
long long counts[CORETEMP_MAX_COUNTERS]
static int _coretemp_ntv_enum_events(unsigned int *EventCode, int modifier)
char symbol[PAPI_HUGE_STR_LEN]
Definition: papi.h:967
#define PAPI_MIN_STR_LEN
Definition: fpapi.h:41
CORETEMP_register_t resources
char units[PAPI_MIN_STR_LEN]
char description[PAPI_MAX_STR_LEN]
#define CORETEMP_MAX_COUNTERS
int stone
static int native
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
#define NUM_PATHS
void PAPIERROR(char *format,...)
static int _coretemp_start(hwd_context_t *ctx, hwd_control_state_t *ctl)
static int _coretemp_ntv_code_to_descr(unsigned int EventCode, char *name, int len)
static int _coretemp_reset(hwd_context_t *ctx, hwd_control_state_t *ctl)
char name[PAPI_MAX_STR_LEN]
Definition: papi.h:630
static struct temp_event * last
#define PAPI_INT_SIGNAL
Definition: papi_internal.h:53
char location[PAPI_MAX_STR_LEN]
static int is_initialized
static int _coretemp_ctl(hwd_context_t *ctx, int code, _papi_int_option_t *option)
static int _coretemp_init_component(int cidx)
#define REFRESH_LAT
static int generateEventList(char *base_dir)
papi_vector_t _coretemp_vector
static int insert_in_list(char *name, char *units, char *description, char *filename)
char path[PATH_MAX]
long long PAPI_get_real_usec(void)
Definition: papi.c:6264
static long long getEventValue(int index)
#define PATH_MAX
Definition: fileop.c:68
#define PAPI_ENOEVNT
Definition: fpapi.h:112
static int _coretemp_init_control_state(hwd_control_state_t *ctl)
long value
char path[PATH_MAX]
static int _coretemp_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info)
volatile int buf[CACHE_FLUSH_BUFFER_SIZE_INTS]
Definition: do_loops.c:12
#define PAPI_DOM_ALL
Definition: fpapi.h:25
static int _coretemp_read(hwd_context_t *ctx, hwd_control_state_t *ctl, long long **events, int flags)
static long count
#define papi_calloc(a, b)
Definition: papi_memory.h:37
int i
Definition: fileop.c:140
#define PAPI_MAX_STR_LEN
Definition: fpapi.h:43
char name[PAPI_MAX_STR_LEN]