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