mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1177226 - Support User Timing API events in the Developer HUD. r=ehsan, r=jryans
This commit is contained in:
parent
bb0be845a6
commit
6ec6ba48ee
@ -1167,3 +1167,7 @@ pref("dom.audiochannel.mutedByDefault", true);
|
||||
|
||||
// Default device name for Presentation API
|
||||
pref("dom.presentation.device.name", "Firefox OS");
|
||||
|
||||
// Enable notification of performance timing
|
||||
pref("dom.performance.enable_notify_performance_timing", true);
|
||||
|
||||
|
@ -25,6 +25,10 @@ XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
|
||||
return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'PerformanceEntriesFront', function() {
|
||||
return devtools.require('devtools/server/actors/performance-entries').PerformanceEntriesFront;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
|
||||
return devtools.require('devtools/server/actors/memory').MemoryFront;
|
||||
});
|
||||
@ -588,6 +592,76 @@ let eventLoopLagWatcher = {
|
||||
};
|
||||
developerHUD.registerWatcher(eventLoopLagWatcher);
|
||||
|
||||
/*
|
||||
* The performanceEntriesWatcher determines the delta between the epoch
|
||||
* of an app's launch time and the app's performance entry marks.
|
||||
* When it receives an "appLaunch" performance entry mark it records the
|
||||
* name of the app being launched and the epoch of when the launch ocurred.
|
||||
* When it receives subsequent performance entry events for the app being
|
||||
* launched, it records the delta of the performance entry opoch compared
|
||||
* to the app-launch epoch and emits an "app-start-time-<performance mark name>"
|
||||
* event containing the delta.
|
||||
*/
|
||||
let performanceEntriesWatcher = {
|
||||
_client: null,
|
||||
_fronts: new Map(),
|
||||
_appLaunchName: null,
|
||||
_appLaunchStartTime: null,
|
||||
|
||||
init(client) {
|
||||
this._client = client;
|
||||
},
|
||||
|
||||
trackTarget(target) {
|
||||
// The performanceEntries watcher doesn't register a metric because
|
||||
// currently the metrics generated are not displayed in
|
||||
// in the front-end.
|
||||
|
||||
let front = new PerformanceEntriesFront(this._client, target.actor);
|
||||
this._fronts.set(target, front);
|
||||
|
||||
// User timings are always gathered; there is no setting to enable/
|
||||
// disable.
|
||||
front.start();
|
||||
|
||||
front.on('entry', detail => {
|
||||
if (detail.type === 'mark') {
|
||||
let name = detail.name;
|
||||
let epoch = detail.epoch;
|
||||
let CHARS_UNTIL_APP_NAME = 7; // '@app://'
|
||||
|
||||
// FIXME There is a potential race condition that can result
|
||||
// in some performance entries being disregarded. See bug 1189942.
|
||||
if (name.indexOf('appLaunch') != -1) {
|
||||
let appStartPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME;
|
||||
let length = (name.indexOf('.') - appStartPos);
|
||||
this._appLaunchName = name.substr(appStartPos, length);
|
||||
this._appLaunchStartTime = epoch;
|
||||
} else {
|
||||
let origin = detail.origin;
|
||||
origin = origin.substr(0, origin.indexOf('.'));
|
||||
if (this._appLaunchName === origin) {
|
||||
let time = epoch - this._appLaunchStartTime;
|
||||
let eventName = 'app-startup-time-' + name;
|
||||
|
||||
// Events based on performance marks are for telemetry only, they are
|
||||
// not displayed in the HUD front end.
|
||||
target._sendTelemetryEvent({name: eventName, value: time});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
untrackTarget(target) {
|
||||
let fronts = this._fronts;
|
||||
if (fronts.has(target)) {
|
||||
fronts.get(target).destroy();
|
||||
fronts.delete(target);
|
||||
}
|
||||
}
|
||||
};
|
||||
developerHUD.registerWatcher(performanceEntriesWatcher);
|
||||
|
||||
/**
|
||||
* The Memory Watcher uses devtools actors to track memory usage.
|
||||
|
@ -262,6 +262,7 @@ bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
|
||||
bool nsContentUtils::sEncodeDecodeURLHash = false;
|
||||
bool nsContentUtils::sGettersDecodeURLHash = false;
|
||||
bool nsContentUtils::sPrivacyResistFingerprinting = false;
|
||||
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
|
||||
|
||||
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
|
||||
|
||||
@ -553,6 +554,9 @@ nsContentUtils::Init()
|
||||
"dom.event.handling-user-input-time-limit",
|
||||
1000);
|
||||
|
||||
Preferences::AddBoolVarCache(&sSendPerformanceTimingNotifications,
|
||||
"dom.performance.enable_notify_performance_timing", false);
|
||||
|
||||
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
|
||||
Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
|
||||
"browser.dom.window.dump.enabled");
|
||||
|
@ -1948,6 +1948,14 @@ public:
|
||||
return sIsResourceTimingEnabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if notification should be sent for peformance timing events.
|
||||
*/
|
||||
static bool SendPerformanceTimingNotifications()
|
||||
{
|
||||
return sSendPerformanceTimingNotifications;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if URL setters should percent encode the Hash/Ref segment
|
||||
* and getters should return the percent decoded value of the segment
|
||||
@ -2544,6 +2552,7 @@ private:
|
||||
static bool sEncodeDecodeURLHash;
|
||||
static bool sGettersDecodeURLHash;
|
||||
static bool sPrivacyResistFingerprinting;
|
||||
static bool sSendPerformanceTimingNotifications;
|
||||
|
||||
static nsHtml5StringParser* sHTMLFragmentParser;
|
||||
static nsIParser* sXMLFragmentParser;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "PerformanceResourceTiming.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/PerformanceBinding.h"
|
||||
#include "mozilla/dom/PerformanceEntryEvent.h"
|
||||
#include "mozilla/dom/PerformanceTimingBinding.h"
|
||||
#include "mozilla/dom/PerformanceNavigationBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -738,14 +739,24 @@ nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
|
||||
nsAutoCString uri;
|
||||
nsAutoCString uri;
|
||||
uint64_t markCreationEpoch = 0;
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled() ||
|
||||
nsContentUtils::SendPerformanceTimingNotifications()) {
|
||||
nsresult rv = GetOwner()->GetDocumentURI()->GetHost(uri);
|
||||
if(NS_FAILED(rv)) {
|
||||
// If we have no URI, just put in "none".
|
||||
uri.AssignLiteral("none");
|
||||
}
|
||||
PerformanceBase::LogEntry(aEntry, uri);
|
||||
markCreationEpoch = static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC);
|
||||
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
|
||||
PerformanceBase::LogEntry(aEntry, uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (nsContentUtils::SendPerformanceTimingNotifications()) {
|
||||
TimingNotification(aEntry, uri, markCreationEpoch);
|
||||
}
|
||||
|
||||
PerformanceBase::InsertUserEntry(aEntry);
|
||||
@ -986,6 +997,29 @@ PerformanceBase::LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) co
|
||||
static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner, uint64_t aEpoch)
|
||||
{
|
||||
PerformanceEntryEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
init.mName = aEntry->GetName();
|
||||
init.mEntryType = aEntry->GetEntryType();
|
||||
init.mStartTime = aEntry->StartTime();
|
||||
init.mDuration = aEntry->Duration();
|
||||
init.mEpoch = aEpoch;
|
||||
init.mOrigin = NS_ConvertUTF8toUTF16(aOwner.BeginReading());
|
||||
|
||||
nsRefPtr<PerformanceEntryEvent> perfEntryEvent =
|
||||
PerformanceEntryEvent::Constructor(this, NS_LITERAL_STRING("performanceentry"), init);
|
||||
|
||||
nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
|
||||
if (et) {
|
||||
bool dummy = false;
|
||||
et->DispatchEvent(perfEntryEvent, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
|
@ -351,6 +351,7 @@ protected:
|
||||
}
|
||||
|
||||
void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const;
|
||||
void TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner, uint64_t epoch);
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
|
||||
|
27
dom/webidl/PerformanceEntryEvent.webidl
Normal file
27
dom/webidl/PerformanceEntryEvent.webidl
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
dictionary PerformanceEntryEventInit : EventInit
|
||||
{
|
||||
DOMString name = "";
|
||||
DOMString entryType = "";
|
||||
DOMHighResTimeStamp startTime = 0;
|
||||
DOMHighResTimeStamp duration = 0;
|
||||
double epoch = 0;
|
||||
DOMString origin = "";
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional PerformanceEntryEventInit eventInitDict),
|
||||
ChromeOnly]
|
||||
interface PerformanceEntryEvent : Event
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString entryType;
|
||||
readonly attribute DOMHighResTimeStamp startTime;
|
||||
readonly attribute DOMHighResTimeStamp duration;
|
||||
readonly attribute double epoch;
|
||||
readonly attribute DOMString origin;
|
||||
};
|
@ -779,6 +779,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
||||
'MozStkCommandEvent.webidl',
|
||||
'MozVoicemailEvent.webidl',
|
||||
'PageTransitionEvent.webidl',
|
||||
'PerformanceEntryEvent.webidl',
|
||||
'PluginCrashedEvent.webidl',
|
||||
'PopStateEvent.webidl',
|
||||
'PopupBlockedEvent.webidl',
|
||||
|
@ -160,6 +160,9 @@ pref("dom.enable_user_timing", true);
|
||||
// Enable printing performance marks/measures to log
|
||||
pref("dom.performance.enable_user_timing_logging", false);
|
||||
|
||||
// Enable notification of performance timing
|
||||
pref("dom.performance.enable_notify_performance_timing", false);
|
||||
|
||||
// Whether the Gamepad API is enabled
|
||||
pref("dom.gamepad.enabled", true);
|
||||
#ifdef RELEASE_BUILD
|
||||
|
83
toolkit/devtools/server/actors/performance-entries.js
Normal file
83
toolkit/devtools/server/actors/performance-entries.js
Normal file
@ -0,0 +1,83 @@
|
||||
/* 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 performanceEntries actor emits events corresponding to performance
|
||||
* entries. It receives `performanceentry` events containing the performance
|
||||
* entry details and emits an event containing the name, type, origin, and
|
||||
* epoch of the performance entry.
|
||||
*/
|
||||
|
||||
const {
|
||||
method, Arg, Option, RetVal, Front, FrontClass, Actor, ActorClass
|
||||
} = require("devtools/server/protocol");
|
||||
const events = require("sdk/event/core");
|
||||
|
||||
let PerformanceEntriesActor = exports.PerformanceEntriesActor = ActorClass({
|
||||
|
||||
typeName: "performanceEntries",
|
||||
|
||||
listenerAdded: false,
|
||||
|
||||
events: {
|
||||
"entry" : {
|
||||
type: "entry",
|
||||
detail: Arg(0, "json") // object containing performance entry name, type,
|
||||
// origin, and epoch.
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function(conn, tabActor) {
|
||||
Actor.prototype.initialize.call(this, conn);
|
||||
this.window = tabActor.window;
|
||||
},
|
||||
|
||||
/**
|
||||
* Start tracking the user timings.
|
||||
*/
|
||||
start: method(function() {
|
||||
if (!this.listenerAdded) {
|
||||
this.onPerformanceEntry = this.onPerformanceEntry.bind(this);
|
||||
this.window.addEventListener("performanceentry", this.onPerformanceEntry, true);
|
||||
this.listenerAdded = true;
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Stop tracking the user timings.
|
||||
*/
|
||||
stop: method(function() {
|
||||
if (this.listenerAdded) {
|
||||
this.window.removeEventListener("performanceentry", this.onPerformanceEntry, true);
|
||||
this.listenerAdded = false;
|
||||
}
|
||||
}),
|
||||
|
||||
disconnect: function() {
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.stop();
|
||||
Actor.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
onPerformanceEntry: function (e) {
|
||||
let emitDetail = {
|
||||
type: e.entryType,
|
||||
name: e.name,
|
||||
origin: e.origin,
|
||||
epoch: e.epoch
|
||||
};
|
||||
events.emit(this, 'entry', emitDetail);
|
||||
}
|
||||
});
|
||||
|
||||
exports.PerformanceEntriesFront = FrontClass(PerformanceEntriesActor, {
|
||||
initialize: function(client, form) {
|
||||
Front.prototype.initialize.call(this, client);
|
||||
this.actorID = form.performanceEntriesActor;
|
||||
this.manage(this);
|
||||
},
|
||||
});
|
@ -545,6 +545,11 @@ var DebuggerServer = {
|
||||
constructor: "PromisesActor",
|
||||
type: { global: true, tab: true }
|
||||
});
|
||||
this.registerModule("devtools/server/actors/performance-entries", {
|
||||
prefix: "performanceEntries",
|
||||
constructor: "PerformanceEntriesActor",
|
||||
type: { tab: true }
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -75,6 +75,7 @@ EXTRA_JS_MODULES.devtools.server.actors += [
|
||||
'actors/memory.js',
|
||||
'actors/monitor.js',
|
||||
'actors/object.js',
|
||||
'actors/performance-entries.js',
|
||||
'actors/preference.js',
|
||||
'actors/pretty-print-worker.js',
|
||||
'actors/profiler.js',
|
||||
|
Loading…
Reference in New Issue
Block a user