1 /******************************************************************************
2 * Copyright (c) Intel Corporation - All rights reserved.                      *
3 * This file is part of the LIBXSMM library.                                   *
4 *                                                                             *
5 * For information on the license, see the LICENSE file.                       *
6 * Further information: https://github.com/hfp/libxsmm/                        *
7 * SPDX-License-Identifier: BSD-3-Clause                                       *
8 ******************************************************************************/
9 /* Hans Pabst (Intel Corp.)
10 ******************************************************************************/
11 #include <libxsmm_timer.h>
12 #include "libxsmm_main.h"
13 
14 #if defined(LIBXSMM_OFFLOAD_TARGET)
15 # pragma offload_attribute(push,target(LIBXSMM_OFFLOAD_TARGET))
16 #endif
17 #if defined(_WIN32)
18 # include <Windows.h>
19 #elif defined(__GNUC__) || defined(__PGI) || defined(_CRAYC)
20 # include <sys/time.h>
21 # include <time.h>
22 #endif
23 #if defined(LIBXSMM_OFFLOAD_TARGET)
24 # pragma offload_attribute(pop)
25 #endif
26 
27 #if defined(__powerpc64__) && defined(__GLIBC__)
28 # include <sys/platform/ppc.h>
29 #endif
30 
31 #if !defined(LIBXSMM_TIMER_TSC)
32 # define LIBXSMM_TIMER_TSC
33 #endif
34 #if !defined(LIBXSMM_TIMER_WPC)
35 # define LIBXSMM_TIMER_WPC
36 #endif
37 
38 #if defined(LIBXSMM_TIMER_TSC)
39 # if defined(__powerpc64__)
40 #  if defined(__GLIBC__)
41 #   define LIBXSMM_TIMER_RDTSC(CYCLE) { \
42       CYCLE = __ppc_get_timebase(); \
43     }
44 #  else
45 #   define LIBXSMM_TIMER_RDTSC(CYCLE) asm volatile("mfspr %%r3, 268": "=r" (CYCLE));
46 #  endif
47 # elif ((defined(__GNUC__) || defined(LIBXSMM_INTEL_COMPILER) || defined(__PGI)) && (64 <= (LIBXSMM_BITS)))
48 #   define LIBXSMM_TIMER_RDTSC(CYCLE) { libxsmm_timer_tickint libxsmm_timer_rdtsc_hi_; \
49       __asm__ __volatile__ ("rdtsc" : "=a"(CYCLE), "=d"(libxsmm_timer_rdtsc_hi_)); \
50       CYCLE |= libxsmm_timer_rdtsc_hi_ << 32; \
51     }
52 # elif (defined(_rdtsc) || defined(_WIN32))
53 #   define LIBXSMM_TIMER_RDTSC(CYCLE) (CYCLE = __rdtsc())
54 # endif
55 #endif
56 
57 
libxsmm_timer_duration_rtc(libxsmm_timer_tickint tick0,libxsmm_timer_tickint tick1)58 LIBXSMM_API_INTERN double libxsmm_timer_duration_rtc(libxsmm_timer_tickint tick0, libxsmm_timer_tickint tick1)
59 {
60   double result = (double)LIBXSMM_DELTA(tick0, tick1);
61 #if defined(_WIN32)
62 # if defined(LIBXSMM_TIMER_WPC)
63   LARGE_INTEGER frequency;
64   QueryPerformanceFrequency(&frequency);
65   result /= (double)frequency.QuadPart;
66 # else /* low resolution */
67   result *= 1E-3;
68 # endif
69 #elif defined(CLOCK_MONOTONIC)
70   result *= 1E-9;
71 #else
72   result *= 1E-6;
73 #endif
74   return result;
75 }
76 
77 
libxsmm_timer_tick_rtc(void)78 LIBXSMM_API_INTERN libxsmm_timer_tickint libxsmm_timer_tick_rtc(void)
79 {
80   libxsmm_timer_tickint result;
81 #if defined(_WIN32)
82 # if defined(LIBXSMM_TIMER_WPC)
83   LARGE_INTEGER t;
84   QueryPerformanceCounter(&t);
85   result = (libxsmm_timer_tickint)t.QuadPart;
86 # else /* low resolution */
87   result = (libxsmm_timer_tickint)GetTickCount64();
88 # endif
89 #elif defined(CLOCK_MONOTONIC)
90   struct timespec t;
91   clock_gettime(CLOCK_MONOTONIC, &t);
92   result = 1000000000ULL * t.tv_sec + t.tv_nsec;
93 #else
94   struct timeval t;
95   gettimeofday(&t, 0);
96   result = 1000000ULL * t.tv_sec + t.tv_usec;
97 #endif
98   return result;
99 }
100 
101 
LIBXSMM_INTRINSICS(LIBXSMM_X86_GENERIC)102 LIBXSMM_API_INTERN LIBXSMM_INTRINSICS(LIBXSMM_X86_GENERIC)
103 libxsmm_timer_tickint libxsmm_timer_tick_tsc(void)
104 {
105   libxsmm_timer_tickint result;
106 #if defined(LIBXSMM_TIMER_RDTSC)
107   LIBXSMM_TIMER_RDTSC(result);
108 #else
109   result = libxsmm_timer_tick_rtc();
110 #endif
111   return result;
112 }
113 
114 
libxsmm_get_timer_info(libxsmm_timer_info * info)115 LIBXSMM_API int libxsmm_get_timer_info(libxsmm_timer_info* info)
116 {
117   int result;
118   if (NULL != info) {
119 #if defined(LIBXSMM_TIMER_RDTSC)
120     if (0 < libxsmm_timer_scale) {
121       info->tsc = 1;
122     }
123 # if !defined(LIBXSMM_INIT_COMPLETED)
124     else if (2 > libxsmm_ninit) {
125       libxsmm_init();
126       if (0 < libxsmm_timer_scale) {
127         info->tsc = 1;
128       }
129       else {
130         info->tsc = 0;
131       }
132     }
133 # endif
134     else {
135       info->tsc = 0;
136     }
137 #else
138     info->tsc = 0;
139 #endif
140     result = EXIT_SUCCESS;
141   }
142   else {
143     static int error_once = 0;
144     if (0 != libxsmm_verbosity /* library code is expected to be mute */
145       && 1 == LIBXSMM_ATOMIC_ADD_FETCH(&error_once, 1, LIBXSMM_ATOMIC_RELAXED))
146     {
147       fprintf(stderr, "LIBXSMM ERROR: invalid argument for libxsmm_get_timer_info specified!\n");
148     }
149     result = EXIT_FAILURE;
150   }
151   return result;
152 }
153 
154 
libxsmm_timer_tick(void)155 LIBXSMM_API libxsmm_timer_tickint libxsmm_timer_tick(void)
156 {
157   libxsmm_timer_tickint result;
158 #if defined(LIBXSMM_TIMER_RDTSC)
159   if (0 < libxsmm_timer_scale) {
160     LIBXSMM_TIMER_RDTSC(result);
161   }
162 # if !defined(LIBXSMM_INIT_COMPLETED)
163   else if (2 > libxsmm_ninit) {
164     libxsmm_init();
165     if (0 < libxsmm_timer_scale) {
166       LIBXSMM_TIMER_RDTSC(result);
167     }
168     else {
169       result = libxsmm_timer_tick_rtc();
170     }
171   }
172 # endif
173   else {
174     result = libxsmm_timer_tick_rtc();
175   }
176 #else
177   result = libxsmm_timer_tick_rtc();
178 #endif
179   return result;
180 }
181 
182 
libxsmm_timer_duration(libxsmm_timer_tickint tick0,libxsmm_timer_tickint tick1)183 LIBXSMM_API double libxsmm_timer_duration(libxsmm_timer_tickint tick0, libxsmm_timer_tickint tick1)
184 {
185   double result;
186 #if defined(LIBXSMM_TIMER_RDTSC)
187   if (0 < libxsmm_timer_scale) {
188     result = (double)LIBXSMM_DELTA(tick0, tick1) * libxsmm_timer_scale;
189   }
190   else
191 #endif
192   {
193     result = libxsmm_timer_duration_rtc(tick0, tick1);
194   }
195   return result;
196 }
197 
198 
199 #if defined(LIBXSMM_BUILD) && (!defined(LIBXSMM_NOFORTRAN) || defined(__clang_analyzer__))
200 
201 /* implementation provided for Fortran 77 compatibility */
202 LIBXSMM_API void LIBXSMM_FSYMBOL(libxsmm_timer_ncycles)(libxsmm_timer_tickint* /*ncycles*/, const libxsmm_timer_tickint* /*tick0*/, const libxsmm_timer_tickint* /*tick1*/);
LIBXSMM_FSYMBOL(libxsmm_timer_ncycles)203 LIBXSMM_API void LIBXSMM_FSYMBOL(libxsmm_timer_ncycles)(libxsmm_timer_tickint* ncycles, const libxsmm_timer_tickint* tick0, const libxsmm_timer_tickint* tick1)
204 {
205 #if !defined(NDEBUG)
206   static int error_once = 0;
207   if (NULL != ncycles && NULL != tick0 && NULL != tick1)
208 #endif
209   {
210     *ncycles = libxsmm_timer_ncycles(*tick0, *tick1);
211   }
212 #if !defined(NDEBUG)
213   else if (0 != libxsmm_verbosity /* library code is expected to be mute */
214     && 1 == LIBXSMM_ATOMIC_ADD_FETCH(&error_once, 1, LIBXSMM_ATOMIC_RELAXED))
215   {
216     fprintf(stderr, "LIBXSMM ERROR: invalid arguments for libxsmm_timer_ncycles specified!\n");
217   }
218 #endif
219 }
220 
221 #endif /*defined(LIBXSMM_BUILD) && (!defined(LIBXSMM_NOFORTRAN) || defined(__clang_analyzer__))*/
222 
223