Skip to content

Commit

Permalink
Auto merge of #18283 - ferjm:user.timing.api, r=jdm
Browse files Browse the repository at this point in the history
User Timing API

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #18109
- [X] There are tests for these changes. I enabled the peformance-timeline API WPTs but some of them are still failing because of implementation bugs or missing APIs (Resource Timing, for instance) the tests are dependent of. I'll file issues to fix them.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18283)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Aug 29, 2017
2 parents 4804e21 + 8cbd47e commit a91250e
Show file tree
Hide file tree
Showing 18 changed files with 281 additions and 10 deletions.
39 changes: 39 additions & 0 deletions components/script/dom/macros.rs
Expand Up @@ -572,3 +572,42 @@ macro_rules! rooted_vec {
let mut $name = $crate::dom::bindings::trace::RootedVec::from_iter(&mut root, $iter);
}
}

/// DOM struct implementation for simple interfaces inheriting from PerformanceEntry.
macro_rules! impl_performance_entry_struct(
($binding:ident, $struct:ident, $type:expr) => (
use dom::bindings::codegen::Bindings::$binding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::globalscope::GlobalScope;
use dom::performanceentry::PerformanceEntry;
use dom_struct::dom_struct;

#[dom_struct]
pub struct $struct {
entry: PerformanceEntry,
}

impl $struct {
fn new_inherited(name: DOMString, start_time: f64, duration: f64)
-> $struct {
$struct {
entry: PerformanceEntry::new_inherited(name,
DOMString::from($type),
start_time,
duration)
}
}

#[allow(unrooted_must_root)]
pub fn new(global: &GlobalScope,
name: DOMString,
start_time: f64,
duration: f64) -> Root<$struct> {
let entry = $struct::new_inherited(name, start_time, duration);
reflect_dom_object(box entry, global, $binding::Wrap)
}
}
);
);
2 changes: 2 additions & 0 deletions components/script/dom/mod.rs
Expand Up @@ -399,6 +399,8 @@ pub mod paintsize;
pub mod paintworkletglobalscope;
pub mod performance;
pub mod performanceentry;
pub mod performancemark;
pub mod performancemeasure;
pub mod performanceobserver;
pub mod performanceobserverentrylist;
pub mod performancepainttiming;
Expand Down
131 changes: 123 additions & 8 deletions components/script/dom/performance.rs
Expand Up @@ -6,12 +6,16 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PerformanceBinding;
use dom::bindings::codegen::Bindings::PerformanceBinding::{DOMHighResTimeStamp, PerformanceMethods};
use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceEntryList as DOMPerformanceEntryList;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::num::Finite;
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::performanceentry::PerformanceEntry;
use dom::performancemark::PerformanceMark;
use dom::performancemeasure::PerformanceMeasure;
use dom::performanceobserver::PerformanceObserver as DOMPerformanceObserver;
use dom::performancetiming::PerformanceTiming;
use dom::window::Window;
Expand All @@ -21,6 +25,30 @@ use std::cell::Cell;
use std::cmp::Ordering;
use time;

const INVALID_ENTRY_NAMES: &'static [&'static str] = &[
"navigationStart",
"unloadEventStart",
"unloadEventEnd",
"redirectStart",
"redirectEnd",
"fetchStart",
"domainLookupStart",
"domainLookupEnd",
"connectStart",
"connectEnd",
"secureConnectionStart",
"requestStart",
"responseStart",
"responseEnd",
"domLoading",
"domInteractive",
"domContentLoadedEventStart",
"domContentLoadedEventEnd",
"domComplete",
"loadEventStart",
"loadEventEnd",
];

/// Implementation of a list of PerformanceEntry items shared by the
/// Performance and PerformanceObserverEntryList interfaces implementations.
#[derive(HeapSizeOf, JSTraceable)]
Expand All @@ -44,6 +72,25 @@ impl PerformanceEntryList {
res.sort_by(|a, b| a.start_time().partial_cmp(&b.start_time()).unwrap_or(Ordering::Equal));
res
}

pub fn clear_entries_by_name_and_type(&mut self, name: Option<DOMString>,
entry_type: Option<DOMString>) {
self.entries.retain(|e|
name.as_ref().map_or(true, |name_| *e.name() == *name_) &&
entry_type.as_ref().map_or(true, |type_| *e.entry_type() == *type_)
);
}

