mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
959c1c861a
--HG-- rename : devtools/shared/shared/framerate.js => devtools/server/performance/framerate.js rename : devtools/shared/shared/memory.js => devtools/server/performance/memory.js rename : devtools/shared/shared/profiler.js => devtools/server/performance/profiler.js
231 lines
6.9 KiB
JavaScript
231 lines
6.9 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
const { Cu } = require("chrome");
|
|
const protocol = require("devtools/server/protocol");
|
|
const { custom, method, RetVal, Arg, Option, types } = protocol;
|
|
const { Profiler } = require("devtools/server/performance/profiler");
|
|
const { actorBridge } = require("devtools/server/actors/common");
|
|
|
|
loader.lazyRequireGetter(this, "events", "sdk/event/core");
|
|
loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
|
|
|
|
types.addType("profiler-data", {
|
|
// On Fx42+, the profile is only deserialized on the front; older
|
|
// servers will get the profiler data as an object from nsIProfiler,
|
|
// causing one parse/stringify cycle, then again implicitly in a packet.
|
|
read: (v) => {
|
|
if (typeof v.profile === "string") {
|
|
// Create a new response object since `profile` is read only.
|
|
let newValue = Object.create(null);
|
|
newValue.profile = JSON.parse(v.profile);
|
|
newValue.currentTime = v.currentTime;
|
|
return newValue;
|
|
}
|
|
return v;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* This actor wraps the Profiler module at devtools/server/performance/profiler.js
|
|
* and provides RDP definitions.
|
|
*
|
|
* @see devtools/server/performance/profiler.js for documentation.
|
|
*/
|
|
var ProfilerActor = exports.ProfilerActor = protocol.ActorClass({
|
|
typeName: "profiler",
|
|
|
|
/**
|
|
* The set of events the ProfilerActor emits over RDP.
|
|
*/
|
|
events: {
|
|
"console-api-profiler": {
|
|
data: Arg(0, "json"),
|
|
},
|
|
"profiler-started": {
|
|
data: Arg(0, "json"),
|
|
},
|
|
"profiler-stopped": {
|
|
data: Arg(0, "json"),
|
|
},
|
|
"profiler-status": {
|
|
data: Arg(0, "json"),
|
|
},
|
|
|
|
// Only for older geckos, pre-protocol.js ProfilerActor (<Fx42).
|
|
// Emitted on other events as a transition from older profiler events
|
|
// to newer ones.
|
|
"eventNotification": {
|
|
subject: Option(0, "json"),
|
|
topic: Option(0, "string"),
|
|
details: Option(0, "json")
|
|
}
|
|
},
|
|
|
|
initialize: function (conn) {
|
|
protocol.Actor.prototype.initialize.call(this, conn);
|
|
this._onProfilerEvent = this._onProfilerEvent.bind(this);
|
|
|
|
this.bridge = new Profiler();
|
|
events.on(this.bridge, "*", this._onProfilerEvent);
|
|
},
|
|
|
|
/**
|
|
* `disconnect` method required to call destroy, since this
|
|
* actor is not managed by a parent actor.
|
|
*/
|
|
disconnect: function() {
|
|
this.destroy();
|
|
},
|
|
|
|
destroy: function() {
|
|
events.off(this.bridge, "*", this._onProfilerEvent);
|
|
this.bridge.destroy();
|
|
protocol.Actor.prototype.destroy.call(this);
|
|
},
|
|
|
|
startProfiler: actorBridge("start", {
|
|
// Write out every property in the request, since we want all these options to be
|
|
// on the packet's top-level for backwards compatibility, when the profiler actor
|
|
// was not using protocol.js (<Fx42)
|
|
request: {
|
|
entries: Option(0, "nullable:number"),
|
|
interval: Option(0, "nullable:number"),
|
|
features: Option(0, "nullable:array:string"),
|
|
threadFilters: Option(0, "nullable:array:string"),
|
|
},
|
|
response: RetVal("json"),
|
|
}),
|
|
|
|
stopProfiler: actorBridge("stop", {
|
|
response: RetVal("json"),
|
|
}),
|
|
|
|
getProfile: actorBridge("getProfile", {
|
|
request: {
|
|
startTime: Option(0, "nullable:number"),
|
|
stringify: Option(0, "nullable:boolean")
|
|
},
|
|
response: RetVal("profiler-data")
|
|
}),
|
|
|
|
getFeatures: actorBridge("getFeatures", {
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
getBufferInfo: actorBridge("getBufferInfo", {
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
getStartOptions: actorBridge("getStartOptions", {
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
isActive: actorBridge("isActive", {
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
getSharedLibraryInformation: actorBridge("getSharedLibraryInformation", {
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
registerEventNotifications: actorBridge("registerEventNotifications", {
|
|
// Explicitly enumerate the arguments
|
|
// @see ProfilerActor#startProfiler
|
|
request: {
|
|
events: Option(0, "nullable:array:string"),
|
|
},
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
unregisterEventNotifications: actorBridge("unregisterEventNotifications", {
|
|
// Explicitly enumerate the arguments
|
|
// @see ProfilerActor#startProfiler
|
|
request: {
|
|
events: Option(0, "nullable:array:string"),
|
|
},
|
|
response: RetVal("json")
|
|
}),
|
|
|
|
setProfilerStatusInterval: actorBridge("setProfilerStatusInterval", {
|
|
request: { interval: Arg(0, "number") },
|
|
oneway: true
|
|
}),
|
|
|
|
/**
|
|
* Pipe events from Profiler module to this actor.
|
|
*/
|
|
_onProfilerEvent: function (eventName, ...data) {
|
|
events.emit(this, eventName, ...data);
|
|
},
|
|
});
|
|
|
|
/**
|
|
* This can be used on older Profiler implementations, but the methods cannot
|
|
* be changed -- you must introduce a new method, and detect the server.
|
|
*/
|
|
exports.ProfilerFront = protocol.FrontClass(ProfilerActor, {
|
|
initialize: function(client, form) {
|
|
protocol.Front.prototype.initialize.call(this, client, form);
|
|
this.actorID = form.profilerActor;
|
|
this.manage(this);
|
|
|
|
this._onProfilerEvent = this._onProfilerEvent.bind(this);
|
|
events.on(this, "*", this._onProfilerEvent);
|
|
},
|
|
|
|
destroy: function () {
|
|
events.off(this, "*", this._onProfilerEvent);
|
|
protocol.Front.prototype.destroy.call(this);
|
|
},
|
|
|
|
/**
|
|
* If using the protocol.js Fronts, then make stringify default,
|
|
* since the read/write mechanisms will expose it as an object anyway, but
|
|
* this lets other consumers who connect directly (xpcshell tests, Gecko Profiler) to
|
|
* have unchanged behaviour.
|
|
*/
|
|
getProfile: custom(function (options) {
|
|
return this._getProfile(extend({ stringify: true }, options));
|
|
}, {
|
|
impl: "_getProfile"
|
|
}),
|
|
|
|
/**
|
|
* Also emit an old `eventNotification` for older consumers of the profiler.
|
|
*/
|
|
_onProfilerEvent: function (eventName, data) {
|
|
// If this event already passed through once, don't repropagate
|
|
if (data.relayed) {
|
|
return;
|
|
}
|
|
data.relayed = true;
|
|
|
|
// If this is `eventNotification`, this is coming from an older Gecko (<Fx42)
|
|
// that doesn't use protocol.js style events. Massage it to emit a protocol.js
|
|
// style event as well.
|
|
if (eventName === "eventNotification") {
|
|
events.emit(this, data.topic, data);
|
|
}
|
|
// Otherwise if a modern protocol.js event, emit it also as `eventNotification`
|
|
// for compatibility reasons on the client (like for any add-ons/Gecko Profiler using this
|
|
// event) and log a deprecation message if there is a listener.
|
|
else {
|
|
this.conn.emit("eventNotification", {
|
|
subject: data.subject,
|
|
topic: data.topic,
|
|
data: data.data,
|
|
details: data.details
|
|
});
|
|
if (this.conn._getListeners("eventNotification").length) {
|
|
Cu.reportError(`
|
|
ProfilerActor's "eventNotification" on the DebuggerClient has been deprecated.
|
|
Use the ProfilerFront found in "devtools/server/actors/profiler".`);
|
|
}
|
|
}
|
|
},
|
|
});
|