PAPI  5.4.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
linux-timer.c
Go to the documentation of this file.
1 /*
2  * File: linux-timer.c
3  *
4  */
5 
6 #include <time.h>
7 #include <sys/syscall.h>
8 
9 #include "papi.h"
10 #include "papi_internal.h"
11 #include "papi_vector.h"
12 
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <string.h>
16 
17 #include <sys/time.h>
18 
19 #include <fcntl.h>
20 #include "linux-common.h"
21 
22 #include <sys/time.h>
23 #include <sys/resource.h>
24 
25 #include <sys/times.h>
26 
27 #ifdef __ia64__
28 #include "perfmon/pfmlib_itanium2.h"
29 #include "perfmon/pfmlib_montecito.h"
30 #endif
31 
32 #if defined(HAVE_MMTIMER)
33 #include <sys/mman.h>
34 #include <linux/mmtimer.h>
35 #include <sys/ioctl.h>
36 #ifndef MMTIMER_FULLNAME
37 #define MMTIMER_FULLNAME "/dev/mmtimer"
38 #endif
39 
40 static int mmdev_fd;
41 static unsigned long mmdev_mask;
42 static unsigned long mmdev_ratio;
43 static volatile unsigned long *mmdev_timer_addr;
44 
45  /* setup mmtimer */
46 int mmtimer_setup(void) {
47 
48  unsigned long femtosecs_per_tick = 0;
49  unsigned long freq = 0;
50  int result;
51  int offset;
52 
53  SUBDBG( "MMTIMER Opening %s\n", MMTIMER_FULLNAME );
54  if ( ( mmdev_fd = open( MMTIMER_FULLNAME, O_RDONLY ) ) == -1 ) {
55  PAPIERROR( "Failed to open MM timer %s", MMTIMER_FULLNAME );
56  return PAPI_ESYS;
57  }
58  SUBDBG( "MMTIMER checking if we can mmap" );
59  if ( ioctl( mmdev_fd, MMTIMER_MMAPAVAIL, 0 ) != 1 ) {
60  PAPIERROR( "mmap of MM timer unavailable" );
61  return PAPI_ESYS;
62  }
63  SUBDBG( "MMTIMER setting close on EXEC flag\n" );
64  if ( fcntl( mmdev_fd, F_SETFD, FD_CLOEXEC ) == -1 ) {
65  PAPIERROR( "Failed to fcntl(FD_CLOEXEC) on MM timer FD %d: %s",
66  mmdev_fd, strerror( errno ) );
67  return PAPI_ESYS;
68  }
69  SUBDBG( "MMTIMER is on FD %d, getting offset\n", mmdev_fd );
70  if ( ( offset = ioctl( mmdev_fd, MMTIMER_GETOFFSET, 0 ) ) < 0 ) {
71  PAPIERROR( "Failed to get offset of MM timer" );
72  return PAPI_ESYS;
73  }
74  SUBDBG( "MMTIMER has offset of %d, getting frequency\n", offset );
75  if ( ioctl( mmdev_fd, MMTIMER_GETFREQ, &freq ) == -1 ) {
76  PAPIERROR( "Failed to get frequency of MM timer" );
77  return PAPI_ESYS;
78  }
79  SUBDBG( "MMTIMER has frequency %lu Mhz\n", freq / 1000000 );
80  // don't know for sure, but I think this ratio is inverted
81  // mmdev_ratio = (freq/1000000) / (unsigned long)_papi_hwi_system_info.hw_info.mhz;
82  mmdev_ratio =
84  ( freq / 1000000 );
85  SUBDBG( "MMTIMER has a ratio of %ld to the CPU's clock, getting resolution\n",
86  mmdev_ratio );
87  if ( ioctl( mmdev_fd, MMTIMER_GETRES, &femtosecs_per_tick ) == -1 ) {
88  PAPIERROR( "Failed to get femtoseconds per tick" );
89  return PAPI_ESYS;
90  }
91  SUBDBG( "MMTIMER res is %lu femtosecs/tick (10^-15s) or %f Mhz, getting valid bits\n",
92  femtosecs_per_tick, 1.0e9 / ( double ) femtosecs_per_tick );
93  if ( ( result = ioctl( mmdev_fd, MMTIMER_GETBITS, 0 ) ) == -ENOSYS ) {
94  PAPIERROR( "Failed to get number of bits in MMTIMER" );
95  return PAPI_ESYS;
96  }
97  mmdev_mask = ~( 0xffffffffffffffff << result );
98  SUBDBG( "MMTIMER has %d valid bits, mask %#16lx, getting mmaped page\n",
99  result, mmdev_mask );
100  if ( ( mmdev_timer_addr =
101  ( unsigned long * ) mmap( 0, getpagesize( ), PROT_READ,
102  MAP_PRIVATE, mmdev_fd,
103  0 ) ) == NULL ) {
104  PAPIERROR( "Failed to mmap MM timer" );
105  return PAPI_ESYS;
106  }
107  SUBDBG( "MMTIMER page is at %p, actual address is %p\n",
108  mmdev_timer_addr, mmdev_timer_addr + offset );
109  mmdev_timer_addr += offset;
110  /* mmdev_fd should be closed and page should be unmapped in a global shutdown routine */
111  return PAPI_OK;
112 
113 }
114 
115 #else
116 int mmtimer_setup(void) { return PAPI_OK; }
117 #endif
118 
119 
120 
121 
122 
123 /* Hardware clock functions */
124 
125 /* All architectures should set HAVE_CYCLES in configure if they have these.
126  Not all do so for now, we have to guard at the end of the statement,
127  instead of the top. When all archs set this, this region will be guarded
128  with:
129  #if defined(HAVE_CYCLE)
130  which is equivalent to
131  #if !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_CLOCK_GETTIME)
132 */
133 
134 /************************/
135 /* MMTIMER get_cycles() */
136 /************************/
137 
138 #if defined(HAVE_MMTIMER)
139 
140 static inline long long
141 get_cycles( void )
142 {
143  long long tmp = 0;
144 
145  tmp = *mmdev_timer_addr & mmdev_mask;
146  SUBDBG("MMTIMER is %llu, scaled %llu\n",tmp,tmp*mmdev_ratio);
147  tmp *= mmdev_ratio;
148 
149  return tmp;
150 }
151 
152 /************************/
153 /* ia64 get_cycles() */
154 /************************/
155 
156 #elif defined(__ia64__)
157 extern int _perfmon2_pfm_pmu_type;
158 
159 static inline long long
160 get_cycles( void )
161 {
162  long long tmp = 0;
163 #if defined(__INTEL_COMPILER)
164  tmp = __getReg( _IA64_REG_AR_ITC );
165 #else
166  __asm__ __volatile__( "mov %0=ar.itc":"=r"( tmp )::"memory" );
167 #endif
168  switch ( _perfmon2_pfm_pmu_type ) {
169  case PFMLIB_MONTECITO_PMU:
170  tmp = tmp * 4;
171  break;
172  }
173  return tmp;
174 }
175 
176 /************************/
177 /* x86 get_cycles() */
178 /************************/
179 
180 #elif (defined(__i386__)||defined(__x86_64__))
181 static inline long long
182 get_cycles( void )
183 {
184  long long ret = 0;
185 #ifdef __x86_64__
186  do {
187  unsigned int a, d;
188  asm volatile ( "rdtsc":"=a" ( a ), "=d"( d ) );
189  ( ret ) = ( ( long long ) a ) | ( ( ( long long ) d ) << 32 );
190  }
191  while ( 0 );
192 #else
193  __asm__ __volatile__( "rdtsc":"=A"( ret ): );
194 #endif
195  return ret;
196 }
197 
198 /************************/
199 /* SPARC get_cycles() */
200 /************************/
201 
202 /* #define get_cycles _rtc ?? */
203 #elif defined(__sparc__)
204 static inline long long
205 get_cycles( void )
206 {
207  register unsigned long ret asm( "g1" );
208 
209  __asm__ __volatile__( ".word 0x83410000" /* rd %tick, %g1 */
210  :"=r"( ret ) );
211  return ret;
212 }
213 
214 /************************/
215 /* aarch64 get_cycles() */
216 /************************/
217 
218 #elif defined(__aarch64__)
219 static inline long long
220 get_cycles( void )
221 {
222  register unsigned long ret;
223 
224  __asm__ __volatile__ ("isb; mrs %0, cntvct_el0" : "=r" (ret));
225 
226  return ret;
227 }
228 
229 /************************/
230 /* POWER get_cycles() */
231 /************************/
232 
233 #elif (defined(__powerpc__) || defined(__arm__) || defined(__mips__))
234 /*
235  * It's not possible to read the cycles from user space on ppc970.
236  * There is a 64-bit time-base register (TBU|TBL), but its
237  * update rate is implementation-specific and cannot easily be translated
238  * into a cycle count. So don't implement get_cycles for now,
239  * but instead, rely on the definition of HAVE_CLOCK_GETTIME_REALTIME in
240  * _papi_hwd_get_real_usec() for the needed functionality.
241 */
242 
243 static inline long long
244 get_cycles( void )
245 {
246  return 0;
247 }
248 
249 
250 #elif !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_CLOCK_GETTIME)
251 #error "No get_cycles support for this architecture. "
252 #endif
253 
254 
255 
256 
257 
258 
259 long long
261 {
262  long long retval;
263 #if defined(HAVE_GETTIMEOFDAY)||defined(__powerpc__)||defined(__arm__)||defined(__mips__)
264 
265  /* Crude estimate, not accurate in prescence of DVFS */
266 
267  retval = _papi_os_vector.get_real_usec( ) *
269 #else
270  retval = get_cycles( );
271 #endif
272  return retval;
273 }
274 
275 
276 
277 
278 /********************************************************************
279  * microsecond timers *
280  ********************************************************************/
281 
282 
283 /*******************************
284  * HAVE_CLOCK_GETTIME *
285  *******************************/
286 
287 long long
289 {
290 
291  long long retval;
292 
293  struct timespec foo;
294 #ifdef HAVE_CLOCK_GETTIME_REALTIME_HR
295  syscall( __NR_clock_gettime, CLOCK_REALTIME_HR, &foo );
296 #else
297  syscall( __NR_clock_gettime, CLOCK_REALTIME, &foo );
298 #endif
299  retval = ( long long ) foo.tv_sec * ( long long ) 1000000;
300  retval += ( long long ) ( foo.tv_nsec / 1000 );
301 
302  return retval;
303 }
304 
305 /**********************
306  * HAVE_GETTIMEOFDAY *
307  **********************/
308 
309 long long
311 {
312 
313  long long retval;
314 
315  struct timeval buffer;
316  gettimeofday( &buffer, NULL );
317  retval = ( long long ) buffer.tv_sec * ( long long ) 1000000;
318  retval += ( long long ) ( buffer.tv_usec );
319 
320  return retval;
321 }
322 
323 
324 long long
326 {
327 
328  long long retval;
329 
330  /* Not accurate in the prescence of DVFS */
331 
332  retval = get_cycles( ) /
334 
335  return retval;
336 }
337 
338 
339 
340 /*******************************
341  * HAVE_PER_THREAD_GETRUSAGE *
342  *******************************/
343 
344 long long
346 {
347 
348  long long retval;
349 
350  struct rusage buffer;
351 
352  getrusage( RUSAGE_SELF, &buffer );
353  SUBDBG( "user %d system %d\n", ( int ) buffer.ru_utime.tv_sec,
354  ( int ) buffer.ru_stime.tv_sec );
355  retval = ( long long ) ( buffer.ru_utime.tv_sec + buffer.ru_stime.tv_sec )
356  * ( long long ) 1000000;
357  retval += (long long) ( buffer.ru_utime.tv_usec + buffer.ru_stime.tv_usec );
358 
359  return retval;
360 }
361 
362 /**************************
363  * HAVE_PER_THREAD_TIMES *
364  **************************/
365 
366 long long
368 {
369 
370  long long retval;
371 
372  struct tms buffer;
373 
374  times( &buffer );
375 
376  SUBDBG( "user %d system %d\n", ( int ) buffer.tms_utime,
377  ( int ) buffer.tms_stime );
378  retval = ( long long ) ( ( buffer.tms_utime + buffer.tms_stime ) *
379  1000000 / sysconf( _SC_CLK_TCK ));
380 
381  /* NOT CLOCKS_PER_SEC as in the headers! */
382 
383  return retval;
384 }
385 
386 /******************************/
387 /* HAVE_CLOCK_GETTIME_THREAD */
388 /******************************/
389 
390 long long
392 {
393 
394  long long retval;
395 
396  struct timespec foo;
397 
398  syscall( __NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &foo );
399  retval = ( long long ) foo.tv_sec * ( long long ) 1000000;
400  retval += ( long long ) foo.tv_nsec / 1000;
401 
402  return retval;
403 }
404 
405 /********************/
406 /* USE_PROC_PTTIMER */
407 /********************/
408 
409 long long
411 {
412 
413  long long retval;
414  char buf[LINE_MAX];
415  long long utime, stime;
416  int rv, cnt = 0, i = 0;
417  int stat_fd;
418 
419 
420 again:
421  sprintf( buf, "/proc/%d/task/%d/stat", getpid( ), mygettid( ) );
422  stat_fd = open( buf, O_RDONLY );
423  if ( stat_fd == -1 ) {
424  PAPIERROR( "open(%s)", buf );
425  return PAPI_ESYS;
426  }
427 
428  rv = read( stat_fd, buf, LINE_MAX * sizeof ( char ) );
429  if ( rv == -1 ) {
430  if ( errno == EBADF ) {
431  close(stat_fd);
432  goto again;
433  }
434  PAPIERROR( "read()" );
435  close(stat_fd);
436  return PAPI_ESYS;
437  }
438  lseek( stat_fd, 0, SEEK_SET );
439 
440  if (rv == LINE_MAX) rv--;
441  buf[rv] = '\0';
442  SUBDBG( "Thread stat file is:%s\n", buf );
443  while ( ( cnt != 13 ) && ( i < rv ) ) {
444  if ( buf[i] == ' ' ) {
445  cnt++;
446  }
447  i++;
448  }
449 
450  if ( cnt != 13 ) {
451  PAPIERROR( "utime and stime not in thread stat file?" );
452  close(stat_fd);
453  return PAPI_ESYS;
454  }
455 
456  if ( sscanf( buf + i, "%llu %llu", &utime, &stime ) != 2 ) {
457  close(stat_fd);
458  PAPIERROR("Unable to scan two items from thread stat file at 13th space?");
459  return PAPI_ESYS;
460  }
461 
462  retval = ( utime + stime ) * ( long long ) 1000000 /_papi_os_info.clock_ticks;
463 
464  close(stat_fd);
465 
466  return retval;
467 }
468 
469 
470 /********************************************************************
471  * nanosecond timers *
472  ********************************************************************/
473 
474 
475 
476 /*******************************
477  * HAVE_CLOCK_GETTIME *
478  *******************************/
479 
480 long long
482 {
483 
484  long long retval;
485 
486  struct timespec foo;
487 #ifdef HAVE_CLOCK_GETTIME_REALTIME_HR
488  syscall( __NR_clock_gettime, CLOCK_REALTIME_HR, &foo );
489 #else
490  syscall( __NR_clock_gettime, CLOCK_REALTIME, &foo );
491 #endif
492  retval = ( long long ) foo.tv_sec * ( long long ) 1000000000;
493  retval += ( long long ) ( foo.tv_nsec );
494 
495  return retval;
496 }
497 
498 
499 /******************************/
500 /* HAVE_CLOCK_GETTIME_THREAD */
501 /******************************/
502 
503 long long
505 {
506 
507  long long retval;
508 
509  struct timespec foo;
510 
511  syscall( __NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &foo );
512  retval = ( long long ) foo.tv_sec * ( long long ) 1000000000;
513  retval += ( long long ) foo.tv_nsec ;
514 
515  return retval;
516 }
517 
518 
519 
520 
sprintf(splash[splash_line++],"\tIozone: Performance Test of File I/O\n")
ssize_t read(int fd, void *buf, size_t count)
Definition: appio.c:225
long long _linux_get_real_cycles(void)
Definition: linux-timer.c:260
int errno
int close(int fd)
Definition: appio.c:175
long long _linux_get_virt_usec_gettime(void)
Definition: linux-timer.c:391
long long(* get_real_usec)(void)
Definition: papi_vector.h:63
off64_t offset
Definition: iozone.c:1279
off_t lseek(int fd, off_t offset, int whence)
Definition: appio.c:210
static int _perfmon2_pfm_pmu_type
Definition: perfmon.c:50
return PAPI_OK
Definition: linux-nvml.c:458
static pid_t mygettid(void)
Definition: darwin-common.h:11
static double a[MATRIX_SIZE][MATRIX_SIZE]
Definition: rapl_basic.c:37
Return codes and api definitions.
long long _linux_get_real_nsec_gettime(void)
Definition: linux-timer.c:481
long long ret
Definition: iozone.c:1346
int open(const char *pathname, int flags, mode_t mode)
Definition: appio.c:184
papi_os_vector_t _papi_os_vector
Definition: aix.c:1288
int i
Definition: fileop.c:140
char buf[200]
Definition: iozone.c:19609
PAPI_os_info_t _papi_os_info
Definition: aix.c:1210
long long _linux_get_real_usec_cycles(void)
Definition: linux-timer.c:325
#define PAPI_ESYS
Definition: papi.h:253
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
long long
Definition: iozone.c:19827
void PAPIERROR(char *format,...)
int mmtimer_setup(void)
Definition: linux-timer.c:116
long long _linux_get_virt_usec_times(void)
Definition: linux-timer.c:367
papi_mdi_t _papi_hwi_system_info
Definition: papi_internal.c:57
PAPI_hw_info_t hw_info
#define get_cycles
Definition: linux-bgq.c:48
sscanf(mnc->m_child_port,"%d",&mc.m_child_port)
long long _linux_get_real_usec_gettime(void)
Definition: linux-timer.c:288
int cpu_max_mhz
Definition: papi.h:793
long long _linux_get_virt_usec_pttimer(void)
Definition: linux-timer.c:410
long long _linux_get_virt_nsec_gettime(void)
Definition: linux-timer.c:504
ssize_t retval
Definition: libasync.c:338
long long tmp
Definition: iozone.c:12031
long long _linux_get_virt_usec_rusage(void)
Definition: linux-timer.c:345
long long _linux_get_real_usec_gettimeofday(void)
Definition: linux-timer.c:310