libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
clock.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3 
4  This file is part of libzmq, the ZeroMQ core engine in C++.
5 
6  libzmq is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License (LGPL) as published
8  by the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
10 
11  As a special exception, the Contributors give you permission to link
12  this library with independent modules to produce an executable,
13  regardless of the license terms of these independent modules, and to
14  copy and distribute the resulting executable under terms of your choice,
15  provided that you also meet, for each linked independent module, the
16  terms and conditions of the license of that module. An independent
17  module is a module which is not derived from or based on this library.
18  If you modify this library, you must extend this exception to your
19  version of the library.
20 
21  libzmq is distributed in the hope that it will be useful, but WITHOUT
22  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24  License for more details.
25 
26  You should have received a copy of the GNU Lesser General Public License
27  along with this program. If not, see <http://www.gnu.org/licenses/>.
28 */
29 
30 #include "precompiled.hpp"
31 #include "clock.hpp"
32 #include "platform.hpp"
33 #include "likely.hpp"
34 #include "config.hpp"
35 #include "err.hpp"
36 #include "mutex.hpp"
37 
38 #include <stddef.h>
39 
40 #if defined _MSC_VER
41 #if defined _WIN32_WCE
42 #include <cmnintrin.h>
43 #else
44 #include <intrin.h>
45 #endif
46 #endif
47 
48 #if !defined ZMQ_HAVE_WINDOWS
49 #include <sys/time.h>
50 #endif
51 
52 #if defined HAVE_CLOCK_GETTIME || defined HAVE_GETHRTIME
53 #include <time.h>
54 #endif
55 
56 #if defined ZMQ_HAVE_OSX
57 #include <mach/clock.h>
58 #include <mach/mach.h>
59 #include <time.h>
60 #include <sys/time.h>
61 
62 int clock_gettime (int clock_id, timespec *ts)
63 {
64  // The clock_id specified is not supported on this system.
65  if (clock_id != CLOCK_REALTIME) {
66  errno = EINVAL;
67  return -1;
68  }
69 
70  clock_serv_t cclock;
71  mach_timespec_t mts;
72  host_get_clock_service (mach_host_self (), CALENDAR_CLOCK, &cclock);
73  clock_get_time (cclock, &mts);
74  mach_port_deallocate (mach_task_self (), cclock);
75  ts->tv_sec = mts.tv_sec;
76  ts->tv_nsec = mts.tv_nsec;
77  return 0;
78 }
79 #endif
80 
81 #ifdef ZMQ_HAVE_WINDOWS
82 typedef ULONGLONG (*f_compatible_get_tick_count64)();
83 
84 static zmq::mutex_t compatible_get_tick_count64_mutex;
85 
86 ULONGLONG compatible_get_tick_count64()
87 {
88  compatible_get_tick_count64_mutex.lock();
89  static DWORD s_wrap = 0;
90  static DWORD s_last_tick = 0;
91  const DWORD current_tick = ::GetTickCount();
92  if (current_tick < s_last_tick)
93  ++s_wrap;
94 
95  s_last_tick = current_tick;
96  const ULONGLONG result = (static_cast<ULONGLONG>(s_wrap) << 32) + static_cast<ULONGLONG>(current_tick);
97  compatible_get_tick_count64_mutex.unlock();
98  return result;
99 }
100 
101 f_compatible_get_tick_count64 init_compatible_get_tick_count64()
102 {
103  f_compatible_get_tick_count64 func = NULL;
104  HMODULE module = ::LoadLibraryA("Kernel32.dll");
105  if (module != NULL)
106  func = reinterpret_cast<f_compatible_get_tick_count64>(::GetProcAddress(module, "GetTickCount64"));
107 
108  if (func == NULL)
109  func = compatible_get_tick_count64;
110 
111  ::FreeLibrary(module);
112 
113  return func;
114 }
115 
116 static f_compatible_get_tick_count64 my_get_tick_count64 = init_compatible_get_tick_count64();
117 #endif
118 
120  last_tsc (rdtsc ()),
121 #ifdef ZMQ_HAVE_WINDOWS
122  last_time (static_cast<uint64_t>((*my_get_tick_count64)()))
123 #else
124  last_time (now_us () / 1000)
125 #endif
126 {
127 }
128 
130 {
131 }
132 
134 {
135 #if defined ZMQ_HAVE_WINDOWS
136 
137  // Get the high resolution counter's accuracy.
138  LARGE_INTEGER ticksPerSecond;
139  QueryPerformanceFrequency (&ticksPerSecond);
140 
141  // What time is it?
142  LARGE_INTEGER tick;
143  QueryPerformanceCounter (&tick);
144 
145  // Convert the tick number into the number of seconds
146  // since the system was started.
147  double ticks_div = ticksPerSecond.QuadPart / 1000000.0;
148  return (uint64_t) (tick.QuadPart / ticks_div);
149 
150 #elif defined HAVE_CLOCK_GETTIME && defined CLOCK_MONOTONIC
151 
152  // Use POSIX clock_gettime function to get precise monotonic time.
153  struct timespec tv;
154  int rc = clock_gettime (CLOCK_MONOTONIC, &tv);
155  // Fix case where system has clock_gettime but CLOCK_MONOTONIC is not supported.
156  // This should be a configuration check, but I looked into it and writing an
157  // AC_FUNC_CLOCK_MONOTONIC seems beyond my powers.
158  if( rc != 0) {
159  // Use POSIX gettimeofday function to get precise time.
160  struct timeval tv;
161  int rc = gettimeofday (&tv, NULL);
162  errno_assert (rc == 0);
163  return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec);
164  }
165  return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_nsec / 1000);
166 
167 #elif defined HAVE_GETHRTIME
168 
169  return (gethrtime () / 1000);
170 
171 #else
172 
173  // Use POSIX gettimeofday function to get precise time.
174  struct timeval tv;
175  int rc = gettimeofday (&tv, NULL);
176  errno_assert (rc == 0);
177  return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec);
178 
179 #endif
180 }
181 
183 {
184  uint64_t tsc = rdtsc ();
185 
186  // If TSC is not supported, get precise time and chop off the microseconds.
187  if (!tsc)
188  {
189 #ifdef ZMQ_HAVE_WINDOWS
190  // Under Windows, now_us is not so reliable since QueryPerformanceCounter
191  // does not guarantee that it will use a hardware that offers a monotonic timer.
192  // So, lets use GetTickCount when GetTickCount64 is not available with an workaround
193  // to its 32 bit limitation.
194  return static_cast<uint64_t>((*my_get_tick_count64)());
195 #else
196  return now_us () / 1000;
197 #endif
198  }
199 
200  // If TSC haven't jumped back (in case of migration to a different
201  // CPU core) and if not too much time elapsed since last measurement,
202  // we can return cached time value.
203  if (likely (tsc - last_tsc <= (clock_precision / 2) && tsc >= last_tsc))
204  return last_time;
205 
206  last_tsc = tsc;
207 #ifdef ZMQ_HAVE_WINDOWS
208  last_time = static_cast<uint64_t>((*my_get_tick_count64)());
209 #else
210  last_time = now_us () / 1000;
211 #endif
212  return last_time;
213 }
214 
216 {
217 #if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))
218  return __rdtsc ();
219 #elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__))
220  uint32_t low, high;
221  __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
222  return (uint64_t) high << 32 | low;
223 #elif (defined __SUNPRO_CC && (__SUNPRO_CC >= 0x5100) && (defined __i386 || \
224  defined __amd64 || defined __x86_64))
225  union {
226  uint64_t u64val;
227  uint32_t u32val [2];
228  } tsc;
229  asm("rdtsc" : "=a" (tsc.u32val [0]), "=d" (tsc.u32val [1]));
230  return tsc.u64val;
231 #elif defined(__s390__)
232  uint64_t tsc;
233  asm("\tstck\t%0\n" : "=Q" (tsc) : : "cc");
234  return(tsc);
235 #else
236  return 0;
237 #endif
238 }
uint64_t now_ms()
Definition: clock.cpp:182
uint64_t last_tsc
Definition: clock.hpp:68
uint64_t last_time
Definition: clock.hpp:71
static uint64_t now_us()
Definition: clock.cpp:133
static uint64_t rdtsc()
Definition: clock.cpp:215
void lock()
Definition: mutex.hpp:120
#define errno_assert(x)
Definition: err.hpp:129
#define likely(x)
Definition: likely.hpp:37