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