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