1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 :
8 : // Make sure that winmm.lib is added to the linker's input.
9 : #pragma comment(lib, "winmm.lib")
10 : #include "native_client/src/include/portability.h"
11 : #include <mmsystem.h>
12 : #include <windows.h>
13 :
14 : #include "native_client/src/include/checked_cast.h"
15 : #include "native_client/src/shared/platform/win/time.h"
16 : #include "native_client/src/shared/platform/win/lock.h"
17 :
18 : namespace {
19 :
20 : // From MSDN, FILETIME "Contains a 64-bit value representing the number of
21 : // 100-nanosecond intervals since January 1, 1601 (UTC)."
22 0 : int64_t FileTimeToMicroseconds(const FILETIME& ft) {
23 : // Need to nacl_bit_cast to fix alignment, then divide by 10 to convert
24 : // 100-nanoseconds to milliseconds. This only works on little-endian
25 : // machines.
26 0 : return nacl_bit_cast<int64_t, FILETIME>(ft) / 10;
27 0 : }
28 :
29 0 : void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
30 : /* DCHECK(us >= 0) << "Time is less than 0, negative values are not "
31 : * "representable in FILETIME";
32 : */
33 :
34 : // Multiply by 10 to convert milliseconds to 100-nanoseconds. Nacl_bit_cast
35 : // will handle alignment problems. This only works on little-endian machines.
36 0 : *ft = nacl_bit_cast<FILETIME, int64_t>(us * 10);
37 0 : }
38 :
39 : } // namespace
40 :
41 : // Time -----------------------------------------------------------------------
42 :
43 : // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
44 : // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
45 : // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
46 : // 1700, 1800, and 1900.
47 : // static
48 : const int64_t NaCl::Time::kTimeTToMicrosecondsOffset =
49 : GG_INT64_C(11644473600000000);
50 :
51 : // static
52 0 : int64_t NaCl::Time::CurrentWallclockMicroseconds() {
53 : FILETIME ft;
54 0 : ::GetSystemTimeAsFileTime(&ft);
55 0 : return FileTimeToMicroseconds(ft);
56 0 : }
57 :
58 : // static
59 0 : NaCl::Time NaCl::Time::FromFileTime(FILETIME ft) {
60 0 : return Time(FileTimeToMicroseconds(ft));
61 0 : }
62 :
63 0 : FILETIME NaCl::Time::ToFileTime() const {
64 : FILETIME utc_ft;
65 0 : MicrosecondsToFileTime(us_, &utc_ft);
66 0 : return utc_ft;
67 0 : }
68 :
69 : // static
70 0 : NaCl::Time NaCl::Time::FromExploded(bool is_local, const Exploded& exploded) {
71 : // Create the system struct representing our exploded time. It will either be
72 : // in local time or UTC.
73 : SYSTEMTIME st;
74 0 : st.wYear = nacl::assert_cast<WORD>(exploded.year);
75 0 : st.wMonth = nacl::assert_cast<WORD>(exploded.month);
76 0 : st.wDayOfWeek = nacl::assert_cast<WORD>(exploded.day_of_week);
77 0 : st.wDay = nacl::assert_cast<WORD>(exploded.day_of_month);
78 0 : st.wHour = nacl::assert_cast<WORD>(exploded.hour);
79 0 : st.wMinute = nacl::assert_cast<WORD>(exploded.minute);
80 0 : st.wSecond = nacl::assert_cast<WORD>(exploded.second);
81 0 : st.wMilliseconds = nacl::assert_cast<WORD>(exploded.millisecond);
82 :
83 : // Convert to FILETIME.
84 : FILETIME ft;
85 0 : if (!SystemTimeToFileTime(&st, &ft)) {
86 : // NOTREACHED() << "Unable to convert time";
87 0 : return Time(0);
88 : }
89 :
90 : // Ensure that it's in UTC.
91 0 : if (is_local) {
92 : FILETIME utc_ft;
93 0 : LocalFileTimeToFileTime(&ft, &utc_ft);
94 0 : return Time(FileTimeToMicroseconds(utc_ft));
95 : }
96 0 : return Time(FileTimeToMicroseconds(ft));
97 0 : }
98 :
99 0 : void NaCl::Time::Explode(bool is_local, Exploded* exploded) const {
100 : // FILETIME in UTC.
101 : FILETIME utc_ft;
102 0 : MicrosecondsToFileTime(us_, &utc_ft);
103 :
104 : // FILETIME in local time if necessary.
105 0 : BOOL success = TRUE;
106 : FILETIME ft;
107 0 : if (is_local)
108 0 : success = FileTimeToLocalFileTime(&utc_ft, &ft);
109 0 : else
110 0 : ft = utc_ft;
111 :
112 : // FILETIME in SYSTEMTIME (exploded).
113 : SYSTEMTIME st;
114 0 : if (!success || !FileTimeToSystemTime(&ft, &st)) {
115 : // NOTREACHED() << "Unable to convert time, don't know why";
116 0 : ZeroMemory(exploded, sizeof(*exploded));
117 0 : return;
118 : }
119 :
120 0 : exploded->year = st.wYear;
121 0 : exploded->month = st.wMonth;
122 0 : exploded->day_of_week = st.wDayOfWeek;
123 0 : exploded->day_of_month = st.wDay;
124 0 : exploded->hour = st.wHour;
125 0 : exploded->minute = st.wMinute;
126 0 : exploded->second = st.wSecond;
127 0 : exploded->millisecond = st.wMilliseconds;
128 0 : }
129 :
130 : // TimeTicks ------------------------------------------------------------------
131 : NaCl::TimeTicks::TickFunction NaCl::TimeTicks::tick_function_=
132 36 : reinterpret_cast<TickFunction>(&timeGetTime);
133 :
134 : // static
135 0 : NaCl::TimeTicks NaCl::TimeTicks::Now() {
136 : // Uses the multimedia timers on Windows to get a higher resolution clock.
137 : // timeGetTime() provides a resolution which is variable depending on
138 : // hardware and system configuration. It can also be changed by other
139 : // apps. This class does not attempt to change the resolution of the
140 : // timer, because we don't want to affect other applications.
141 :
142 : // timeGetTime() should at least be accurate to ~5ms on all systems.
143 : // timeGetTime() returns a 32-bit millisecond counter which has rollovers
144 : // every ~49 days.
145 : static DWORD last_tick_count = 0;
146 : static int64_t tick_rollover_accum = 0;
147 : static Lock* tick_lock = NULL; // To protect during rollover periods.
148 :
149 : // Lazily create the lock we use.
150 0 : if (!tick_lock) {
151 0 : Lock* new_lock = new Lock;
152 : if (InterlockedCompareExchangePointer(
153 0 : reinterpret_cast<PVOID*>(&tick_lock), new_lock, NULL)) {
154 0 : delete new_lock;
155 : }
156 : }
157 :
158 : // Atomically protect the low and high 32bit values for time.
159 : // In the future we may be able to optimize with
160 : // InterlockedCompareExchange64, but that doesn't work on XP.
161 : DWORD tick_count;
162 : int64_t rollover_count;
163 : /* lint complains about this, ignore */{
164 0 : AutoLock lock(*tick_lock);
165 0 : tick_count = tick_function_();
166 0 : if (tick_count < last_tick_count)
167 0 : tick_rollover_accum += GG_INT64_C(0x100000000);
168 :
169 0 : last_tick_count = tick_count;
170 0 : rollover_count = tick_rollover_accum;
171 0 : }
172 :
173 : // GetTickCount returns milliseconds, we want microseconds.
174 : return TimeTicks((tick_count + rollover_count) *
175 0 : Time::kMicrosecondsPerMillisecond);
176 0 : }
177 :
178 : // Overview of time counters:
179 : // (1) CPU cycle counter. (Retrieved via RDTSC)
180 : // The CPU counter provides the highest resolution time stamp and is the least
181 : // expensive to retrieve. However, the CPU counter is unreliable and should not
182 : // be used in production. Its biggest issue is that it is per processor and it
183 : // is not synchronized between processors. Also, on some computers, the counters
184 : // will change frequency due to thermal and power changes, and stop in some
185 : // states.
186 : //
187 : // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
188 : // resolution (100 nanoseconds) time stamp but is comparatively more expensive
189 : // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
190 : // (with some help from ACPI).
191 : // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
192 : // in the worst case, it gets the counter from the rollover interrupt on the
193 : // programmable interrupt timer. In best cases, the HAL may conclude that the
194 : // RDTSC counter runs at a constant frequency, then it uses that instead. On
195 : // multiprocessor machines, it will try to verify the values returned from
196 : // RDTSC on each processor are consistent with each other, and apply a handful
197 : // of workarounds for known buggy hardware. In other words, QPC is supposed to
198 : // give consistent result on a multiprocessor computer, but it is unreliable in
199 : // reality due to bugs in BIOS or HAL on some, especially old computers.
200 : // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
201 : // it should be used with caution.
202 : //
203 : // (3) System time. The system time provides a low-resolution (typically 10ms
204 : // to 55 milliseconds) time stamp but is comparatively less expensive to
205 : // retrieve and more reliable.
206 :
207 : // static
208 0 : NaCl::TimeTicks NaCl::TimeTicks::UnreliableHighResNow() {
209 : // Cached clock frequency -> microseconds. This assumes that the clock
210 : // frequency is faster than one microsecond (which is 1MHz, should be OK).
211 : static int64_t ticks_per_microsecond = 0;
212 :
213 0 : if (ticks_per_microsecond == 0) {
214 0 : LARGE_INTEGER ticks_per_sec = { 0, 0 };
215 0 : if (!QueryPerformanceFrequency(&ticks_per_sec))
216 0 : return TimeTicks(0); // Broken, we don't guarantee this function works.
217 : ticks_per_microsecond =
218 0 : ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond;
219 : }
220 :
221 : LARGE_INTEGER now;
222 0 : QueryPerformanceCounter(&now);
223 0 : return TimeTicks(now.QuadPart / ticks_per_microsecond);
224 0 : }
|