clock.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MPL-2.0 */
2 
3 #include "precompiled.hpp"
4 #include "clock.hpp"
5 #include "likely.hpp"
6 #include "config.hpp"
7 #include "err.hpp"
8 #include "mutex.hpp"
9 
10 #include <stddef.h>
11 
12 #if defined _MSC_VER
13 #if defined _WIN32_WCE
14 #include <cmnintrin.h>
15 #else
16 #include <intrin.h>
17 #if defined(_M_ARM) || defined(_M_ARM64)
18 #include <arm_neon.h>
19 #endif
20 #endif
21 #endif
22 
23 #if !defined ZMQ_HAVE_WINDOWS
24 #include <sys/time.h>
25 #endif
26 
27 #if defined HAVE_CLOCK_GETTIME || defined HAVE_GETHRTIME
28 #include <time.h>
29 #endif
30 
31 #if defined ZMQ_HAVE_VXWORKS
32 #include "timers.h"
33 #endif
34 
35 #if defined ZMQ_HAVE_OSX
36 int alt_clock_gettime (int clock_id, timespec *ts)
37 {
38  clock_serv_t cclock;
39  mach_timespec_t mts;
40  host_get_clock_service (mach_host_self (), clock_id, &cclock);
41  clock_get_time (cclock, &mts);
42  mach_port_deallocate (mach_task_self (), cclock);
43  ts->tv_sec = mts.tv_sec;
44  ts->tv_nsec = mts.tv_nsec;
45  return 0;
46 }
47 #endif
48 
49 #ifdef ZMQ_HAVE_WINDOWS
50 typedef ULONGLONG (*f_compatible_get_tick_count64) ();
51 
52 static zmq::mutex_t compatible_get_tick_count64_mutex;
53 
54 ULONGLONG compatible_get_tick_count64 ()
55 {
56 #ifdef ZMQ_HAVE_WINDOWS_UWP
57  const ULONGLONG result = ::GetTickCount64 ();
58  return result;
59 #else
60  zmq::scoped_lock_t locker (compatible_get_tick_count64_mutex);
61 
62  static DWORD s_wrap = 0;
63  static DWORD s_last_tick = 0;
64  const DWORD current_tick = ::GetTickCount ();
65 
66  if (current_tick < s_last_tick)
67  ++s_wrap;
68 
69  s_last_tick = current_tick;
70  const ULONGLONG result = (static_cast<ULONGLONG> (s_wrap) << 32)
71  + static_cast<ULONGLONG> (current_tick);
72 
73  return result;
74 #endif
75 }
76 
77 f_compatible_get_tick_count64 init_compatible_get_tick_count64 ()
78 {
79  f_compatible_get_tick_count64 func = NULL;
80 #if !defined ZMQ_HAVE_WINDOWS_UWP
81 
82  const HMODULE module = ::LoadLibraryA ("Kernel32.dll");
83  if (module != NULL)
84  func = reinterpret_cast<f_compatible_get_tick_count64> (
85  ::GetProcAddress (module, "GetTickCount64"));
86 #endif
87  if (func == NULL)
88  func = compatible_get_tick_count64;
89 
90 #if !defined ZMQ_HAVE_WINDOWS_UWP
91  if (module != NULL)
92  ::FreeLibrary (module);
93 #endif
94 
95  return func;
96 }
97 
98 static f_compatible_get_tick_count64 my_get_tick_count64 =
99  init_compatible_get_tick_count64 ();
100 #endif
101 
102 #ifndef ZMQ_HAVE_WINDOWS
103 const uint64_t usecs_per_msec = 1000;
104 const uint64_t nsecs_per_usec = 1000;
105 #endif
106 const uint64_t usecs_per_sec = 1000000;
107 
109  _last_tsc (rdtsc ()),
110 #ifdef ZMQ_HAVE_WINDOWS
111  _last_time (static_cast<uint64_t> ((*my_get_tick_count64) ()))
112 #else
113  _last_time (now_us () / usecs_per_msec)
114 #endif
115 {
116 }
117 
119 {
120 #if defined ZMQ_HAVE_WINDOWS
121 
122  // Get the high resolution counter's accuracy.
123  // While QueryPerformanceFrequency only needs to be called once, since its
124  // value does not change during runtime, we query it here since this is a
125  // static function. It might make sense to cache it, though.
126  LARGE_INTEGER ticks_per_second;
127  QueryPerformanceFrequency (&ticks_per_second);
128 
129  // What time is it?
130  LARGE_INTEGER tick;
131  QueryPerformanceCounter (&tick);
132 
133  // Convert the tick number into the number of seconds
134  // since the system was started.
135  const double ticks_div =
136  static_cast<double> (ticks_per_second.QuadPart) / usecs_per_sec;
137  return static_cast<uint64_t> (tick.QuadPart / ticks_div);
138 
139 #elif defined HAVE_CLOCK_GETTIME \
140  && (defined CLOCK_MONOTONIC || defined ZMQ_HAVE_VXWORKS)
141 
142  // Use POSIX clock_gettime function to get precise monotonic time.
143  struct timespec tv;
144 
145 #if defined ZMQ_HAVE_OSX \
146  && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
147  int rc = alt_clock_gettime (SYSTEM_CLOCK, &tv);
148 #else
149  int rc = clock_gettime (CLOCK_MONOTONIC, &tv);
150 #endif
151  // Fix case where system has clock_gettime but CLOCK_MONOTONIC is not supported.
152  // This should be a configuration check, but I looked into it and writing an
153  // AC_FUNC_CLOCK_MONOTONIC seems beyond my powers.
154  if (rc != 0) {
155 #ifndef ZMQ_HAVE_VXWORKS
156  // Use POSIX gettimeofday function to get precise time.
157  struct timeval tv;
158  int rc = gettimeofday (&tv, NULL);
159  errno_assert (rc == 0);
160  return tv.tv_sec * usecs_per_sec + tv.tv_usec;
161 #endif
162  }
163  return tv.tv_sec * usecs_per_sec + tv.tv_nsec / nsecs_per_usec;
164 
165 #elif defined HAVE_GETHRTIME
166 
167  return gethrtime () / nsecs_per_usec;
168 
169 #else
170 
172  // Use POSIX gettimeofday function to get precise time.
173  struct timeval tv;
174  int rc = gettimeofday (&tv, NULL);
175  errno_assert (rc == 0);
176  return tv.tv_sec * usecs_per_sec + tv.tv_usec;
177 
178 #endif
179 }
180 
182 {
183  const uint64_t tsc = rdtsc ();
184 
185  // If TSC is not supported, get precise time and chop off the microseconds.
186  if (!tsc) {
187 #ifdef ZMQ_HAVE_WINDOWS
188  // Under Windows, now_us is not so reliable since QueryPerformanceCounter
189  // does not guarantee that it will use a hardware that offers a monotonic timer.
190  // So, lets use GetTickCount when GetTickCount64 is not available with an workaround
191  // to its 32 bit limitation.
192  return static_cast<uint64_t> ((*my_get_tick_count64) ());
193 #else
194  return now_us () / usecs_per_msec;
195 #endif
196  }
197 
198  // If TSC haven't jumped back (in case of migration to a different
199  // CPU core) and if not too much time elapsed since last measurement,
200  // we can return cached time value.
201  if (likely (tsc - _last_tsc <= (clock_precision / 2) && tsc >= _last_tsc))
202  return _last_time;
203 
204  _last_tsc = tsc;
205 #ifdef ZMQ_HAVE_WINDOWS
206  _last_time = static_cast<uint64_t> ((*my_get_tick_count64) ());
207 #else
208  _last_time = now_us () / usecs_per_msec;
209 #endif
210  return _last_time;
211 }
212 
214 {
215 #if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))
216  return __rdtsc ();
217 #elif defined(_MSC_VER) && defined(_M_ARM) // NC => added for windows ARM
218  return __rdpmccntr64 ();
219 #elif defined(_MSC_VER) && defined(_M_ARM64) // NC => added for windows ARM64
220  const int64_t pmccntr_el0 = (((3 & 1) << 14) | // op0
221  ((3 & 7) << 11) | // op1
222  ((9 & 15) << 7) | // crn
223  ((13 & 15) << 3) | // crm
224  ((0 & 7) << 0)); // op2
225  return _ReadStatusReg (pmccntr_el0);
226 #elif (defined(_WIN32) && defined(__GNUC__) && defined(__aarch64__))
227  uint64_t val;
228  __asm__ volatile("mrs %0, pmccntr_el0" : "=r"(val));
229  return val;
230 #elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__))
231  uint32_t low, high;
232  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
233  return static_cast<uint64_t> (high) << 32 | low;
234 #elif (defined __SUNPRO_CC && (__SUNPRO_CC >= 0x5100) \
235  && (defined __i386 || defined __amd64 || defined __x86_64))
236  union
237  {
238  uint64_t u64val;
239  uint32_t u32val[2];
240  } tsc;
241  asm("rdtsc" : "=a"(tsc.u32val[0]), "=d"(tsc.u32val[1]));
242  return tsc.u64val;
243 #elif defined(__s390__)
244  uint64_t tsc;
245  asm("\tstck\t%0\n" : "=Q"(tsc) : : "cc");
246  return tsc;
247 #else
248  struct timespec ts;
249 #if defined ZMQ_HAVE_OSX \
250  && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
251  alt_clock_gettime (SYSTEM_CLOCK, &ts);
252 #else
253  clock_gettime (CLOCK_MONOTONIC, &ts);
254 #endif
255  return static_cast<uint64_t> (ts.tv_sec) * nsecs_per_usec * usecs_per_sec
256  + ts.tv_nsec;
257 #endif
258 }
zmq::clock_t::clock_t
clock_t()
Definition: clock.cpp:108
NULL
NULL
Definition: test_security_zap.cpp:405
config.hpp
usecs_per_sec
const uint64_t usecs_per_sec
Definition: clock.cpp:106
precompiled.hpp
clock.hpp
zmq::clock_precision
@ clock_precision
Definition: config.hpp:50
likely
#define likely(x)
Definition: likely.hpp:10
errno_assert
#define errno_assert(x)
Definition: err.hpp:113
LIBZMQ_UNUSED
#define LIBZMQ_UNUSED(object)
Definition: macros.hpp:6
zmq::clock_t::now_us
static uint64_t now_us()
Definition: clock.cpp:118
zmq::mutex_t
Definition: mutex.hpp:82
zmq::clock_t::rdtsc
static uint64_t rdtsc()
Definition: clock.cpp:213
timers.h
func
GLenum func
Definition: glcorearb.h:3052
err.hpp
zmq::clock_t::now_ms
uint64_t now_ms()
Definition: clock.cpp:181
likely.hpp
nsecs_per_usec
const uint64_t nsecs_per_usec
Definition: clock.cpp:104
val
GLuint GLfloat * val
Definition: glcorearb.h:3604
usecs_per_msec
const uint64_t usecs_per_msec
Definition: clock.cpp:103
ZMQ_HAVE_WINDOWS
#define ZMQ_HAVE_WINDOWS
Definition: deprecated-msvc/platform.hpp:4
zmq::scoped_lock_t
Definition: mutex.hpp:143
mutex.hpp


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:48