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 {
// this global header and put in the platform-specific ones when we remove the
// migration code.
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
// Represents an exploded time that can be formatted nicely. This is kind of
......
......@@ -393,11 +393,14 @@ class HighResNowSingleton {
int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
if (!ticks_per_second_)
return 0;
// Intentionally calculate microseconds in a round about manner to avoid
// overflow and precision issues. Think twice before simplifying!
// If the QPC Value is below the overflow threshold, we proceed with
// simple multiply and divide.
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 leftover_ticks = qpc_value % ticks_per_second_;
int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_);
int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
((leftover_ticks * Time::kMicrosecondsPerSecond) /
ticks_per_second_);
......@@ -447,7 +450,8 @@ NowFunction now_function = RolloverProtectedNow;
bool CPUReliablySupportsHighResTime() {
base::CPU cpu;
if (!cpu.has_non_stop_time_stamp_counter())
if (!cpu.has_non_stop_time_stamp_counter() ||
!GetHighResNowSingleton()->IsUsingHighResClock())
return false;
if (IsBuggyAthlon(cpu))
......
......@@ -241,3 +241,34 @@ TEST(TimeTicks, DISABLED_Drift) {
printf("average time drift in microseconds: %lld\n",
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