Commit 3687b2f8 authored by fmeawad@chromium.org's avatar fmeawad@chromium.org

Make QPCValueToMicroseconds faster in case the value is less than 44 bits

If the QPC value is less than 44 bits, it is safe to multiply by a 20 bits
value (1000000) without risking overflow. This optimization reduces the
call time by half.

BUG=158234

Review URL: https://codereview.chromium.org/429743002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287704 0039d316-1c4b-4281-b951-d872f2087c98
parent b55d82b9
...@@ -230,6 +230,11 @@ class BASE_EXPORT Time { ...@@ -230,6 +230,11 @@ class BASE_EXPORT Time {
// this global header and put in the platform-specific ones when we remove the // this global header and put in the platform-specific ones when we remove the
// migration code. // migration code.
static const int64 kWindowsEpochDeltaMicroseconds; static const int64 kWindowsEpochDeltaMicroseconds;
#else
// To avoid overflow in QPC to Microseconds calculations, since we multiply
// by kMicrosecondsPerSecond, then the QPC value should not exceed
// (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
static const int64 kQPCOverflowThreshold = 0x8637BD05AF7;
#endif #endif
// Represents an exploded time that can be formatted nicely. This is kind of // Represents an exploded time that can be formatted nicely. This is kind of
......
...@@ -393,11 +393,14 @@ class HighResNowSingleton { ...@@ -393,11 +393,14 @@ class HighResNowSingleton {
int64 QPCValueToMicroseconds(LONGLONG qpc_value) { int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
if (!ticks_per_second_) if (!ticks_per_second_)
return 0; return 0;
// If the QPC Value is below the overflow threshold, we proceed with
// Intentionally calculate microseconds in a round about manner to avoid // simple multiply and divide.
// overflow and precision issues. Think twice before simplifying! if (qpc_value < Time::kQPCOverflowThreshold)
return qpc_value * Time::kMicrosecondsPerSecond / ticks_per_second_;
// Otherwise, calculate microseconds in a round about manner to avoid
// overflow and precision issues.
int64 whole_seconds = qpc_value / ticks_per_second_; int64 whole_seconds = qpc_value / ticks_per_second_;
int64 leftover_ticks = qpc_value % ticks_per_second_; int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_);
int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
((leftover_ticks * Time::kMicrosecondsPerSecond) / ((leftover_ticks * Time::kMicrosecondsPerSecond) /
ticks_per_second_); ticks_per_second_);
...@@ -447,7 +450,8 @@ NowFunction now_function = RolloverProtectedNow; ...@@ -447,7 +450,8 @@ NowFunction now_function = RolloverProtectedNow;
bool CPUReliablySupportsHighResTime() { bool CPUReliablySupportsHighResTime() {
base::CPU cpu; base::CPU cpu;
if (!cpu.has_non_stop_time_stamp_counter()) if (!cpu.has_non_stop_time_stamp_counter() ||
!GetHighResNowSingleton()->IsUsingHighResClock())
return false; return false;
if (IsBuggyAthlon(cpu)) if (IsBuggyAthlon(cpu))
......
...@@ -241,3 +241,34 @@ TEST(TimeTicks, DISABLED_Drift) { ...@@ -241,3 +241,34 @@ TEST(TimeTicks, DISABLED_Drift) {
printf("average time drift in microseconds: %lld\n", printf("average time drift in microseconds: %lld\n",
total_drift / kIterations); total_drift / kIterations);
} }
int64 QPCValueToMicrosecondsSafely(LONGLONG qpc_value,
int64 ticks_per_second) {
int64 whole_seconds = qpc_value / ticks_per_second;
int64 leftover_ticks = qpc_value % ticks_per_second;
int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
((leftover_ticks * Time::kMicrosecondsPerSecond) /
ticks_per_second);
return microseconds;
}
TEST(TimeTicks, FromQPCValue) {
if (!TimeTicks::IsHighResClockWorking())
return;
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
int64 ticks_per_second = frequency.QuadPart;
LONGLONG qpc_value = Time::kQPCOverflowThreshold;
TimeTicks expected_value = TimeTicks::FromInternalValue(
QPCValueToMicrosecondsSafely(qpc_value + 1, ticks_per_second));
EXPECT_EQ(expected_value,
TimeTicks::FromQPCValue(qpc_value + 1));
expected_value = TimeTicks::FromInternalValue(
QPCValueToMicrosecondsSafely(qpc_value, ticks_per_second));
EXPECT_EQ(expected_value,
TimeTicks::FromQPCValue(qpc_value));
expected_value = TimeTicks::FromInternalValue(
QPCValueToMicrosecondsSafely(qpc_value - 1, ticks_per_second));
EXPECT_EQ(expected_value,
TimeTicks::FromQPCValue(qpc_value - 1));
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment