Update copyright to LGPL on all files
[dyninst.git] / common / src / mmtimer.c
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31  
32 #include <sn/mmtimer.h> /* MMTIMER_* */
33
34 /* getpid() */
35 #include <sys/types.h>
36 #include <unistd.h>              
37
38 #include <stdio.h> /* fprintf() */
39 #include <sys/ioctl.h> /* for ioctl() */
40 #include <sys/mman.h> /* for mmap() */
41
42 /* The mmtimer, once initialized by a call to isMMTimerAvail(),
43    is always (mmdev_clicks_per_tick * (*mmdev_timer_addr)). */
44 static unsigned long mmdev_clicks_per_tick = 0;
45 static volatile unsigned long * mmdev_timer_addr = NULL;
46
47 /* The defined interface in common/h/timing.h is too clumsy, so duplicate code. */
48 double getLocalCyclesPerSecond() {
49         FILE * cpuinfo = fopen( "/proc/cpuinfo", "r" );
50         if( cpuinfo == NULL ) { return 0; }
51         
52         double MHz = 0.0;
53         /* Scan /proc/cpuinfo until we find something; assume all CPUs the same. */
54         while( ! feof( cpuinfo ) ) {
55                 char buffer[ 256 ];
56                 char * result = fgets( buffer, 255, cpuinfo );
57                 if( result != NULL ) {
58                         int status = sscanf( result, "cpu MHz : %lf", & MHz );
59                         if( status == 1 ) { 
60                                 fclose( cpuinfo );
61                                 return ( MHz * 1000000.0 );
62                                 }
63                         }
64                 } /* end scanning loop */
65                 
66         fclose( cpuinfo );
67         return 0;
68         } /* end getLocalCyclesPerSecond() */
69
70 int isMMTimerAvail() {
71         int fd = 0;
72         unsigned long femtosecondsPerTick = 0;
73         int mmTimerOffset = 0;
74         
75         /* Don't do anything twice. */
76         if( mmdev_clicks_per_tick != 0 || mmdev_timer_addr != 0 ) { return 1; }
77         
78         /* Attempt to setup the mmtimer. */
79         if( ( fd = open( MMTIMER_FULLNAME, O_RDONLY ) ) == -1 ) {
80                 return 0;
81                 }
82         if( ( mmTimerOffset = ioctl( fd, MMTIMER_GETOFFSET, 0 ) ) == -ENOSYS ) {
83                 close( fd );
84                 return 0;
85                 }
86          if( ( mmdev_timer_addr = (volatile unsigned long int *)mmap( 0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0 ) ) == NULL ) {
87                 close( fd );
88                 return 0;
89                 }
90
91         mmdev_timer_addr += mmTimerOffset;
92         ioctl( fd, MMTIMER_GETRES, & femtosecondsPerTick );
93         mmdev_clicks_per_tick = (unsigned long)((getLocalCyclesPerSecond() * 1.0e-15) * femtosecondsPerTick);
94          
95         assert( mmdev_clicks_per_tick != 0 );
96         
97         ///* DEBUG */ fprintf( stderr,  "%d: %lf MHz, "
98         //                                                              "microseconds/tick = %lf, "
99         //                                                              "clicks_per_tick = %lu\n",
100         //                                                              getpid(),
101         //                                                              getLocalCyclesPerSecond() / 1.0e6,
102         //                                                              femtosecondsPerTick / 1.0e9,
103         //                                                              mmdev_clicks_per_tick );
104
105     close( fd );
106     return 1;
107         } /* end isMMtimerAvail() */