Mypal/devtools/server/actors/performance.js

117 lines
3.6 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 { Task } = require("devtools/shared/task");
const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
const { actorBridgeWithSpec } = require("devtools/server/actors/common");
const { performanceSpec } = require("devtools/shared/specs/performance");
loader.lazyRequireGetter(this, "events", "sdk/event/core");
loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
loader.lazyRequireGetter(this, "PerformanceRecorder",
"devtools/server/performance/recorder", true);
loader.lazyRequireGetter(this, "normalizePerformanceFeatures",
"devtools/shared/performance/recording-utils", true);
const PIPE_TO_FRONT_EVENTS = new Set([
"recording-started", "recording-stopping", "recording-stopped",
"profiler-status", "timeline-data", "console-profile-start"
]);
const RECORDING_STATE_CHANGE_EVENTS = new Set([
"recording-started", "recording-stopping", "recording-stopped"
]);
/**
* This actor wraps the Performance module at devtools/shared/shared/performance.js
* and provides RDP definitions.
*
* @see devtools/shared/shared/performance.js for documentation.
*/
var PerformanceActor = ActorClassWithSpec(performanceSpec, {
traits: {
features: {
withMarkers: true,
withTicks: true,
withMemory: true,
withFrames: true,
withGCEvents: true,
withDocLoadingEvents: true,
withAllocations: true,
},
},
initialize: function (conn, tabActor) {
Actor.prototype.initialize.call(this, conn);
this._onRecorderEvent = this._onRecorderEvent.bind(this);
this.bridge = new PerformanceRecorder(conn, tabActor);
events.on(this.bridge, "*", this._onRecorderEvent);
},
/**
* `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._onRecorderEvent);
this.bridge.destroy();
Actor.prototype.destroy.call(this);
},
connect: function (config) {
this.bridge.connect({ systemClient: config.systemClient });
return { traits: this.traits };
},
canCurrentlyRecord: function () {
return this.bridge.canCurrentlyRecord();
},
startRecording: Task.async(function* (options = {}) {
if (!this.bridge.canCurrentlyRecord().success) {
return null;
}
let normalizedOptions = normalizePerformanceFeatures(options, this.traits.features);
let recording = yield this.bridge.startRecording(normalizedOptions);
this.manage(recording);
return recording;
}),
stopRecording: actorBridgeWithSpec("stopRecording"),
isRecording: actorBridgeWithSpec("isRecording"),
getRecordings: actorBridgeWithSpec("getRecordings"),
getConfiguration: actorBridgeWithSpec("getConfiguration"),
setProfilerStatusInterval: actorBridgeWithSpec("setProfilerStatusInterval"),
/**
* Filter which events get piped to the front.
*/
_onRecorderEvent: function (eventName, ...data) {
// If this is a recording state change, call
// a method on the related PerformanceRecordingActor so it can
// update its internal state.
if (RECORDING_STATE_CHANGE_EVENTS.has(eventName)) {
let recording = data[0];
let extraData = data[1];
recording._setState(eventName, extraData);
}
if (PIPE_TO_FRONT_EVENTS.has(eventName)) {
events.emit(this, eventName, ...data);
}
},
});
exports.PerformanceActor = PerformanceActor;