Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / gmxlib / gmx_cyclecounter.c
1  /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * This file is part of Gromacs        Copyright (c) 1991-2006
5  * David van der Spoel, Erik Lindahl, Berk Hess, University of Groningen.
6  * Copyright (c) 2012, by the GROMACS development team, led by
7  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
8  * others, as listed in the AUTHORS file in the top-level source
9  * directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <time.h>
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45
46 #ifdef _MSC_VER
47 #include <windows.h>
48 #endif
49
50 #include "gmx_cyclecounter.h"
51
52
53
54
55
56 /*! \brief Calculate number of seconds per cycle tick on host
57 *
58 *  This routine runs a timer loop to calibrate the number of
59 *  seconds per the units returned fro gmx_cycles_read().
60 *
61 *  \param  sampletime Minimum real sample time. It takes some trial-and-error
62 *          to find the correct delay loop size, so the total runtime of
63 *          this routine is about twice this time.
64 *  \return Number of seconds per cycle unit. If it is not possible to
65 *          calculate on this system (for whatever reason) the return value
66 *          will be -1, so check that it is positive before using it.
67 */
68 double 
69 gmx_cycles_calibrate(double sampletime)
70 {
71 #ifdef _MSC_VER
72   
73   /* Windows does not have gettimeofday, but it provides a special
74    * routine that returns the cycle counter frequency.
75    */
76   LARGE_INTEGER i;
77   
78   QueryPerformanceFrequency(&i);
79   
80   return 1.0/((double) i.QuadPart);
81   /* end of MS Windows implementation */
82   
83 #elif (defined HAVE_GETTIMEOFDAY)
84   
85   /*  generic implementation with gettimeofday() */
86     struct timeval t1,t2;
87     gmx_cycles_t c1,c2;
88     double timediff,cyclediff;
89     double d=0.1; /* Dummy variable so we don't optimize away delay loop */
90     int i;
91
92     if(!gmx_cycles_have_counter())
93     {
94         return -1;
95     }
96     
97 #if (defined(__alpha__) || defined(__alpha)) 
98     /* Alpha cannot count to more than 4e9, but I don't expect
99         * that the architecture will go over 2GHz before it dies, so
100         * up to 2.0 seconds of sampling should be safe.
101         */
102     if(sampletime>2.0)
103     {
104         sampletime=2.0;
105     }
106 #endif
107     
108     /* Start a timing loop. We want this to be largely independent
109      * of machine speed, so we need to start with a very small number 
110      * of iterations and repeat it until we reach the requested time.
111      *
112      * We call gettimeofday an extra time at the start to avoid cache misses.
113      */
114     gettimeofday(&t1,NULL);
115     gettimeofday(&t1,NULL);
116     c1=gmx_cycles_read();
117     
118     do 
119     {
120         /* just a delay loop. To avoid optimizing it away, we calculate a number
121         * that will underflow to zero in most cases. By conditionally adding it
122         * to a result at the end it cannot be removed. n=10000 is arbitrary...
123         */
124         for(i=0;i<10000;i++)
125             d=d/(1.0+(double)i);
126         /* Read the time again */
127         gettimeofday(&t2,NULL);
128         c2=gmx_cycles_read();
129         timediff=(double)(t2.tv_sec-t1.tv_sec)+
130             (double)(t2.tv_usec-t1.tv_usec)*1e-6;
131     } 
132     while( timediff < sampletime );
133     
134     cyclediff=c2-c1;
135     
136     /* Add a very small result so the delay loop cannot be optimized away */
137     if(d<1e-30)
138     {
139         timediff+=d;
140     }
141     
142     /* Return seconds per cycle */
143     return timediff/cyclediff;
144     
145 #else
146     /* No timing function available */
147     return -1;
148 #endif
149 }  
150
151