mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 908390 part 2. Implement performance.now() on workers. r=khuey
--HG-- rename : dom/workers/test/test_worker_interfaces.html => dom/workers/test/test_worker_performance_now.html rename : dom/tests/mochitest/general/test_performance_now.html => dom/workers/test/test_worker_performance_now.js
This commit is contained in:
parent
3dc5b32864
commit
ed56d2edc8
@ -959,10 +959,15 @@ DOMInterfaces = {
|
||||
'wrapperCache': False
|
||||
},
|
||||
|
||||
'Performance': {
|
||||
'Performance': [{
|
||||
'nativeType': 'nsPerformance',
|
||||
'resultNotAddRefed': [ 'timing', 'navigation' ]
|
||||
},
|
||||
{
|
||||
'nativeType': 'mozilla::dom::workers::Performance',
|
||||
'headerFile': 'mozilla/dom/workers/bindings/Performance.h',
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'PerformanceTiming': {
|
||||
'nativeType': 'nsPerformanceTiming',
|
||||
@ -1619,7 +1624,12 @@ DOMInterfaces = {
|
||||
'implicitJSContext': [
|
||||
'close', 'importScripts',
|
||||
],
|
||||
'binaryNames': { 'console': 'getConsole', },
|
||||
# Rename a few things so we don't have both classes and methods
|
||||
# with the same name
|
||||
'binaryNames': {
|
||||
'console': 'getConsole',
|
||||
'performance': 'getPerformance',
|
||||
},
|
||||
},
|
||||
|
||||
'WorkerLocation': {
|
||||
|
@ -13,9 +13,13 @@
|
||||
typedef double DOMHighResTimeStamp;
|
||||
typedef sequence <PerformanceEntry> PerformanceEntryList;
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface Performance {
|
||||
DOMHighResTimeStamp now();
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
partial interface Performance {
|
||||
[Constant]
|
||||
readonly attribute PerformanceTiming timing;
|
||||
[Constant]
|
||||
@ -25,6 +29,7 @@ interface Performance {
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/performance-timeline/#sec-window.performance-attribute
|
||||
[Exposed=Window]
|
||||
partial interface Performance {
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
PerformanceEntryList getEntries();
|
||||
@ -36,6 +41,7 @@ partial interface Performance {
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/resource-timing/#extensions-performance-interface
|
||||
[Exposed=Window]
|
||||
partial interface Performance {
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
void clearResourceTimings();
|
||||
|
@ -44,4 +44,7 @@ partial interface WorkerGlobalScope {
|
||||
attribute EventHandler onclose;
|
||||
|
||||
void dump(optional DOMString str);
|
||||
|
||||
// XXXbz no spec for this yet, because the webperf WG is a bit dysfunctional
|
||||
readonly attribute Performance performance;
|
||||
};
|
||||
|
43
dom/workers/Performance.cpp
Normal file
43
dom/workers/Performance.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "Performance.h"
|
||||
#include "mozilla/dom/PerformanceBinding.h"
|
||||
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Performance, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Performance, Release)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Performance)
|
||||
|
||||
Performance::Performance(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
Performance::~Performance()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Performance::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return PerformanceBinding_workers::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
double
|
||||
Performance::Now() const
|
||||
{
|
||||
TimeDuration duration =
|
||||
TimeStamp::Now() - mWorkerPrivate->NowBaseTimeStamp();
|
||||
return duration.ToMilliseconds();
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
49
dom/workers/Performance.h
Normal file
49
dom/workers/Performance.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_performance_h__
|
||||
#define mozilla_dom_workers_performance_h__
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "Workers.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class WorkerPrivate;
|
||||
|
||||
class Performance MOZ_FINAL : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Performance)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Performance)
|
||||
|
||||
Performance(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
private:
|
||||
~Performance();
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
public:
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
nsISupports*
|
||||
GetParentObject() const
|
||||
{
|
||||
// There's only one global on a worker, so we don't need to specify.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// WebIDL (public APIs)
|
||||
double Now() const;
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_performance_h__
|
@ -21,6 +21,7 @@
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
@ -2127,11 +2128,22 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
||||
aParent->AssertIsOnWorkerThread();
|
||||
|
||||
aParent->CopyJSSettings(mJSSettings);
|
||||
|
||||
MOZ_ASSERT(IsDedicatedWorker());
|
||||
mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
|
||||
}
|
||||
else {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
RuntimeService::GetDefaultJSSettings(mJSSettings);
|
||||
|
||||
if (IsDedicatedWorker() && aLoadInfo.mWindow &&
|
||||
aLoadInfo.mWindow->GetPerformance()) {
|
||||
mNowBaseTimeStamp = aLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
|
||||
GetNavigationStartTimeStamp();
|
||||
} else {
|
||||
mNowBaseTimeStamp = CreationTimeStamp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,6 +243,7 @@ private:
|
||||
bool mMainThreadObjectsForgotten;
|
||||
WorkerType mWorkerType;
|
||||
TimeStamp mCreationTimeStamp;
|
||||
TimeStamp mNowBaseTimeStamp;
|
||||
|
||||
protected:
|
||||
// The worker is owned by its thread, which is represented here. This is set
|
||||
@ -515,6 +516,11 @@ public:
|
||||
return mCreationTimeStamp;
|
||||
}
|
||||
|
||||
TimeStamp NowBaseTimeStamp() const
|
||||
{
|
||||
return mNowBaseTimeStamp;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
GetPrincipal() const
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "RuntimeService.h"
|
||||
#include "ScriptLoader.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "Performance.h"
|
||||
|
||||
#define UNWRAP_WORKER_OBJECT(Interface, obj, value) \
|
||||
UnwrapObject<prototypes::id::Interface##_workers, \
|
||||
@ -54,12 +55,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
DOMEventTargetHelper)
|
||||
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
|
||||
// XXXbz what about mLocation and mNavigator?
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
DOMEventTargetHelper)
|
||||
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
|
||||
// XXXbz what about mLocation and mNavigator?
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
@ -277,6 +282,18 @@ WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
Performance*
|
||||
WorkerGlobalScope::GetPerformance()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (!mPerformance) {
|
||||
mPerformance = new Performance(mWorkerPrivate);
|
||||
}
|
||||
|
||||
return mPerformance;
|
||||
}
|
||||
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerGlobalScope(aWorkerPrivate)
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ BEGIN_WORKERS_NAMESPACE
|
||||
class WorkerPrivate;
|
||||
class WorkerLocation;
|
||||
class WorkerNavigator;
|
||||
class Performance;
|
||||
|
||||
class WorkerGlobalScope : public DOMEventTargetHelper,
|
||||
public nsIGlobalObject
|
||||
@ -30,6 +31,7 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
|
||||
nsRefPtr<Console> mConsole;
|
||||
nsRefPtr<WorkerLocation> mLocation;
|
||||
nsRefPtr<WorkerNavigator> mNavigator;
|
||||
nsRefPtr<Performance> mPerformance;
|
||||
|
||||
protected:
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
@ -115,6 +117,8 @@ public:
|
||||
|
||||
void
|
||||
Dump(const Optional<nsAString>& aString) const;
|
||||
|
||||
Performance* GetPerformance();
|
||||
};
|
||||
|
||||
class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
|
||||
|
@ -27,6 +27,7 @@ EXPORTS.mozilla.dom.workers.bindings += [
|
||||
'Location.h',
|
||||
'MessagePort.h',
|
||||
'Navigator.h',
|
||||
'Performance.h',
|
||||
'ServiceWorker.h',
|
||||
'SharedWorker.h',
|
||||
'URL.h',
|
||||
@ -44,6 +45,7 @@ SOURCES += [
|
||||
'Location.cpp',
|
||||
'MessagePort.cpp',
|
||||
'Navigator.cpp',
|
||||
'Performance.cpp',
|
||||
'Principal.cpp',
|
||||
'RegisterBindings.cpp',
|
||||
'RuntimeService.cpp',
|
||||
|
@ -79,6 +79,7 @@ support-files =
|
||||
subdir/relativeLoad_sub_worker2.js
|
||||
subdir/relativeLoad_sub_import.js
|
||||
test_worker_interfaces.js
|
||||
test_worker_performance_now.js
|
||||
worker_driver.js
|
||||
worker_wrapper.js
|
||||
|
||||
@ -152,6 +153,7 @@ skip-if = buildapp == 'b2g' || e10s # b2g(test timed out, might need more time)
|
||||
[test_urlApi.html]
|
||||
[test_workersDisabled.html]
|
||||
[test_worker_interfaces.html]
|
||||
[test_worker_performance_now.html]
|
||||
[test_xhr.html]
|
||||
[test_xhr2.html]
|
||||
[test_xhrAbort.html]
|
||||
|
@ -101,6 +101,8 @@ var interfaceNamesInGlobalScope =
|
||||
"MessageEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MessagePort",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Performance",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Promise",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
16
dom/workers/test/test_worker_performance_now.html
Normal file
16
dom/workers/test/test_worker_performance_now.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Validate Interfaces Exposed to Workers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="worker_driver.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
workerTestExec("test_worker_performance_now.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
54
dom/workers/test/test_worker_performance_now.js
Normal file
54
dom/workers/test/test_worker_performance_now.js
Normal file
@ -0,0 +1,54 @@
|
||||
ok(self.performance, "Performance object should exist.");
|
||||
ok(typeof self.performance.now == 'function', "Performance object should have a 'now' method.");
|
||||
var n = self.performance.now(), d = Date.now();
|
||||
ok(n >= 0, "The value of now() should be equal to or greater than 0.");
|
||||
ok(self.performance.now() >= n, "The value of now() should monotonically increase.");
|
||||
|
||||
// The spec says performance.now() should have micro-second resolution, but allows 1ms if the platform doesn't support it.
|
||||
// Our implementation does provide micro-second resolution, except for windows XP combined with some HW properties
|
||||
// where we can't use QueryPerformanceCounters (see comments at mozilla-central/xpcom/ds/TimeStamp_windows.cpp).
|
||||
// This XP-low-res case results in about 15ms resolutions, and can be identified when perf.now() returns only integers.
|
||||
//
|
||||
// Since setTimeout might return too early/late, our goal is that perf.now() changed within 2ms
|
||||
// (or 25ms for XP-low-res), rather than specific number of setTimeout(N) invocations.
|
||||
// See bug 749894 (intermittent failures of this test)
|
||||
var platformPossiblyLowRes;
|
||||
workerTestGetOSCPU(function(oscpu) {
|
||||
platformPossiblyLowRes = oscpu.indexOf("Windows NT 5.1") == 0; // XP only
|
||||
setTimeout(checkAfterTimeout, 1);
|
||||
});
|
||||
var allInts = (n % 1) == 0; // Indicator of limited HW resolution.
|
||||
var checks = 0;
|
||||
|
||||
function checkAfterTimeout() {
|
||||
checks++;
|
||||
var d2 = Date.now();
|
||||
var n2 = self.performance.now();
|
||||
|
||||
allInts = allInts && (n2 % 1) == 0;
|
||||
var lowResCounter = platformPossiblyLowRes && allInts;
|
||||
|
||||
if ( n2 == n && checks < 50 && // 50 is just a failsafe. Our real goals are 2ms or 25ms.
|
||||
( (d2 - d) < 2 // The spec allows 1ms resolution. We allow up to measured 2ms to ellapse.
|
||||
||
|
||||
lowResCounter &&
|
||||
(d2 - d) < 25
|
||||
)
|
||||
) {
|
||||
setTimeout(checkAfterTimeout, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Loose spec: 1ms resolution, or 15ms resolution for the XP-low-res case.
|
||||
// We shouldn't test that dt is actually within 2/25ms since the iterations break if it isn't, and timeout could be late.
|
||||
ok(n2 > n, "Loose - the value of now() should increase within 2ms (or 25ms if low-res counter) (delta now(): " + (n2 - n) + " ms).");
|
||||
|
||||
// Strict spec: if it's not the XP-low-res case, while the spec allows 1ms resolution, it prefers microseconds, which we provide.
|
||||
// Since the fastest setTimeout return which I observed was ~500 microseconds, a microseconds counter should change in 1 iteretion.
|
||||
ok(n2 > n && (lowResCounter || checks == 1),
|
||||
"Strict - [if high-res counter] the value of now() should increase after one setTimeout (hi-res: " + (!lowResCounter) +
|
||||
", iters: " + checks +
|
||||
", dt: " + (d2 - d) +
|
||||
", now(): " + n2 + ").");
|
||||
workerTestDone();
|
||||
};
|
@ -23,6 +23,7 @@
|
||||
// workerTestGetPermissions() - request an array permissions from the MT
|
||||
// workerTestGetVersion() - request the current version string from the MT
|
||||
// workerTestGetUserAgent() - request the user agent string from the MT
|
||||
// workerTestGetOSCPU() - request the navigator.oscpu string from the MT
|
||||
//
|
||||
// For an example see test_worker_interfaces.html and test_worker_interfaces.js.
|
||||
|
||||
@ -70,6 +71,11 @@ function workerTestExec(script) {
|
||||
type: 'returnUserAgent',
|
||||
result: navigator.userAgent
|
||||
});
|
||||
} else if (event.data.type == 'getOSCPU') {
|
||||
worker.postMessage({
|
||||
type: 'returnOSCPU',
|
||||
result: navigator.oscpu
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,19 @@ function workerTestGetUserAgent(cb) {
|
||||
});
|
||||
}
|
||||
|
||||
function workerTestGetOSCPU(cb) {
|
||||
addEventListener('message', function workerTestGetOSCPUCB(e) {
|
||||
if (e.data.type !== 'returnOSCPU') {
|
||||
return;
|
||||
}
|
||||
removeEventListener('message', workerTestGetOSCPUCB);
|
||||
cb(e.data.result);
|
||||
});
|
||||
postMessage({
|
||||
type: 'getOSCPU'
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener('message', function workerWrapperOnMessage(e) {
|
||||
removeEventListener('message', workerWrapperOnMessage);
|
||||
var data = e.data;
|
||||
|
Loading…
Reference in New Issue
Block a user