fn get_last_entry_start_time_with_name_and_type(&self, name: DOMString,
entry_type: DOMString) -> f64 {
match self.entries.iter()
.rev()
.position(|e| *e.entry_type() == *entry_type &&
*e.name() == *name) {
Some(pos) => self.entries[pos].start_time(),
None => 0.,
}
}
}

impl IntoIterator for PerformanceEntryList {
Expand Down Expand Up @@ -77,8 +124,8 @@ impl Performance {
Performance {
reflector_: Reflector::new(),
timing: JS::from_ref(&*PerformanceTiming::new(window,
navigation_start,
navigation_start_precise)),
navigation_start,
navigation_start_precise)),
entries: DOMRefCell::new(PerformanceEntryList::new(Vec::new())),
observers: DOMRefCell::new(Vec::new()),
pending_notification_observers_task: Cell::new(false),
Expand Down Expand Up @@ -139,9 +186,6 @@ impl Performance {
///
/// Algorithm spec:
/// https://w3c.github.io/performance-timeline/#queue-a-performanceentry
///
/// XXX This should be called at some point by the User Timing, Resource
/// Timing, Server Timing and Paint Timing APIs.
pub fn queue_entry(&self, entry: &PerformanceEntry,
add_to_performance_entries_buffer: bool) {
// Steps 1-3.
Expand Down Expand Up @@ -198,6 +242,11 @@ impl Performance {
o.notify();
}
}

fn now(&self) -> f64 {
let nav_start = self.timing.navigation_start_precise();
(time::precise_time_ns() as f64 - nav_start) / 1000000 as f64
}
}

pub struct NotifyPerformanceObserverRunnable {
Expand Down Expand Up @@ -229,9 +278,7 @@ impl PerformanceMethods for Performance {

// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now
fn Now(&self) -> DOMHighResTimeStamp {
let nav_start = self.timing.navigation_start_precise();
let now = (time::precise_time_ns() as f64 - nav_start) / 1000000 as f64;
Finite::wrap(now)
Finite::wrap(self.now())
}

// https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
Expand All @@ -249,4 +296,72 @@ impl PerformanceMethods for Performance {
-> Vec<Root<PerformanceEntry>> {
self.entries.borrow().get_entries_by_name_and_type(Some(name), entry_type)
}

// https://w3c.github.io/user-timing/#dom-performance-mark
fn Mark(&self, mark_name: DOMString) -> Fallible<()> {
let global = self.global();
// Step 1.
if global.is::<Window>() && INVALID_ENTRY_NAMES.contains(&mark_name.as_ref()) {
return Err((Error::Syntax));
}

// Steps 2 to 6.
let entry = PerformanceMark::new(&global,
mark_name,
self.now(),
0.);
// Steps 7 and 8.
self.queue_entry(&entry.upcast::<PerformanceEntry>(),
true /* buffer performance entry */);

// Step 9.
Ok(())
}

// https://w3c.github.io/user-timing/#dom-performance-clearmarks
fn ClearMarks(&self, mark_name: Option<DOMString>) {
self.entries.borrow_mut().clear_entries_by_name_and_type(mark_name,
Some(DOMString::from("mark")));
}

// https://w3c.github.io/user-timing/#dom-performance-measure
fn Measure(&self,
measure_name: DOMString,
start_mark: Option<DOMString>,
end_mark: Option<DOMString>) -> Fallible<()> {
// Steps 1 and 2.
let end_time = match end_mark {
Some(name) =>
self.entries.borrow().get_last_entry_start_time_with_name_and_type(
DOMString::from("mark"), name),
None => self.now(),
};

// Step 3.
let start_time = match start_mark {
Some(name) =>
self.entries.borrow().get_last_entry_start_time_with_name_and_type(
DOMString::from("mark"), name),
None => 0.,
};

// Steps 4 to 8.
let entry = PerformanceMeasure::new(&self.global(),
measure_name,
start_time,
end_time - start_time);

// Step 9 and 10.
self.queue_entry(&entry.upcast::<PerformanceEntry>(),
true /* buffer performance entry */);

// Step 11.
Ok(())
}

// https://w3c.github.io/user-timing/#dom-performance-clearmeasures
fn ClearMeasures(&self, measure_name: Option<DOMString>) {
self.entries.borrow_mut().clear_entries_by_name_and_type(measure_name,
Some(DOMString::from("measure")));
}
}
7 changes: 7 additions & 0 deletions components/script/dom/performancemark.rs
@@ -0,0 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

impl_performance_entry_struct!(PerformanceMarkBinding,
PerformanceMark,
"mark");
7 changes: 7 additions & 0 deletions components/script/dom/performancemeasure.rs
@@ -0,0 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

impl_performance_entry_struct!(PerformanceMeasureBinding,
PerformanceMeasure,
"measure");
4 changes: 2 additions & 2 deletions components/script/dom/performanceobserver.rs
Expand Up @@ -23,8 +23,8 @@ use std::rc::Rc;

/// List of allowed performance entry types.
const VALID_ENTRY_TYPES: &'static [&'static str] = &[
// "mark", XXX User Timing API
// "measure", XXX User Timing API
"mark", // User Timing API
"measure", // User Timing API
// "resource", XXX Resource Timing API
// "server", XXX Server Timing API
"paint", // Paint Timing API
Expand Down
11 changes: 11 additions & 0 deletions components/script/dom/webidls/Performance.webidl
Expand Up @@ -26,3 +26,14 @@ partial interface Performance {
PerformanceEntryList getEntriesByName(DOMString name,
optional DOMString type);
};

// http://www.w3.org/TR/user-timing/
[Exposed=(Window,Worker)]
partial interface Performance {
[Throws]
void mark(DOMString markName);
void clearMarks(optional DOMString markName);
[Throws]
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
void clearMeasures(optional DOMString measureName);
};
11 changes: 11 additions & 0 deletions components/script/dom/webidls/PerformanceMark.webidl
@@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/user-timing/#performancemark
*/

[Exposed=(Window,Worker)]
interface PerformanceMark : PerformanceEntry {
};
11 changes: 11 additions & 0 deletions components/script/dom/webidls/PerformanceMeasure.webidl
@@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/user-timing/#performancemeasure
*/

[Exposed=(Window,Worker)]
interface PerformanceMeasure : PerformanceEntry {
};
2 changes: 2 additions & 0 deletions tests/wpt/include.ini
Expand Up @@ -45,6 +45,8 @@ skip: true
skip: true
[script_scheduling]
skip: false
[performance-timeline]
skip: false
[quirks-mode]
skip: false
[referrer-policy]
Expand Down
2 changes: 2 additions & 0 deletions tests/wpt/metadata/fetch/api/cors/cors-preflight.any.js.ini
Expand Up @@ -21,6 +21,7 @@
[CORS [PUT\] [several headers\], server allows]
expected: FAIL


[cors-preflight.any.worker.html]
type: testharness
[CORS [PATCH\], server allows]
Expand All @@ -43,3 +44,4 @@

[CORS [PUT\] [several headers\], server allows]
expected: FAIL

@@ -0,0 +1,17 @@
[case-sensitivity.any.worker.html]
type: testharness
[getEntriesByType values are case sensitive]
expected: FAIL

[getEntriesByName values are case sensitive]
expected: FAIL


[case-sensitivity.any.html]
type: testharness
[getEntriesByType values are case sensitive]
expected: FAIL

[getEntriesByName values are case sensitive]
expected: FAIL

13 changes: 13 additions & 0 deletions tests/wpt/metadata/performance-timeline/po-disconnect.any.js.ini
@@ -0,0 +1,13 @@
[po-disconnect.any.html]
type: testharness
expected: TIMEOUT
[An observer disconnected after a mark must receive the mark]
expected: TIMEOUT


[po-disconnect.any.worker.html]
type: testharness
expected: TIMEOUT
[disconnected callbacks must not be invoked]
expected: TIMEOUT

@@ -0,0 +1,9 @@
[po-getentries.any.html]
type: testharness

[po-getentries.any.worker.html]
type: testharness
expected: TIMEOUT
[getEntries, getEntriesByType and getEntriesByName work]
expected: TIMEOUT

@@ -0,0 +1,6 @@
[po-mark-measure.any.html]
type: testharness

[po-mark-measure.any.worker.html]
type: testharness
expected: CRASH
@@ -0,0 +1,5 @@
[po-navigation.html]
type: testharness
[navigation entry is observable]
expected: FAIL

9 changes: 9 additions & 0 deletions tests/wpt/metadata/performance-timeline/po-observe.any.js.ini
@@ -0,0 +1,9 @@
[po-observe.any.worker.html]
type: testharness
expected: CRASH

[po-observe.any.html]
type: testharness
[replace observer if already present]
expected: FAIL

0 comments on commit a91250e

Please sign in to comment.