commit 6a927d435699
Author: Tom Ritter <tom@mozilla.com>
Date: Fri Jan 12 13:36:04 2018 -0600
Bug 1429764 - Do not call ReduceTimerPrecision twice for DOM Navigation timers. r=bkelly, r=timhuang, a=jcristau
Bug 1429764 details a test failure that was asserting that the performance navigation
timers were strictly increasing (or equal). fetchStart should have a timestamp before
domainLookupStart. But it didn't.
The problem is two-fold. This corrects the test and the issue by addressing one part
of the problem, the second part of the problem needs to be written up in a new bug
and addressed there. (That bug is not yet filed at writing, but see dependencies of
1429764 in the future to find it.)
The second, and underlying, problem is that calling ReduceTimerPrecision with the
same value multiple times may continually reduce it. Meaning that the first you call
it with, say, .75, (and a precision of .20), it will be reduced to .6. The second time
you call it (with .6), instead of staying at .6 it will be reduced to .4. This is
because floats are fuzzy. Inside ReduceTimerPrecision we are multiplying a decimal by
a decimal, so while floor(.6 / .20) should equal 3, sometimes it's actually 2.999...
which gets floors to 2, gets multiplied again by .2, and which results in .4
If that's the underlying problem, the first, and surface, problem is - why are we
calling ReduceTimerPrecision multiple times? We shouldn't be. That's what this
patch fixes.
TimeStampToDOMHighResOrFetchStart will return either TimeStampToDOMHighRes() or
FetchStartHighRes(). FetchStartHighRes() internally calls TimeStampToDOMHighRes
and then ReduceTimerPrecision - this is where (some of) the two reduction calls
happen - because TimeStampToDOMHighRes itself calls ReduceTimerPrecision also.
I remove the ReduceTimerPrecision from TimeStampToDOMHighRes. FetchStartHighRes
will now only call ReduceTimerPrecision once, at the end of the return.
But we have to fix places we call TimeStampToDOMHighResOrFetchStart, because the
callers of that function also call ReduceTimerPrecision. So if
TimeStampToDOMHighResOrFetchStart returned FetchStartHighRes, we'd be calling
ReduceTimerPrecision twice for those callers.
So inside first off, we remove the outer call to ReduceTimerPrecision. that
surrounds the 5 or so callsites of TimeStampToDOMHighResOrFetchStart. Then
inside of TimeStampToDOMHighResOrFetchStart we return either FetchStartHighRes
(which is has already called ReduceTimerPrecision) or we call
ReduceTimerPrecision with the value.
Now. TimeStampToDOMHighRes was used in more places than just FetchStartHighRes -
there were several other places where we were doing double rounding, and this
fixed those as well. AsyncOpenHighRes, WorkerStartHighRes, DomainLookupEndHighRes,
ConnectStartHighRes, SecureConnectionStartHighRes, ConnectEndHighRes, and
ResponseEndHighRes.
MozReview-Commit-ID: K5nHql135rb
--HG--
extra : source : 17bf5819b42fa3b656f2d3c565bc4fb0ca050066
---
dom/performance/PerformanceTiming.cpp | 15 +++------
dom/performance/PerformanceTiming.h | 7 ++--
.../resistfingerprinting/nsRFPService.cpp | 38 +++++++++++++++++++---
3 files changed, 42 insertions(+), 18 deletions(-)
diff --git dom/performance/PerformanceTiming.cpp dom/performance/PerformanceTiming.cpp
index 3d7e55a0c80f..f80d7f509a40 100644
--- dom/performance/PerformanceTiming.cpp
+++ dom/performance/PerformanceTiming.cpp
@@ -222,7 +222,7 @@ PerformanceTiming::RedirectStartHighRes()
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mRedirectStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mRedirectStart);
}
DOMTimeMilliSec
@@ -256,7 +256,7 @@ PerformanceTiming::RedirectEndHighRes()
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mRedirectEnd);
+ return TimeStampToReducedDOMHighResOrFetchStart(mRedirectEnd);
}
DOMTimeMilliSec
@@ -280,7 +280,7 @@ PerformanceTiming::DomainLookupStartHighRes()
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mDomainLookupStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mDomainLookupStart);
}
DOMTimeMilliSec
@@ -366,7 +366,7 @@ PerformanceTiming::RequestStartHighRes()
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mRequestStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mRequestStart);
}
DOMTimeMilliSec
@@ -386,7 +386,7 @@ PerformanceTiming::ResponseStartHighRes()
(!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) {
mResponseStart = mCacheReadStart;
}
- return TimeStampToDOMHighResOrFetchStart(mResponseStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mResponseStart);
}
DOMTimeMilliSec
diff --git dom/performance/PerformanceTiming.h dom/performance/PerformanceTiming.h
index 0558fc11d64e..9fba3210ef1d 100644
--- dom/performance/PerformanceTiming.h
+++ dom/performance/PerformanceTiming.h
@@ -68,10 +68,10 @@ public:
* page), if the given TimeStamp is valid. Otherwise, it will return
* the FetchStart timing value.
*/
- inline DOMHighResTimeStamp TimeStampToDOMHighResOrFetchStart(TimeStamp aStamp)
+ inline DOMHighResTimeStamp TimeStampToReducedDOMHighResOrFetchStart(TimeStamp aStamp)
{
return (!aStamp.IsNull())
- ? TimeStampToDOMHighRes(aStamp)
+ ? nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(aStamp))
: FetchStartHighRes();
}
diff --git toolkit/components/resistfingerprinting/nsRFPService.cpp toolkit/components/resistfingerprinting/nsRFPService.cpp
index 51552da69923..98857a764721 100644
--- toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -8,6 +8,7 @@
#include <time.h>
#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
@@ -28,6 +29,10 @@
using namespace mozilla;
+#ifdef DEBUG
+static mozilla::LazyLogModule gResistFingerprintingLog("nsResistFingerprinting");
+#endif
+
#define RESIST_FINGERPRINTING_PREF "privacy.resistFingerprinting"
#define PROFILE_INITIALIZED_TOPIC "profile-initial-state"
@@ -66,7 +71,13 @@ nsRFPService::ReduceTimePrecisionAsMSecs(double aTime)
return aTime;
}
const double resolutionMSec = kResolutionUSec / 1000.0;
- return floor(aTime / resolutionMSec) * resolutionMSec;
+ double ret = floor(aTime / resolutionMSec) * resolutionMSec;
+#if defined(DEBUG)
+ MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
+ ("Given: %.*f, Rounding with %.*f, Intermediate: %.*f, Got: %.*f",
+ DBL_DIG-1, aTime, DBL_DIG-1, resolutionMSec, DBL_DIG-1, floor(aTime / resolutionMSec), DBL_DIG-1, ret));
+#endif
+ return ret;
}
/* static */
@@ -76,7 +87,14 @@ nsRFPService::ReduceTimePrecisionAsUSecs(double aTime)
if (!IsResistFingerprintingEnabled()) {
return aTime;
}
- return floor(aTime / kResolutionUSec) * kResolutionUSec;
+ double ret = floor(aTime / kResolutionUSec) * kResolutionUSec;
+#if defined(DEBUG)
+ double tmp_kResolutionUSec = kResolutionUSec;
+ MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
+ ("Given: %.*f, Rounding with %.*f, Intermediate: %.*f, Got: %.*f",
+ DBL_DIG-1, aTime, DBL_DIG-1, tmp_kResolutionUSec, DBL_DIG-1, floor(aTime / tmp_kResolutionUSec), DBL_DIG-1, ret));
+#endif
+ return ret;
}
/* static */
@@ -90,10 +108,22 @@ nsRFPService::ReduceTimePrecisionAsSecs(double aTime)
// The resolution is smaller than one sec. Use the reciprocal to avoid
// floating point error.
const double resolutionSecReciprocal = 1000000.0 / kResolutionUSec;
- return floor(aTime * resolutionSecReciprocal) / resolutionSecReciprocal;
+ double ret = floor(aTime * resolutionSecReciprocal) / resolutionSecReciprocal;
+#if defined(DEBUG)
+ MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
+ ("Given: %.*f, Reciprocal Rounding with %.*f, Intermediate: %.*f, Got: %.*f",
+ DBL_DIG-1, aTime, DBL_DIG-1, resolutionSecReciprocal, DBL_DIG-1, floor(aTime * resolutionSecReciprocal), DBL_DIG-1, ret));
+#endif
+ return ret;
}
const double resolutionSec = kResolutionUSec / 1000000.0;
- return floor(aTime / resolutionSec) * resolutionSec;
+ double ret = floor(aTime / resolutionSec) * resolutionSec;
+#if defined(DEBUG)
+ MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
+ ("Given: %.*f, Rounding with %.*f, Intermediate: %.*f, Got: %.*f",
+ DBL_DIG-1, aTime, DBL_DIG-1, resolutionSec, DBL_DIG-1, floor(aTime / resolutionSec), DBL_DIG-1, ret));
+#endif
+ return ret;
}
nsresult