Chromium Code Reviews| 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 | |
| 9 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
| 10 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 12 | 14 |
| 13 using base::Time; | 15 using base::Time; |
| 14 using base::TimeDelta; | 16 using base::TimeDelta; |
| 15 using base::TimeTicks; | 17 using base::TimeTicks; |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 CloseHandle(g_rollover_test_start); | 109 CloseHandle(g_rollover_test_start); |
| 108 | 110 |
| 109 // Teardown | 111 // Teardown |
| 110 MockTimeTicks::UninstallTicker(); | 112 MockTimeTicks::UninstallTicker(); |
| 111 } | 113 } |
| 112 } | 114 } |
| 113 | 115 |
| 114 TEST(TimeTicks, SubMillisecondTimers) { | 116 TEST(TimeTicks, SubMillisecondTimers) { |
| 115 // HighResNow doesn't work on some systems. Since the product still works | 117 // 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. | 118 // even if it doesn't work, it makes this entire test questionable. |
| 117 if (!TimeTicks::IsHighResClockWorking()) | 119 if (!TimeTicks::IsHighResolution()) |
| 118 return; | 120 return; |
| 119 | 121 |
| 120 const int kRetries = 1000; | 122 const int kRetries = 1000; |
| 121 bool saw_submillisecond_timer = false; | 123 bool saw_submillisecond_timer = false; |
| 122 | 124 |
| 123 // Run kRetries attempts to see a sub-millisecond timer. | 125 // Run kRetries attempts to see a sub-millisecond timer. |
| 124 for (int index = 0; index < kRetries; index++) { | 126 for (int index = 0; index < kRetries; index++) { |
| 125 TimeTicks last_time = TimeTicks::HighResNow(); | 127 TimeTicks last_time = TimeTicks::HighResNow(); |
| 126 TimeDelta delta; | 128 TimeDelta delta; |
| 127 // Spin until the clock has detected a change. | 129 // Spin until the clock has detected a change. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 176 TestFunc func; | 178 TestFunc func; |
| 177 const char *description; | 179 const char *description; |
| 178 }; | 180 }; |
| 179 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) | 181 // Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time) |
| 180 // in order to create a single test case list. | 182 // in order to create a single test case list. |
| 181 COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time), | 183 COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time), |
| 182 test_only_works_with_same_sizes); | 184 test_only_works_with_same_sizes); |
| 183 TestCase cases[] = { | 185 TestCase cases[] = { |
| 184 { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" }, | 186 { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" }, |
| 185 { TimeTicks::Now, "TimeTicks::Now" }, | 187 { TimeTicks::Now, "TimeTicks::Now" }, |
| 186 { TimeTicks::HighResNow, "TimeTicks::HighResNow" }, | 188 { TimeTicks::NowFromSystemTraceTime, "TimeTicks::NowFromSystemTraceTime" }, |
| 187 { NULL, "" } | 189 { NULL, "" } |
| 188 }; | 190 }; |
| 189 | 191 |
| 190 int test_case = 0; | 192 int test_case = 0; |
| 191 while (cases[test_case].func) { | 193 while (cases[test_case].func) { |
| 192 TimeTicks start = TimeTicks::HighResNow(); | 194 TimeTicks start = TimeTicks::HighResNow(); |
| 193 for (int index = 0; index < kLoops; index++) | 195 for (int index = 0; index < kLoops; index++) |
| 194 cases[test_case].func(); | 196 cases[test_case].func(); |
| 195 TimeTicks stop = TimeTicks::HighResNow(); | 197 TimeTicks stop = TimeTicks::HighResNow(); |
| 196 // Turning off the check for acceptible delays. Without this check, | 198 // Turning off the check for acceptible delays. Without this check, |
| 197 // the test really doesn't do much other than measure. But the | 199 // the test really doesn't do much other than measure. But the |
| 198 // measurements are still useful for testing timers on various platforms. | 200 // measurements are still useful for testing timers on various platforms. |
| 199 // The reason to remove the check is because the tests run on many | 201 // 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 | 202 // 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. | 203 // slow, and there is really no value for checking against a max timer. |
| 202 //const int kMaxTime = 35; // Maximum acceptible milliseconds for test. | 204 //const int kMaxTime = 35; // Maximum acceptible milliseconds for test. |
| 203 //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); | 205 //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime); |
| 204 printf("%s: %1.2fus per call\n", cases[test_case].description, | 206 printf("%s: %1.2fus per call\n", cases[test_case].description, |
| 205 (stop - start).InMillisecondsF() * 1000 / kLoops); | 207 (stop - start).InMillisecondsF() * 1000 / kLoops); |
| 206 test_case++; | 208 test_case++; |
| 207 } | 209 } |
| 208 } | 210 } |
| 209 | 211 |
| 210 // http://crbug.com/396384 | 212 TEST(TimeTicks, FromQPCValue) { |
| 211 TEST(TimeTicks, DISABLED_Drift) { | 213 if (!TimeTicks::IsHighResolution()) |
| 212 // If QPC is disabled, this isn't measuring anything. | |
| 213 if (!TimeTicks::IsHighResClockWorking()) | |
| 214 return; | 214 return; |
| 215 | 215 |
| 216 const int kIterations = 100; | 216 const int kIterations = 100; |
| 217 int64 total_drift = 0; | 217 |
| 218 LARGE_INTEGER frequency; | |
| 219 ASSERT_TRUE(QueryPerformanceFrequency(&frequency)); | |
| 220 const int64 ticks_per_second = frequency.QuadPart; | |
| 221 ASSERT_GT(ticks_per_second, 0); | |
| 222 | |
| 223 // Tolerance between the TimeTicks values computed by this test versus those | |
| 224 // computed using FromQCPValue(). On most systems, this will be 1us. | |
| 225 // However, when the QPC frequency is less than 1 MHz, the tolerance needs to | |
| 226 // be greater. | |
| 227 const int64 tolerance_us = static_cast<int64>( | |
| 228 std::ceil((1.0 / ticks_per_second) * Time::kMicrosecondsPerSecond)); | |
| 229 | |
| 230 int64 ticks_increment = 10; // Changes with each loop iteration. | |
| 231 LARGE_INTEGER start_ticks; | |
| 232 // The start value is chosen such that part of the test will make | |
| 233 // FromQPCValue() use the faster conversion logic, and part will make it use | |
| 234 // the overflow-safe logic. | |
| 235 start_ticks.QuadPart = | |
| 236 Time::kQPCOverflowThreshold - (ticks_increment * kIterations / 2); | |
| 237 LARGE_INTEGER ticks = start_ticks; | |
| 238 TimeTicks start_time = TimeTicks() + TimeDelta::FromMicroseconds( | |
| 239 start_ticks.QuadPart * Time::kMicrosecondsPerSecond / ticks_per_second); | |
| 218 | 240 |
| 219 for (int i = 0; i < kIterations; ++i) { | 241 for (int i = 0; i < kIterations; ++i) { |
|
brianderson
2015/01/09 00:02:02
I don't think this for loop tests the 3 corner cas
miu
2015/01/14 02:12:24
Done.
| |
| 220 int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds(); | 242 ticks.QuadPart += ticks_increment; |
| 243 ticks_increment = ticks_increment * 6 / 5; | |
| 221 | 244 |
| 222 // Make sure the drift never exceeds our limit. | 245 const int64 ticks_advanced = ticks.QuadPart - start_ticks.QuadPart; |
| 223 EXPECT_LT(drift_microseconds, 50000); | 246 const TimeTicks expected_value = start_time + |
|
brianderson
2015/01/09 00:02:02
This test rounds to microseconds twice (here and i
miu
2015/01/14 02:12:24
I looked into 128-bit integers, but didn't like wh
brianderson
2015/01/14 02:31:42
Thanks for looking into that. It would have been n
| |
| 224 | 247 TimeDelta::FromMicroseconds( |
| 225 // Sleep for a few milliseconds (note that it means 1000 microseconds). | 248 ticks_advanced * Time::kMicrosecondsPerSecond / ticks_per_second); |
| 226 // If we check the drift too frequently, it's going to increase | 249 const TimeTicks value = TimeTicks::FromQPCValue(ticks.QuadPart); |
| 227 // monotonically, making our measurement less realistic. | 250 EXPECT_GE(tolerance_us, |
| 228 base::PlatformThread::Sleep( | 251 (value - expected_value).magnitude().InMicroseconds()) |
| 229 base::TimeDelta::FromMilliseconds((i % 2 == 0) ? 1 : 2)); | 252 << "iteration: " << i << ", logic path: " |
| 230 | 253 << (ticks.QuadPart < Time::kQPCOverflowThreshold ? "FAST" : "SAFE"); |
| 231 total_drift += drift_microseconds; | |
| 232 } | 254 } |
| 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 } | 255 } |
| 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 |