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