PAPI  5.3.2.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 /* POWER get_cycles() */
216 /************************/
217 
218 #elif (defined(__powerpc__) || defined(__arm__) || defined(__mips__) || defined(__aarch64__))
219 /*
220  * It's not possible to read the cycles from user space on ppc970.
221  * There is a 64-bit time-base register (TBU|TBL), but its
222  * update rate is implementation-specific and cannot easily be translated
223  * into a cycle count. So don't implement get_cycles for now,
224  * but instead, rely on the definition of HAVE_CLOCK_GETTIME_REALTIME in
225  * _papi_hwd_get_real_usec() for the needed functionality.
226 */
227 
228 static inline long long
229 get_cycles( void )
230 {
231  return 0;
232 }
233 
234 
235 #elif !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_CLOCK_GETTIME)
236 #error "No get_cycles support for this architecture. "
237 #endif
238 
239 
240 
241 
242 
243 
244 long long
246 {
247  long long retval;
248 #if defined(HAVE_GETTIMEOFDAY)||defined(__powerpc__)||defined(__arm__)||defined(__mips__)
249 
250  /* Crude estimate, not accurate in prescence of DVFS */
251 
252  retval = _papi_os_vector.get_real_usec( ) *
254 #else
255  retval = get_cycles( );
256 #endif
257  return retval;
258 }
259 
260 
261 
262 
263 /********************************************************************
264  * microsecond timers *
265  ********************************************************************/
266 
267 
268 /*******************************
269  * HAVE_CLOCK_GETTIME *
270  *******************************/
271 
272 long long
274 {
275 
276  long long retval;
277 
278  struct timespec foo;
279 #ifdef HAVE_CLOCK_GETTIME_REALTIME_HR
280  syscall( __NR_clock_gettime, CLOCK_REALTIME_HR, &foo );
281 #else
282  syscall( __NR_clock_gettime, CLOCK_REALTIME, &foo );
283 #endif
284  retval = ( long long ) foo.tv_sec * ( long long ) 1000000;
285  retval += ( long long ) ( foo.tv_nsec / 1000 );
286 
287  return retval;
288 }
289 
290 /**********************
291  * HAVE_GETTIMEOFDAY *
292  **********************/
293 
294 long long
296 {
297 
298  long long retval;
299 
300  struct timeval buffer;
301  gettimeofday( &buffer, NULL );
302  retval = ( long long ) buffer.tv_sec * ( long long ) 1000000;
303  retval += ( long long ) ( buffer.tv_usec );
304 
305  return retval;
306 }
307 
308 
309 long long
311 {
312 
313  long long retval;
314 
315  /* Not accurate in the prescence of DVFS */
316 
317  retval = get_cycles( ) /
319 
320  return retval;
321 }
322 
323 
324 
325 /*******************************
326  * HAVE_PER_THREAD_GETRUSAGE *
327  *******************************/
328 
329 long long
331 {
332 
333  long long retval;
334 
335  struct rusage buffer;
336 
337  getrusage( RUSAGE_SELF, &buffer );
338  SUBDBG( "user %d system %d\n", ( int ) buffer.ru_utime.tv_sec,
339  ( int ) buffer.ru_stime.tv_sec );
340  retval = ( long long ) ( buffer.ru_utime.tv_sec + buffer.ru_stime.tv_sec )
341  * ( long long ) 1000000;
342  retval += (long long) ( buffer.ru_utime.tv_usec + buffer.ru_stime.tv_usec );
343 
344  return retval;
345 }
346 
347 /**************************
348  * HAVE_PER_THREAD_TIMES *
349  **************************/
350 
351 long long
353 {
354 
355  long long retval;
356 
357  struct tms buffer;
358 
359  times( &buffer );
360 
361  SUBDBG( "user %d system %d\n", ( int ) buffer.tms_utime,
362  ( int ) buffer.tms_stime );
363  retval = ( long long ) ( ( buffer.tms_utime + buffer.tms_stime ) *
364  1000000 / sysconf( _SC_CLK_TCK ));
365 
366  /* NOT CLOCKS_PER_SEC as in the headers! */
367 
368  return retval;
369 }
370 
371 /******************************/
372 /* HAVE_CLOCK_GETTIME_THREAD */
373 /******************************/
374 
375 long long
377 {
378 
379  long long retval;
380 
381  struct timespec foo;
382 
383  syscall( __NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &foo );
384  retval = ( long long ) foo.tv_sec * ( long long ) 1000000;
385  retval += ( long long ) foo.tv_nsec / 1000;
386 
387  return retval;
388 }
389 
390 /********************/
391 /* USE_PROC_PTTIMER */
392 /********************/
393 
394 long long
396 {
397 
398  long long retval;
399  char buf[LINE_MAX];
400  long long utime, stime;
401  int rv, cnt = 0, i = 0;
402  int stat_fd;
403 
404 
405 again:
406  sprintf( buf, "/proc/%d/task/%d/stat", getpid( ), mygettid( ) );
407  stat_fd = open( buf, O_RDONLY );
408  if ( stat_fd == -1 ) {
409  PAPIERROR( "open(%s)", buf );
410  return PAPI_ESYS;
411  }
412 
413  rv = read( stat_fd, buf, LINE_MAX * sizeof ( char ) );
414  if ( rv == -1 ) {
415  if ( errno == EBADF ) {
416  close(stat_fd);
417  goto again;
418  }
419  PAPIERROR( "read()" );
420  close(stat_fd);
421  return PAPI_ESYS;
422  }
423  lseek( stat_fd, 0, SEEK_SET );
424 
425  if (rv == LINE_MAX) rv--;
426  buf[rv] = '\0';
427  SUBDBG( "Thread stat file is:%s\n", buf );
428  while ( ( cnt != 13 ) && ( i < rv ) ) {
429  if ( buf[i] == ' ' ) {
430  cnt++;
431  }
432  i++;
433  }
434 
435  if ( cnt != 13 ) {
436  PAPIERROR( "utime and stime not in thread stat file?" );
437  close(stat_fd);
438  return PAPI_ESYS;
439  }
440 
441  if ( sscanf( buf + i, "%llu %llu", &utime, &stime ) != 2 ) {
442  close(stat_fd);
443  PAPIERROR("Unable to scan two items from thread stat file at 13th space?");
444  return PAPI_ESYS;
445  }
446 
447  retval = ( utime + stime ) * ( long long ) 1000000 /_papi_os_info.clock_ticks;
448 
449  close(stat_fd);
450 
451  return retval;
452 }
453 
454 
455 /********************************************************************
456  * nanosecond timers *
457  ********************************************************************/
458 
459 
460 
461 /*******************************
462  * HAVE_CLOCK_GETTIME *
463  *******************************/
464 
465 long long
467 {
468 
469  long long retval;
470 
471  struct timespec foo;
472 #ifdef HAVE_CLOCK_GETTIME_REALTIME_HR
473  syscall( __NR_clock_gettime, CLOCK_REALTIME_HR, &foo );
474 #else
475  syscall( __NR_clock_gettime, CLOCK_REALTIME, &foo );
476 #endif
477  retval = ( long long ) foo.tv_sec * ( long long ) 1000000000;
478  retval += ( long long ) ( foo.tv_nsec );
479 
480  return retval;
481 }
482 
483 
484 /******************************/
485 /* HAVE_CLOCK_GETTIME_THREAD */
486 /******************************/
487 
488 long long
490 {
491 
492  long long retval;
493 
494  struct timespec foo;
495 
496  syscall( __NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &foo );
497  retval = ( long long ) foo.tv_sec * ( long long ) 1000000000;
498  retval += ( long long ) foo.tv_nsec ;
499 
500  return retval;
501 }
502 
503 
504 
505 
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:245
int errno
int close(int fd)
Definition: appio.c:175
long long _linux_get_virt_usec_gettime(void)
Definition: linux-timer.c:376
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:466
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:310
#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:352
#define PAPI_ESYS
Definition: fpapi.h:108
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:273
int cpu_max_mhz
Definition: papi.h:791
long long _linux_get_virt_usec_pttimer(void)
Definition: linux-timer.c:395
long long _linux_get_virt_nsec_gettime(void)
Definition: linux-timer.c:489
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:330
long long _linux_get_real_usec_gettimeofday(void)
Definition: linux-timer.c:295