OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <windows.h> | 5 #include <windows.h> |
6 #include <mmsystem.h> | 6 #include <mmsystem.h> |
7 #include <process.h> | 7 #include <process.h> |
8 | 8 |
| 9 #include <cmath> |
| 10 #include <limits> |
| 11 #include <vector> |
| 12 |
9 #include "base/threading/platform_thread.h" | 13 #include "base/threading/platform_thread.h" |
10 #include "base/time/time.h" | 14 #include "base/time/time.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
12 | 16 |
13 using base::Time; | 17 using base::Time; |
14 using base::TimeDelta; | 18 using base::TimeDelta; |
15 using base::TimeTicks; | 19 using base::TimeTicks; |
16 | 20 |
17 namespace { | 21 namespace { |
18 | 22 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 CloseHandle(g_rollover_test_start); | 111 CloseHandle(g_rollover_test_start); |
108 | 112 |
109 // Teardown | 113 // Teardown |
110 MockTimeTicks::UninstallTicker(); | 114 MockTimeTicks::UninstallTicker(); |
111 } | 115 } |
112 } | 116 } |
113 | 117 |
114 TEST(TimeTicks, SubMillisecondTimers) { | 118 TEST(TimeTicks, SubMillisecondTimers) { |
115 // HighResNow doesn't work on some systems. Since the product still works | 119 // HighResNow doesn't work on some systems. Since the product still works |
116 // even if it doesn't work, it makes this entire test questionable. | 120 // even if it doesn't work, it makes this entire test questionable. |
117 if (!TimeTicks::IsHighResClockWorking()) | 121 if (!TimeTicks::IsHighResolution()) |
118 return; | 122 return; |
119 | 123 |
120 const int kRetries = 1000; | 124 const int kRetries = 1000; |
121 bool saw_submillisecond_timer = false; | 125 bool saw_submillisecond_timer = false; |
122 | 126 |
123 // Run kRetries attempts to see a sub-millisecond timer. | 127 // Run kRetries attempts to see a sub-millisecond timer. |
124 for (int index = 0; index < kRetries; index++) { | 128 for (int index = 0; index < kRetries; index++) { |
125 TimeTicks last_time = TimeTicks::HighResNow(); | 129 TimeTicks last_time = TimeTicks::HighResNow(); |
126 TimeDelta delta; | 130 TimeDelta delta; |
127 // Spin until the clock has detected a change. | 131 // Spin until the clock has detected a change. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 TestFunc func; | 180 TestFunc func; |
177 const char *description; | 181 const char *description; |
178 }; | 182 }; |
179 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) | 183 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) |
180 // in order to create a single test case list. | 184 // in order to create a single test case list. |
181 COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time), | 185 COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time), |
182 test_only_works_with_same_sizes); | 186 test_only_works_with_same_sizes); |
183 TestCase cases[] = { | 187 TestCase cases[] = { |
184 { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" }, | 188 { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" }, |
185 { TimeTicks::Now, "TimeTicks::Now" }, | 189 { TimeTicks::Now, "TimeTicks::Now" }, |
186 { TimeTicks::HighResNow, "TimeTicks::HighResNow" }, | 190 { TimeTicks::NowFromSystemTraceTime, "TimeTicks::NowFromSystemTraceTime" }, |
187 { NULL, "" } | 191 { NULL, "" } |
188 }; | 192 }; |
189 | 193 |
190 int test_case = 0; | 194 int test_case = 0; |
191 while (cases[test_case].func) { | 195 while (cases[test_case].func) { |
192 TimeTicks start = TimeTicks::HighResNow(); | 196 TimeTicks start = TimeTicks::HighResNow(); |
193 for (int index = 0; index < kLoops; index++) | 197 for (int index = 0; index < kLoops; index++) |
194 cases[test_case].func(); | 198 cases[test_case].func(); |
195 TimeTicks stop = TimeTicks::HighResNow(); | 199 TimeTicks stop = TimeTicks::HighResNow(); |
196 // Turning off the check for acceptible delays. Without this check, | 200 // Turning off the check for acceptible delays. Without this check, |
197 // the test really doesn't do much other than measure. But the | 201 // the test really doesn't do much other than measure. But the |
198 // measurements are still useful for testing timers on various platforms. | 202 // measurements are still useful for testing timers on various platforms. |
199 // The reason to remove the check is because the tests run on many | 203 // The reason to remove the check is because the tests run on many |
200 // buildbots, some of which are VMs. These machines can run horribly | 204 // buildbots, some of which are VMs. These machines can run horribly |
201 // slow, and there is really no value for checking against a max timer. | 205 // slow, and there is really no value for checking against a max timer. |
202 //const int kMaxTime = 35; // Maximum acceptible milliseconds for test. | 206 //const int kMaxTime = 35; // Maximum acceptible milliseconds for test. |
203 //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); | 207 //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); |
204 printf("%s: %1.2fus per call\n", cases[test_case].description, | 208 printf("%s: %1.2fus per call\n", cases[test_case].description, |
205 (stop - start).InMillisecondsF() * 1000 / kLoops); | 209 (stop - start).InMillisecondsF() * 1000 / kLoops); |
206 test_case++; | 210 test_case++; |
207 } | 211 } |
208 } | 212 } |
209 | 213 |
210 // http://crbug.com/396384 | 214 TEST(TimeTicks, FromQPCValue) { |
211 TEST(TimeTicks, DISABLED_Drift) { | 215 if (!TimeTicks::IsHighResolution()) |
212 // If QPC is disabled, this isn't measuring anything. | |
213 if (!TimeTicks::IsHighResClockWorking()) | |
214 return; | 216 return; |
215 | 217 |
216 const int kIterations = 100; | 218 LARGE_INTEGER frequency; |
217 int64 total_drift = 0; | 219 ASSERT_TRUE(QueryPerformanceFrequency(&frequency)); |
| 220 const int64 ticks_per_second = frequency.QuadPart; |
| 221 ASSERT_GT(ticks_per_second, 0); |
218 | 222 |
219 for (int i = 0; i < kIterations; ++i) { | 223 // Generate the tick values to convert, advancing the tick count by varying |
220 int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds(); | 224 // amounts. These values will ensure that both the fast and overflow-safe |
| 225 // conversion logic in FromQPCValue() is tested, and across the entire range |
| 226 // of possible QPC tick values. |
| 227 std::vector<int64> test_cases; |
| 228 test_cases.push_back(0); |
| 229 const int kNumAdvancements = 100; |
| 230 int64 ticks = 0; |
| 231 int64 ticks_increment = 10; |
| 232 for (int i = 0; i < kNumAdvancements; ++i) { |
| 233 test_cases.push_back(ticks); |
| 234 ticks += ticks_increment; |
| 235 ticks_increment = ticks_increment * 6 / 5; |
| 236 } |
| 237 test_cases.push_back(Time::kQPCOverflowThreshold - 1); |
| 238 test_cases.push_back(Time::kQPCOverflowThreshold); |
| 239 test_cases.push_back(Time::kQPCOverflowThreshold + 1); |
| 240 ticks = Time::kQPCOverflowThreshold + 10; |
| 241 ticks_increment = 10; |
| 242 for (int i = 0; i < kNumAdvancements; ++i) { |
| 243 test_cases.push_back(ticks); |
| 244 ticks += ticks_increment; |
| 245 ticks_increment = ticks_increment * 6 / 5; |
| 246 } |
| 247 test_cases.push_back(std::numeric_limits<int64>::max()); |
221 | 248 |
222 // Make sure the drift never exceeds our limit. | 249 // Test that the conversions using FromQPCValue() match those computed here |
223 EXPECT_LT(drift_microseconds, 50000); | 250 // using simple floating-point arithmetic. The floating-point math provides |
224 | 251 // enough precision to confirm the implementation is correct to the |
225 // Sleep for a few milliseconds (note that it means 1000 microseconds). | 252 // microsecond for all |test_cases| (though it would be insufficient to |
226 // If we check the drift too frequently, it's going to increase | 253 // confirm many "very large" tick values which are not being tested here). |
227 // monotonically, making our measurement less realistic. | 254 for (int64 ticks : test_cases) { |
228 base::PlatformThread::Sleep( | 255 const double expected_microseconds_since_origin = |
229 base::TimeDelta::FromMilliseconds((i % 2 == 0) ? 1 : 2)); | 256 (static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) / |
230 | 257 ticks_per_second; |
231 total_drift += drift_microseconds; | 258 const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks); |
| 259 const double converted_microseconds_since_origin = |
| 260 static_cast<double>((converted_value - TimeTicks()).InMicroseconds()); |
| 261 EXPECT_NEAR(expected_microseconds_since_origin, |
| 262 converted_microseconds_since_origin, |
| 263 1.0) |
| 264 << "ticks=" << ticks << ", to be converted via logic path: " |
| 265 << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE"); |
232 } | 266 } |
233 | |
234 // Sanity check. We expect some time drift to occur, especially across | |
235 // the number of iterations we do. | |
236 EXPECT_LT(0, total_drift); | |
237 | |
238 printf("average time drift in microseconds: %lld\n", | |
239 total_drift / kIterations); | |
240 } | 267 } |
241 | |
242 int64 QPCValueToMicrosecondsSafely(LONGLONG qpc_value, | |
243 int64 ticks_per_second) { | |
244 int64 whole_seconds = qpc_value / ticks_per_second; | |
245 int64 leftover_ticks = qpc_value % ticks_per_second; | |
246 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + | |
247 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | |
248 ticks_per_second); | |
249 return microseconds; | |
250 } | |
251 | |
252 TEST(TimeTicks, FromQPCValue) { | |
253 if (!TimeTicks::IsHighResClockWorking()) | |
254 return; | |
255 LARGE_INTEGER frequency; | |
256 QueryPerformanceFrequency(&frequency); | |
257 int64 ticks_per_second = frequency.QuadPart; | |
258 LONGLONG qpc_value = Time::kQPCOverflowThreshold; | |
259 TimeTicks expected_value = TimeTicks::FromInternalValue( | |
260 QPCValueToMicrosecondsSafely(qpc_value + 1, ticks_per_second)); | |
261 EXPECT_EQ(expected_value, | |
262 TimeTicks::FromQPCValue(qpc_value + 1)); | |
263 expected_value = TimeTicks::FromInternalValue( | |
264 QPCValueToMicrosecondsSafely(qpc_value, ticks_per_second)); | |
265 EXPECT_EQ(expected_value, | |
266 TimeTicks::FromQPCValue(qpc_value)); | |
267 expected_value = TimeTicks::FromInternalValue( | |
268 QPCValueToMicrosecondsSafely(qpc_value - 1, ticks_per_second)); | |
269 EXPECT_EQ(expected_value, | |
270 TimeTicks::FromQPCValue(qpc_value - 1)); | |
271 } | |
OLD | NEW |