PAPI 7.1.0.0
Loading...
Searching...
No Matches
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__
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
49static int mmdev_fd;
50static unsigned long mmdev_mask;
51static unsigned long mmdev_ratio;
52static volatile unsigned long *mmdev_timer_addr;
53
54 /* setup mmtimer */
55int 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__)
127static uint64_t multiplier = 1;
128#endif
129
130int mmtimer_setup(void) {
131
132#if defined(__powerpc__)
133multiplier = ((uint64_t)_papi_hwi_system_info.hw_info.cpu_max_mhz * 1000000ULL) / (__ppc_get_timebase_freq()/(uint64_t)1000);
134#endif
135return 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
159static inline long long
160get_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__)
176extern int _perfmon2_pfm_pmu_type;
177
178static inline long long
179get_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 ) {
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__))
200static inline long long
201get_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__)
223static inline long long
224get_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__)
238static inline long long
239get_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
254static 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__) || defined(__hppa__))
285static inline long long
286get_cycles( void )
287{
288 return 0;
289}
290
291/************************/
292/* NEC get_cycles() */
293/************************/
294
295#elif defined(__NEC__)
296static inline long long
297get_cycles( void )
298{
299 long long ret = 0;
300 return ret;
301}
302
303
304
305#elif !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_CLOCK_GETTIME)
306#error "No get_cycles support for this architecture. "
307#endif
308
309
310
311long long
313{
314 long long retval;
315#if defined(HAVE_GETTIMEOFDAY)||defined(__arm__)||defined(__mips__)
316
317 /* Crude estimate, not accurate in prescence of DVFS */
318
321#else
322 retval = get_cycles( );
323#endif
324 return retval;
325}
326
327
328
329
330/********************************************************************
331 * microsecond timers *
332 ********************************************************************/
333
334
335/*******************************
336 * HAVE_CLOCK_GETTIME *
337 *******************************/
338
339long long
341{
342
343 long long retval;
344
345 struct timespec foo;
346#ifdef HAVE_CLOCK_GETTIME_REALTIME_HR
347 syscall( __NR_clock_gettime, CLOCK_REALTIME_HR, &foo );
348#else
349 syscall( __NR_clock_gettime, CLOCK_REALTIME, &foo );
350#endif
351 retval = ( long long ) foo.tv_sec * ( long long ) 1000000;
352 retval += ( long long ) ( foo.tv_nsec / 1000 );
353
354 return retval;
355}
356
357/**********************
358 * HAVE_GETTIMEOFDAY *
359 **********************/
360
361long long
363{
364
365 long long retval;
366
367 struct timeval buffer;
368 gettimeofday( &buffer, NULL );
369 retval = ( long long ) buffer.tv_sec * ( long long ) 1000000;
370 retval += ( long long ) ( buffer.tv_usec );
371
372 return retval;
373}
374
375
376long long
378{
379
380 long long retval;
381
382 /* Not accurate in the prescence of DVFS */
383
384 retval = get_cycles( ) /
386
387 return retval;
388}
389
390
391
392/*******************************
393 * HAVE_PER_THREAD_GETRUSAGE *
394 *******************************/
395
396long long
398{
399
400 long long retval;
401
402 struct rusage buffer;
403
404 getrusage( RUSAGE_SELF, &buffer );
405 SUBDBG( "user %d system %d\n", ( int ) buffer.ru_utime.tv_sec,
406 ( int ) buffer.ru_stime.tv_sec );
407 retval = ( long long ) ( buffer.ru_utime.tv_sec + buffer.ru_stime.tv_sec )
408 * ( long long ) 1000000;
409 retval += (long long) ( buffer.ru_utime.tv_usec + buffer.ru_stime.tv_usec );
410
411 return retval;
412}
413
414/**************************
415 * HAVE_PER_THREAD_TIMES *
416 **************************/
417
418long long
420{
421
422 long long retval;
423
424 struct tms buffer;
425
426 times( &buffer );
427
428 SUBDBG( "user %d system %d\n", ( int ) buffer.tms_utime,
429 ( int ) buffer.tms_stime );
430 retval = ( long long ) ( ( buffer.tms_utime + buffer.tms_stime ) *
431 1000000 / sysconf( _SC_CLK_TCK ));
432
433 /* NOT CLOCKS_PER_SEC as in the headers! */
434
435 return retval;
436}
437
438/******************************/
439/* HAVE_CLOCK_GETTIME_THREAD */
440/******************************/
441
442long long
444{
445
446 long long retval;
447
448 struct timespec foo;
449
450 syscall( __NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &foo );
451 retval = ( long long ) foo.tv_sec * ( long long ) 1000000;
452 retval += ( long long ) foo.tv_nsec / 1000;
453
454 return retval;
455}
456
457/********************/
458/* USE_PROC_PTTIMER */
459/********************/
460
461long long
463{
464
465 long long retval;
466 char buf[LINE_MAX];
467 long long utime, stime;
468 int rv, cnt = 0, i = 0;
469 int stat_fd;
470
471
472again:
473 sprintf( buf, "/proc/%d/task/%d/stat", getpid( ), mygettid( ) );
474 stat_fd = open( buf, O_RDONLY );
475 if ( stat_fd == -1 ) {
476 PAPIERROR( "open(%s)", buf );
477 return PAPI_ESYS;
478 }
479
480 rv = read( stat_fd, buf, LINE_MAX * sizeof ( char ) );
481 if ( rv == -1 ) {
482 if ( errno == EBADF ) {
483 close(stat_fd);
484 goto again;
485 }
486 PAPIERROR( "read()" );
487 close(stat_fd);
488 return PAPI_ESYS;
489 }
490 lseek( stat_fd, 0, SEEK_SET );
491
492 if (rv == LINE_MAX) rv--;
493 buf[rv] = '\0';
494 SUBDBG( "Thread stat file is:%s\n", buf );
495 while ( ( cnt != 13 ) && ( i < rv ) ) {
496 if ( buf[i] == ' ' ) {
497 cnt++;
498 }
499 i++;
500 }
501
502 if ( cnt != 13 ) {
503 PAPIERROR( "utime and stime not in thread stat file?" );
504 close(stat_fd);
505 return PAPI_ESYS;
506 }
507
508 if ( sscanf( buf + i, "%llu %llu", &utime, &stime ) != 2 ) {
509 close(stat_fd);
510 PAPIERROR("Unable to scan two items from thread stat file at 13th space?");
511 return PAPI_ESYS;
512 }
513
514 retval = ( utime + stime ) * ( long long ) 1000000 /_papi_os_info.clock_ticks;
515
516 close(stat_fd);
517
518 return retval;
519}
520
521
522/********************************************************************
523 * nanosecond timers *
524 ********************************************************************/
525
526
527
528/*******************************
529 * HAVE_CLOCK_GETTIME *
530 *******************************/
531
532long long
534{
535
536 long long retval;
537
538 struct timespec foo;
539#ifdef HAVE_CLOCK_GETTIME_REALTIME_HR
540 syscall( __NR_clock_gettime, CLOCK_REALTIME_HR, &foo );
541#else
542 syscall( __NR_clock_gettime, CLOCK_REALTIME, &foo );
543#endif
544 retval = ( long long ) foo.tv_sec * ( long long ) 1000000000;
545 retval += ( long long ) ( foo.tv_nsec );
546
547 return retval;
548}
549
550
551/******************************/
552/* HAVE_CLOCK_GETTIME_THREAD */
553/******************************/
554
555long long
557{
558
559 long long retval;
560
561 struct timespec foo;
562
563 syscall( __NR_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &foo );
564 retval = ( long long ) foo.tv_sec * ( long long ) 1000000000;
565 retval += ( long long ) foo.tv_nsec ;
566
567 return retval;
568}
volatile int result
double tmp
int i
PAPI_os_info_t _papi_os_info
Definition: aix.c:1210
papi_os_vector_t _papi_os_vector
Definition: aix.c:1288
int open(const char *pathname, int flags, mode_t mode)
Definition: appio.c:188
off_t lseek(int fd, off_t offset, int whence)
Definition: appio.c:214
int close(int fd)
Definition: appio.c:179
int errno
ssize_t read(int fd, void *buf, size_t count)
Definition: appio.c:229
static pid_t mygettid(void)
Definition: darwin-common.h:11
volatile int buf[CACHE_FLUSH_BUFFER_SIZE_INTS]
Definition: do_loops.c:12
void dummy(void *array)
Definition: do_loops.c:306
#define PAPI_OK
Definition: f90papi.h:73
#define PAPI_ESYS
Definition: f90papi.h:136
static double a[MATRIX_SIZE][MATRIX_SIZE]
Definition: libmsr_basic.c:38
#define get_cycles
Definition: linux-bgq.c:48
uint32_t freq
long long _linux_get_real_usec_gettime(void)
Definition: linux-timer.c:340
long long _linux_get_virt_usec_times(void)
Definition: linux-timer.c:419
long long _linux_get_real_usec_cycles(void)
Definition: linux-timer.c:377
int mmtimer_setup(void)
Definition: linux-timer.c:130
long long _linux_get_real_cycles(void)
Definition: linux-timer.c:312
long long _linux_get_virt_usec_rusage(void)
Definition: linux-timer.c:397
long long _linux_get_virt_usec_gettime(void)
Definition: linux-timer.c:443
long long _linux_get_real_nsec_gettime(void)
Definition: linux-timer.c:533
long long _linux_get_real_usec_gettimeofday(void)
Definition: linux-timer.c:362
long long _linux_get_virt_nsec_gettime(void)
Definition: linux-timer.c:556
long long _linux_get_virt_usec_pttimer(void)
Definition: linux-timer.c:462
Return codes and api definitions.
#define SUBDBG(format, args...)
Definition: papi_debug.h:64
void PAPIERROR(char *format,...)
papi_mdi_t _papi_hwi_system_info
Definition: papi_internal.c:56
static int _perfmon2_pfm_pmu_type
#define PFMLIB_MONTECITO_PMU
Definition: pfmlib.h:226
long long int long long
Definition: sde_internal.h:85
int cpu_max_mhz
Definition: papi.h:790
PAPI_hw_info_t hw_info
long long(* get_real_usec)(void)
Definition: papi_vector.h:63
__syscall_slong_t tv_nsec
__time_t tv_sec
__time_t tv_sec
__suseconds_t tv_usec
int retval
Definition: zero_fork.c:53