Moved additional gmxlib sources to C++
[alexxy/gromacs.git] / src / gromacs / timing / cyclecounter.cpp
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,2015, 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 "gmxpre.h"
37
38 #include "cyclecounter.h"
39
40 #include "config.h"
41
42 #include <ctime>
43
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47 #ifdef _MSC_VER
48 #include <windows.h>
49 #endif
50
51 /*! \brief Calculate number of seconds per cycle tick on host
52  *
53  *  This routine runs a timer loop to calibrate the number of
54  *  seconds per the units returned fro gmx_cycles_read().
55  *
56  *  \param  sampletime Minimum real sample time. It takes some trial-and-error
57  *          to find the correct delay loop size, so the total runtime of
58  *          this routine is about twice this time.
59  *  \return Number of seconds per cycle unit. If it is not possible to
60  *          calculate on this system (for whatever reason) the return value
61  *          will be -1, so check that it is positive before using it.
62  */
63 double
64 gmx_cycles_calibrate(double sampletime)
65 {
66 #ifdef _MSC_VER
67
68     /* Windows does not have gettimeofday, but it provides a special
69      * routine that returns the cycle counter frequency.
70      */
71     LARGE_INTEGER i;
72
73     QueryPerformanceFrequency(&i);
74
75     return 1.0/static_cast<double>(i.QuadPart);
76     /* end of MS Windows implementation */
77
78 #elif (defined HAVE_GETTIMEOFDAY)
79
80     /*  generic implementation with gettimeofday() */
81     struct timeval t1, t2;
82     gmx_cycles_t   c1, c2;
83     double         timediff, cyclediff;
84     double         d = 0.1; /* Dummy variable so we don't optimize away delay loop */
85
86     if (!gmx_cycles_have_counter())
87     {
88         return -1;
89     }
90
91 #if (defined(__alpha__) || defined(__alpha))
92     /* Alpha cannot count to more than 4e9, but I don't expect
93      * that the architecture will go over 2GHz before it dies, so
94      * up to 2.0 seconds of sampling should be safe.
95      */
96     if (sampletime > 2.0)
97     {
98         sampletime = 2.0;
99     }
100 #endif
101
102     /* Start a timing loop. We want this to be largely independent
103      * of machine speed, so we need to start with a very small number
104      * of iterations and repeat it until we reach the requested time.
105      *
106      * We call gettimeofday an extra time at the start to avoid cache misses.
107      */
108     gettimeofday(&t1, NULL);
109     gettimeofday(&t1, NULL);
110     c1 = gmx_cycles_read();
111
112     do
113     {
114         /* just a delay loop. To avoid optimizing it away, we calculate a number
115          * that will underflow to zero in most cases. By conditionally adding it
116          * to a result at the end it cannot be removed. n=10000 is arbitrary...
117          */
118         for (int i = 0; i < 10000; i++)
119         {
120             d = d/(1.0+static_cast<double>(i));
121         }
122         /* Read the time again */
123         gettimeofday(&t2, NULL);
124         c2       = gmx_cycles_read();
125         timediff = static_cast<double>(t2.tv_sec-t1.tv_sec)+(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 }