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