Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / timing / cyclecounter.c
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
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  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * To help us fund GROMACS development, we humbly ask that you cite
13  * the research papers on the package. Check out http://www.gromacs.org
14  *
15  * And Hey:
16  * Gnomes, ROck Monsters And Chili Sauce
17  */
18 #include "gromacs/timing/cyclecounter.h"
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <time.h>
25 #ifdef HAVE_SYS_TIME_H
26 #include <sys/time.h>
27 #endif
28
29 #ifdef _MSC_VER
30 #include <windows.h>
31 #endif
32
33 /*! \brief Calculate number of seconds per cycle tick on host
34  *
35  *  This routine runs a timer loop to calibrate the number of
36  *  seconds per the units returned fro gmx_cycles_read().
37  *
38  *  \param  sampletime Minimum real sample time. It takes some trial-and-error
39  *          to find the correct delay loop size, so the total runtime of
40  *          this routine is about twice this time.
41  *  \return Number of seconds per cycle unit. If it is not possible to
42  *          calculate on this system (for whatever reason) the return value
43  *          will be -1, so check that it is positive before using it.
44  */
45 double
46 gmx_cycles_calibrate(double sampletime)
47 {
48 #ifdef _MSC_VER
49
50     /* Windows does not have gettimeofday, but it provides a special
51      * routine that returns the cycle counter frequency.
52      */
53     LARGE_INTEGER i;
54
55     QueryPerformanceFrequency(&i);
56
57     return 1.0/((double) i.QuadPart);
58     /* end of MS Windows implementation */
59
60 #elif (defined HAVE_GETTIMEOFDAY)
61
62     /*  generic implementation with gettimeofday() */
63     struct timeval t1, t2;
64     gmx_cycles_t   c1, c2;
65     double         timediff, cyclediff;
66     double         d = 0.1; /* Dummy variable so we don't optimize away delay loop */
67     int            i;
68
69     if (!gmx_cycles_have_counter())
70     {
71         return -1;
72     }
73
74 #if (defined(__alpha__) || defined(__alpha))
75     /* Alpha cannot count to more than 4e9, but I don't expect
76      * that the architecture will go over 2GHz before it dies, so
77      * up to 2.0 seconds of sampling should be safe.
78      */
79     if (sampletime > 2.0)
80     {
81         sampletime = 2.0;
82     }
83 #endif
84
85     /* Start a timing loop. We want this to be largely independent
86      * of machine speed, so we need to start with a very small number
87      * of iterations and repeat it until we reach the requested time.
88      *
89      * We call gettimeofday an extra time at the start to avoid cache misses.
90      */
91     gettimeofday(&t1, NULL);
92     gettimeofday(&t1, NULL);
93     c1 = gmx_cycles_read();
94
95     do
96     {
97         /* just a delay loop. To avoid optimizing it away, we calculate a number
98          * that will underflow to zero in most cases. By conditionally adding it
99          * to a result at the end it cannot be removed. n=10000 is arbitrary...
100          */
101         for (i = 0; i < 10000; i++)
102         {
103             d = d/(1.0+(double)i);
104         }
105         /* Read the time again */
106         gettimeofday(&t2, NULL);
107         c2       = gmx_cycles_read();
108         timediff = (double)(t2.tv_sec-t1.tv_sec)+
109             (double)(t2.tv_usec-t1.tv_usec)*1e-6;
110     }
111     while (timediff < sampletime);
112
113     cyclediff = c2-c1;
114
115     /* Add a very small result so the delay loop cannot be optimized away */
116     if (d < 1e-30)
117     {
118         timediff += d;
119     }
120
121     /* Return seconds per cycle */
122     return timediff/cyclediff;
123
124 #else
125     /* No timing function available */
126     return -1;
127 #endif
128 }