Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / timing / cyclecounter.h
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 /*! \internal \file
19  * \brief
20  * High-resolution timestamp or CPU clock cycle counters.
21  *
22  * After reading the current value with gmx_cycles_read() you can add or
23  * subtract these numbers as normal integers of type gmx_cycles_t.
24  */
25 #ifndef GMX_TIMING_CYCLECOUNTER_H
26 #define GMX_TIMING_CYCLECOUNTER_H
27
28 /*
29  * define HAVE_RDTSCP to use the serializing rdtscp instruction instead of rdtsc.
30  * This is only supported on newer Intel/AMD hardware, but provides better accuracy.
31  */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #ifdef _MSC_VER
37 #include <intrin.h>
38 #endif
39
40 #ifdef __cplusplus
41 extern "C"
42 {
43 #endif
44 #if 0
45 } /* fixes auto-indentation problems */
46 #endif
47
48 /* Minor implementation note:
49  *
50  * I like to use these counters in other programs too, so to avoid making
51  * it dependent on other Gromacs definitions I use the #ifdef's to set
52  * architecture-specific inline macros instead of using gmx_inline from
53  * gmx_types.h /Erik 2005-12-10
54  */
55
56 #if ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__)) && \
57     (defined(__i386__) || defined(__x86_64__)))
58 /* x86 or x86-64 with GCC inline assembly */
59 typedef unsigned long long
60     gmx_cycles_t;
61
62 #elif defined(_MSC_VER)
63 #include <windows.h>
64 typedef __int64
65     gmx_cycles_t;
66
67 #elif (defined(__hpux) || defined(__HP_cc)) && defined(__ia64)
68 /* HP compiler on ia64 */
69 #include <machine/sys/inline.h>
70 typedef unsigned long
71     gmx_cycles_t;
72
73 #elif (defined(__INTEL_COMPILER) || defined(__ECC)) && defined(__ia64__)
74 /* Intel compiler on ia64 */
75 #include <ia64intrin.h>
76 typedef unsigned long
77     gmx_cycles_t;
78
79 #elif defined(__GNUC__) && defined(__ia64__)
80 /* ia64 with GCC inline assembly */
81 typedef unsigned long
82     gmx_cycles_t;
83
84 #elif ((defined(__hppa__) || defined(__hppa)) && defined (__GNUC__))
85 /* HP PA-RISC, inline asm with gcc */
86 typedef unsigned long
87     gmx_cycles_t;
88
89 #elif ((defined(__hppa__) || defined(__hppa)) && defined (__hpux))
90 /* HP PA-RISC, instruction when using HP compiler */
91 #include <machine/inline.h>
92 typedef unsigned long
93     gmx_cycles_t;
94
95 #elif defined(__GNUC__) && defined(__s390__)
96 /* S390, taken from FFTW who got it from James Treacy */
97 typedef unsigned long long
98     gmx_cycles_t;
99
100 #elif defined(__GNUC__) && defined(__alpha__)
101 /* gcc inline assembly on alpha CPUs */
102 typedef unsigned long
103     gmx_cycles_t;
104
105 #elif defined(__GNUC__) && defined(__sparc_v9__)
106 /* gcc inline assembly on sparc v9 */
107 typedef unsigned long
108     gmx_cycles_t;
109
110 #elif defined(__DECC) && defined(__alpha)
111 /* Digital GEM C compiler on alpha */
112 #include <c_asm.h>
113 typedef unsigned long
114     gmx_cycles_t;
115
116 #elif (defined(__sgi) && defined(CLOCK_SGI_CYCLE))
117 /* Irix compilers on SGI hardware. Get nanoseconds from struct timespec */
118 typedef unsigned long long
119     gmx_cycles_t;
120
121 #elif (defined(__SVR4) && defined (__SUNPRO_CC))
122 /* Solaris high-resolution timers */
123 typedef hrtime_t
124     gmx_cycles_t;
125
126 #elif defined(__xlC__) && defined (_AIX)
127 /* AIX compilers */
128 #include <sys/time.h>
129 #include <sys/systemcfg.h>
130 typedef unsigned long long
131     gmx_cycles_t;
132
133 #elif ( ( defined(__GNUC__) || defined(__IBM_GCC_ASM) || defined(__IBM_STDCPP_ASM) ) && \
134     ( defined(__powerpc__) || defined(__ppc__) ) )
135 /* PowerPC using gcc inline assembly (also works on xlc>=7.0 with -qasm=gcc) */
136 typedef unsigned long long
137     gmx_cycles_t;
138
139 #elif (defined(__MWERKS__) && (defined(MAC) || defined(macintosh)))
140 /* Metrowerks on macintosh */
141 typedef unsigned long long
142     gmx_cycles_t;
143
144 #elif defined(__sun) && defined(__sparcv9)
145
146 typedef unsigned long
147     gmx_cycles_t;
148
149 #else
150 /*! \brief Integer-like datatype for cycle counter values
151  *
152  *  Depending on your system this will usually be something like long long,
153  *  or a special cycle datatype from the system header files. It is NOT
154  *  necessarily real processor cycles - many systems count in nanoseconds
155  *  or a special external time register at fixed frequency (not the CPU freq.)
156  *
157  *  You can subtract or add gmx_cycle_t types just as normal integers, and if
158  *  you run the calibration routine you can also multiply it with a factor to
159  *  translate the cycle data to seconds.
160  */
161 typedef long
162     gmx_cycles_t;
163
164 #endif
165
166 /*! \brief Check if high-resolution cycle counters are available
167  *
168  *  Not all architectures provide any way to read timestep counters
169  *  in the CPU, and on some it is broken. Although we refer to it
170  *  as cycle counters, it is not necessarily given in units of
171  *  cycles.
172  *
173  *  If you notice that system is missing, implement support for it,
174  *  find out how to detect the system during preprocessing, and send us a
175  *  patch.
176  *
177  *  \return 1 if cycle counters are available, 0 if not.
178  *
179  * \note This functions not need to be in the header for performance
180  *       reasons, but it is very important that we get exactly the
181  *       same detection as for gmx_cycles_read() routines. If you
182  *       compile the library with one compiler, and then use a different
183  *       one when later linking to the library it might happen that the
184  *       library supports cyclecounters but not the headers, or vice versa.
185  */
186 #if ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__)) && \
187     (defined(__i386__) || defined(__x86_64__)))
188 static __inline__ int gmx_cycles_have_counter(void)
189 {
190     /* x86 or x86-64 with GCC inline assembly - pentium TSC register */
191     return 1;
192 }
193 #elif (defined(_MSC_VER))
194 static __inline int gmx_cycles_have_counter(void)
195 {
196     return 1;
197 }
198 #elif (defined(__hpux) || defined(__HP_cc)) && defined(__ia64)
199 static inline int gmx_cycles_have_counter(void)
200 {
201     /* HP compiler on ia64, use special instruction to read ITC */
202     return 1;
203 }
204 #elif (defined(__INTEL_COMPILER) || defined(__ECC)) && defined(__ia64__)
205 static __inline__ int gmx_cycles_have_counter(void)
206 {
207     /* Intel compiler on ia64, use special instruction to read ITC */
208     return 1;
209 }
210 #elif defined(__GNUC__) && defined(__ia64__)
211 static __inline__ int gmx_cycles_have_counter(void)
212 {
213     /* AMD64 with GCC inline assembly - TSC register */
214     return 1;
215 }
216 #elif ((defined(__hppa__) || defined(__hppa)) && defined (__GNUC__))
217 static __inline__ int gmx_cycles_have_counter(void)
218 {
219     /* HP PA-RISC, inline asm with gcc */
220     return 1;
221 }
222 #elif ((defined(__hppa__) || defined(__hppa)) && defined (__hpux))
223 static inline int gmx_cycles_have_counter(void)
224 {
225     /* HP PA-RISC, instruction when using HP compiler */
226     return 1;
227 }
228 #elif defined(__GNUC__) && defined(__s390__)
229 static __inline__ int gmx_cycles_have_counter(void)
230 {
231     /* S390, taken from FFTW who got it from James Treacy */
232     return 1;
233 }
234 #elif defined(__GNUC__) && defined(__alpha__)
235 static __inline__ int gmx_cycles_have_counter(void)
236 {
237     /* gcc inline assembly on alpha CPUs */
238     return 1;
239 }
240 #elif defined(__GNUC__) && defined(__sparc_v9__)
241 static __inline__ int gmx_cycles_have_counter(void)
242 {
243     /* gcc inline assembly on sparc v9 */
244     return 1;
245 }
246 #elif defined(__DECC) && defined(__alpha)
247 static __inline int gmx_cycles_have_counter(void)
248 {
249     /* Digital GEM C compiler on alpha */
250     return 1;
251 }
252 #elif (defined(__sgi) && defined(CLOCK_SGI_CYCLE))
253 static __inline int gmx_cycles_have_counter(void)
254 {
255     /* Irix compilers on SGI hardware */
256     return 1;
257 }
258 #elif (defined(__SVR4) && defined (__SUNPRO_CC))
259 static inline int gmx_cycles_have_counter(void)
260 {
261     /* Solaris high-resolution timers */
262     return 1;
263 }
264 #elif defined(__xlC__) && defined (_AIX)
265 static inline int gmx_cycles_have_counter(void)
266 {
267     /* AIX compilers */
268     return 1;
269 }
270 #elif ( ( defined(__GNUC__) || defined(__IBM_GCC_ASM) || defined(__IBM_STDCPP_ASM) ) && \
271     ( defined(__powerpc__) || defined(__ppc__) ) )
272 static __inline__ int gmx_cycles_have_counter(void)
273 {
274     /* PowerPC using gcc inline assembly (and xlc>=7.0 with -qasm=gcc) */
275     return 1;
276 }
277 #elif (defined(__MWERKS__) && (defined(MAC) || defined(macintosh)))
278 static __inline__ int gmx_cycles_have_counter(void)
279 {
280     /* Metrowerks on macintosh */
281     return 1;
282 }
283 #elif defined(__sun) && defined(__sparcv9)
284
285 static __inline__ int gmx_cycles_have_counter(void)
286 {
287     /* Solaris on SPARC*/
288     return 1;
289 }
290 #else
291 static int gmx_cycles_have_counter(void)
292 {
293     /* No cycle counter that we know of on this system */
294     return 0;
295 }
296 #endif
297
298 /*! \brief Read CPU cycle counter
299  *
300  *  This routine returns an abstract datatype containing a
301  *  cycle counter timestamp.
302  *
303  *  \return Opaque data corresponding to a cycle reading.
304  *
305  *  Please note that on most systems it takes several cycles
306  *  to read and return the cycle counters. If you are measuring
307  *  small intervals, you can compensate for this time by calling
308  *  the routine twice and calculating what the difference is.
309  *  Subtract this from your other measurements to get an accurate result.
310  *
311  *  Use gmx_cycles_difference() to get a real number corresponding to
312  *  the difference between two gmx_cycles_t values returned from this
313  *  routine.
314  */
315 #if ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__)) && \
316     (defined(__i386__) || defined(__x86_64__)))
317 static __inline__ gmx_cycles_t gmx_cycles_read(void)
318 {
319     /* x86 with GCC inline assembly - pentium TSC register */
320     gmx_cycles_t   cycle;
321     unsigned       low, high;
322
323 #ifdef HAVE_RDTSCP
324     __asm__ __volatile__("rdtscp" : "=a" (low), "=d" (high) :: "ecx" );
325 #else
326     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
327 #endif
328
329     cycle = ((unsigned long long)low) | (((unsigned long long)high)<<32);
330
331     return cycle;
332 }
333 #elif defined(_MSC_VER)
334 static __inline gmx_cycles_t gmx_cycles_read(void)
335 {
336 #ifdef HAVE_RDTSCP
337     unsigned int ui;
338     return __rdtscp(&ui);
339 #else
340     return __rdtsc();
341 #endif
342 }
343 #elif (defined(__hpux) || defined(__HP_cc)) && defined(__ia64)
344 static inline gmx_cycles_t gmx_cycles_read(void)
345 {
346     /* HP compiler on ia64 */
347     gmx_cycles_t ret;
348     ret = _Asm_mov_from_ar (_AREG_ITC);
349     return ret;
350 }
351 #elif (defined(__INTEL_COMPILER) && defined(__ia64__))
352 static __inline__ gmx_cycles_t gmx_cycles_read(void)
353 {
354     /* Intel compiler on ia64 */
355     return __getReg(_IA64_REG_AR_ITC);
356 }
357 #elif defined(__GNUC__) && defined(__ia64__)
358 static __inline__ gmx_cycles_t gmx_cycles_read(void)
359 {
360     /* ia64 with GCC inline assembly */
361     gmx_cycles_t ret;
362     __asm__ __volatile__ ("mov %0=ar.itc" : "=r" (ret));
363     return ret;
364 }
365 #elif ((defined(__hppa__) || defined(__hppa)) && defined (__GNUC__))
366 static __inline__ gmx_cycles_t gmx_cycles_read(void)
367 {
368     /* HP PA-RISC, inline asm with gcc */
369     gmx_cycles_t ret;
370     __asm__ __volatile__("mfctl 16, %0" : "=r" (ret));
371     /* no input, nothing else clobbered */
372     return ret;
373 }
374 #elif ((defined(__hppa__) || defined(__hppa)) && defined (__hpux))
375 static inline gmx_cycles_t gmx_cycles_read(void)
376 {
377     /* HP PA-RISC, instruction when using HP compiler */
378     gmx_cycles_t ret;
379     _MFCTL(16, ret);
380     return ret;
381 }
382 #elif defined(__GNUC__) && defined(__s390__)
383 static __inline__ gmx_cycles_t gmx_cycles_read(void)
384 {
385     /* S390, taken from FFTW who got it from James Treacy */
386     gmx_cycles_t cycle;
387     __asm__("stck 0(%0)" : : "a" (&(cycle)) : "memory", "cc");
388     return cycle;
389 }
390 #elif defined(__GNUC__) && defined(__alpha__)
391 static __inline__ gmx_cycles_t gmx_cycles_read(void)
392 {
393     /* gcc inline assembly on alpha CPUs */
394     unsigned long cycle;
395     __asm__ __volatile__ ("rpcc %0" : "=r" (cycle));
396     return (cycle & 0xFFFFFFFF);
397 }
398 #elif defined(__GNUC__) && defined(__sparc_v9__)
399 static __inline__ gmx_cycles_t gmx_cycles_read(void)
400 {
401     /* gcc inline assembly on sparc v9 */
402     unsigned long ret;
403     __asm__("rd %%tick, %0" : "=r" (ret));
404     return ret;
405 }
406 #elif defined(__DECC) && defined(__alpha)
407 static __inline gmx_cycles_t gmx_cycles_read(void)
408 {
409     /* Digital GEM C compiler on alpha */
410     unsigned long cycle;
411     cycle = asm ("rpcc %v0");
412     return (cycle & 0xFFFFFFFF);
413 }
414 #elif (defined(__sgi) && defined(CLOCK_SGI_CYCLE))
415 static __inline gmx_cycles_t gmx_cycles_read(void)
416 {
417     /* Irix compilers on SGI hardware */
418     struct timespec t;
419     clock_gettime(CLOCK_SGI_CYCLE, &t);
420     /* Return the number of nanoseconds, so we can subtract/add */
421     return ((unsigned long long)t.tv_sec)*1000000000+
422            (unsigned long long)t.tv_nsec;
423 }
424 #elif (defined(__SVR4) && defined (__SUNPRO_CC))
425 static inline gmx_cycles_t gmx_cycles_read(void)
426 {
427     /* Solaris high-resolution timers */
428     return gethrtime();
429 }
430 #elif defined(__xlC__) && defined (_AIX)
431 static inline gmx_cycles_t gmx_cycles_read(void)
432 {
433     /* AIX compilers. Inline the calculation instead of using library functions */
434     timebasestruct_t t1;
435     read_real_time(&t1, TIMEBASE_SZ);
436     /* POWER returns real time (seconds + nanoseconds),
437      * POWER_PC returns high/low 32 bits of a counter.
438      */
439     if (t1.flag == RTC_POWER_PC)
440     {
441         return ((gmx_cycles_t)t1.tb_high)<<32 | (gmx_cycles_t)t1.tb_low;
442     }
443     else
444     {
445         return ((gmx_cycles_t)t1.tb_high)*1000000000+(gmx_cycles_t)t1.tb_low;
446     }
447 }
448 #elif ( ( defined(__GNUC__) || defined(__IBM_GCC_ASM) || defined(__IBM_STDCPP_ASM) ) && \
449     ( defined(__powerpc__) || defined(__ppc__) ) )
450 static __inline__ gmx_cycles_t gmx_cycles_read(void)
451 {
452     /* PowerPC using gcc inline assembly (and xlC>=7.0 with -qasm=gcc) */
453     unsigned long low, high1, high2;
454     do
455     {
456         __asm__ __volatile__ ("mftbu %0" : "=r" (high1) : );
457         __asm__ __volatile__ ("mftb %0" : "=r" (low) : );
458         __asm__ __volatile__ ("mftbu %0" : "=r" (high2) : );
459     }
460     while (high1 != high2);
461
462     return (((gmx_cycles_t)high2) << 32) | (gmx_cycles_t)low;
463 }
464 #elif (defined(__MWERKS__) && (defined(MAC) || defined(macintosh)))
465 static __inline__ gmx_cycles_t gmx_cycles_read(void)
466 {
467     /* Metrowerks on macintosh */
468     unsigned int long low, high1, high2;
469     do
470     {
471         __asm__ __volatile__ ("mftbu %0" : "=r" (high1) : );
472         __asm__ __volatile__ ("mftb %0" : "=r" (low) : );
473         __asm__ __volatile__ ("mftbu %0" : "=r" (high2) : );
474     }
475     while (high1 != high2);
476
477     return (((gmx_cycles_t)high2) << 32) | (gmx_cycles_t)low;
478 }
479 #elif defined(__sun) && defined(__sparcv9)
480
481 static __inline__ gmx_cycles_t gmx_cycles_read(void)
482 {
483     gmx_cycles_t ret;
484     __asm__ __volatile__("rd %%tick, %0" : "=r" (ret));
485     return ret;
486 }
487
488 #else
489 static gmx_cycles_t gmx_cycles_read(void)
490 {
491     return 0;
492 }
493 #endif
494
495 /*! \brief Calculate number of seconds per cycle tick on host
496  *
497  *  This routine runs a timer loop to calibrate the number of
498  *  seconds per the units returned fro gmx_cycles_read().
499  *
500  *  \param  sampletime Minimum real sample time. It takes some trial-and-error
501  *          to find the correct delay loop size, so the total runtime of
502  *          this routine is about twice this time.
503  *  \return Number of seconds per cycle unit. If it is not possible to
504  *          calculate on this system (for whatever reason) the return value
505  *          will be -1, so check that it is positive before using it.
506  */
507 double
508 gmx_cycles_calibrate(double sampletime);
509
510 #ifdef __cplusplus
511 }
512 #endif
513
514 #endif