Auto merge of #25659 - pshaughn:timingresolution, r=jdm,nox

Expose DOMHighResTimeStamps at lower res

As explained in https://www.w3.org/TR/hr-time-2/#clock-resolution and tested in a few WPT tests, we're not supposed to show Javascript the full resolution of OS timestamps. This fixes that on all the DOMHighResTimeStamp interfaces that weren't already limiting themselves to integer milliseconds.

The specific choice of how to coarsen the resolution is extremely bikesheddable; I commented the reasoning for my arbitrary choice but I admit it's arbitrary.

A couple tests of timing resolution still fail, but because they're seeing undefined and NaN values due to unimplemented attributes (#25658).

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25656 fix #25296 fix #21276

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-02-10 13:50:42 -05:00 committed by GitHub
commit c0ee7594c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 46 additions and 51 deletions

View file

@ -10,7 +10,6 @@ use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeS
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceBinding::PerformanceMethods;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, DomSlice, MutNullableDom};
@ -19,6 +18,7 @@ use crate::dom::document::Document;
use crate::dom::eventtarget::{CompiledEventListener, EventTarget, ListenerPhase};
use crate::dom::globalscope::GlobalScope;
use crate::dom::node::Node;
use crate::dom::performance::reduce_timing_resolution;
use crate::dom::virtualmethods::vtable_for;
use crate::dom::window::Window;
use crate::task::TaskOnce;
@ -333,7 +333,7 @@ impl EventMethods for Event {
// https://dom.spec.whatwg.org/#dom-event-timestamp
fn TimeStamp(&self) -> DOMHighResTimeStamp {
Finite::wrap(
reduce_timing_resolution(
(self.precise_time_ns - (*self.global().performance().TimeOrigin()).round() as u64)
.to_ms(),
)

View file

@ -401,12 +401,12 @@ impl PerformanceMethods for Performance {
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now
fn Now(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.now())
reduce_timing_resolution(self.now())
}
// https://www.w3.org/TR/hr-time-2/#dom-performance-timeorigin
fn TimeOrigin(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.navigation_start_precise as f64)
reduce_timing_resolution(self.navigation_start_precise as f64)
}
// https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
@ -525,3 +525,14 @@ impl PerformanceMethods for Performance {
SetOnresourcetimingbufferfull
);
}
// https://www.w3.org/TR/hr-time-2/#clock-resolution
pub fn reduce_timing_resolution(exact: f64) -> DOMHighResTimeStamp {
// We need a granularity no finer than 5 microseconds.
// 5 microseconds isn't an exactly representable f64 so WPT tests
// might occasionally corner-case on rounding.
// web-platform-tests/wpt#21526 wants us to use an integer number of
// microseconds; the next divisor of milliseconds up from 5 microseconds
// is 10, which is 1/100th of a millisecond.
Finite::wrap((exact * 100.0).floor() / 100.0)
}

View file

@ -2,13 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
use crate::dom::bindings::codegen::Bindings::PerformanceEntryBinding;
use crate::dom::bindings::codegen::Bindings::PerformanceEntryBinding::PerformanceEntryMethods;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::performance::reduce_timing_resolution;
use dom_struct::dom_struct;
#[dom_struct]
@ -77,12 +78,12 @@ impl PerformanceEntryMethods for PerformanceEntry {
}
// https://w3c.github.io/performance-timeline/#dom-performanceentry-starttime
fn StartTime(&self) -> Finite<f64> {
Finite::wrap(self.start_time)
fn StartTime(&self) -> DOMHighResTimeStamp {
reduce_timing_resolution(self.start_time)
}
// https://w3c.github.io/performance-timeline/#dom-performanceentry-duration
fn Duration(&self) -> Finite<f64> {
Finite::wrap(self.duration)
fn Duration(&self) -> DOMHighResTimeStamp {
reduce_timing_resolution(self.duration)
}
}

View file

@ -6,11 +6,11 @@ use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeS
use crate::dom::bindings::codegen::Bindings::PerformanceResourceTimingBinding::{
self, PerformanceResourceTimingMethods,
};
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::performance::reduce_timing_resolution;
use crate::dom::performanceentry::PerformanceEntry;
use dom_struct::dom_struct;
use net_traits::ResourceFetchTiming;
@ -182,17 +182,17 @@ impl PerformanceResourceTimingMethods for PerformanceResourceTiming {
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-domainlookupstart
fn DomainLookupStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.domain_lookup_start)
reduce_timing_resolution(self.domain_lookup_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-domainlookupend
fn DomainLookupEnd(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.domain_lookup_end)
reduce_timing_resolution(self.domain_lookup_end)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-secureconnectionstart
fn SecureConnectionStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.secure_connection_start)
reduce_timing_resolution(self.secure_connection_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-transfersize
@ -212,41 +212,41 @@ impl PerformanceResourceTimingMethods for PerformanceResourceTiming {
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-requeststart
fn RequestStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.request_start)
reduce_timing_resolution(self.request_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-redirectstart
fn RedirectStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.redirect_start)
reduce_timing_resolution(self.redirect_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-redirectend
fn RedirectEnd(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.redirect_end)
reduce_timing_resolution(self.redirect_end)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responsestart
fn ResponseStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.response_start)
reduce_timing_resolution(self.response_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-fetchstart
fn FetchStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.fetch_start)
reduce_timing_resolution(self.fetch_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-connectstart
fn ConnectStart(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.connect_start)
reduce_timing_resolution(self.connect_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-connectend
fn ConnectEnd(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.connect_end)
reduce_timing_resolution(self.connect_end)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responseend
fn ResponseEnd(&self) -> DOMHighResTimeStamp {
Finite::wrap(self.response_end)
reduce_timing_resolution(self.response_end)
}
}

View file

@ -2,13 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
use crate::dom::bindings::codegen::Bindings::VRFrameDataBinding;
use crate::dom::bindings::codegen::Bindings::VRFrameDataBinding::VRFrameDataMethods;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::performance::reduce_timing_resolution;
use crate::dom::vrpose::VRPose;
use crate::dom::window::Window;
use crate::script_runtime::JSContext;
@ -119,8 +120,8 @@ impl VRFrameData {
impl VRFrameDataMethods for VRFrameData {
// https://w3c.github.io/webvr/#dom-vrframedata-timestamp
fn Timestamp(&self) -> Finite<f64> {
Finite::wrap(self.timestamp.get() - self.first_timestamp.get())
fn Timestamp(&self) -> DOMHighResTimeStamp {
reduce_timing_resolution(self.timestamp.get() - self.first_timestamp.get())
}
#[allow(unsafe_code)]

View file

@ -19,7 +19,6 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRVisibilityState
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods;
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
@ -28,6 +27,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::node::Node;
use crate::dom::node::NodeDamage;
use crate::dom::performance::reduce_timing_resolution;
use crate::dom::promise::Promise;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrinputsourcearray::XRInputSourceArray;
@ -336,7 +336,7 @@ impl XRSession {
// Step 4-5
let mut callbacks = mem::replace(&mut *self.raf_callback_list.borrow_mut(), vec![]);
let start = self.global().as_window().get_navigation_start();
let time = (frame.time_ns - start).to_ms();
let time = reduce_timing_resolution((frame.time_ns - start).to_ms());
let frame = XRFrame::new(&self.global(), self, frame);
// Step 6,7
@ -347,7 +347,7 @@ impl XRSession {
self.outside_raf.set(false);
for (_, callback) in callbacks.drain(..) {
if let Some(callback) = callback {
let _ = callback.Call__(Finite::wrap(time), &frame, ExceptionHandling::Report);
let _ = callback.Call__(time, &frame, ExceptionHandling::Report);
}
}
self.outside_raf.set(true);

View file

@ -1,6 +0,0 @@
[Event-timestamp-safe-resolution.html]
type: testharness
[Event timestamp should not have a resolution better than 5 microseconds]
expected: FAIL

View file

@ -1,15 +0,0 @@
[webtiming-resolution.any.html]
[Verifies the resolution of performance.now() is at least 5 microseconds.]
expected: FAIL
[webtiming-resolution.any.worker.html]
[Verifies the resolution of performance.now() is at least 20 microseconds.]
expected: FAIL
[Verifies the resolution of entry.startTime is at least 20 microseconds.]
expected: TIMEOUT
[Verifies the resolution of performance.now() is at least 5 microseconds.]
expected: FAIL

View file

@ -19708,7 +19708,7 @@
"testharness"
],
"mozilla/window_performance.html": [
"302073e8041763102d678326509d7ef0a1fb5c79",
"c1e38a1e00147caf82492dc82f1cb5e85759f8e3",
"testharness"
],
"mozilla/window_performance_topLevelDomComplete.html": [

View file

@ -27,12 +27,15 @@ test(function() {
var last = window.performance.now();
assert_greater_than(last, 0);
// Check that window.performance.now() is monotonically increasing
// Check that window.performance.now() is monotonically nondecreasing
// and eventually increases
var before_loop = window.performance.now();
for (var i = 0; i < 100; i++) {
var next = window.performance.now();
assert_greater_than(next, last);
assert_greater_than_equal(next, last);
last = next;
}
assert_greater_than(last, before_loop, "If this fails, either performance timing is broken, or Servo JS execution has gotten much faster since this test was written.");
});
</script>
</body>