mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1130200 - Fix the mocked memory and timeline actors for older gecko targets (fx2.0, fx2.1). r=vp
This commit is contained in:
parent
2b20074ce1
commit
d18630fb7a
109
browser/devtools/performance/modules/compatibility.js
Normal file
109
browser/devtools/performance/modules/compatibility.js
Normal file
@ -0,0 +1,109 @@
|
||||
/* 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 { Task } = require("resource://gre/modules/Task.jsm");
|
||||
loader.lazyRequireGetter(this, "EventEmitter",
|
||||
"devtools/toolkit/event-emitter");
|
||||
|
||||
const REQUIRED_MEMORY_ACTOR_METHODS = [
|
||||
"attach", "detach", "startRecordingAllocations", "stopRecordingAllocations", "getAllocations"
|
||||
];
|
||||
|
||||
/**
|
||||
* A dummy front decorated with the provided methods.
|
||||
*
|
||||
* @param array blueprint
|
||||
* A list of [funcName, retVal] describing the class.
|
||||
*/
|
||||
function MockFront (blueprint) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
for (let [funcName, retVal] of blueprint) {
|
||||
this[funcName] = (x => typeof x === "function" ? x() : x).bind(this, retVal);
|
||||
}
|
||||
}
|
||||
|
||||
function MockMemoryFront () {
|
||||
MockFront.call(this, [
|
||||
["attach"],
|
||||
["detach"],
|
||||
["initialize"],
|
||||
["destroy"],
|
||||
["startRecordingAllocations", 0],
|
||||
["stopRecordingAllocations", 0],
|
||||
["getAllocations", createMockAllocations],
|
||||
]);
|
||||
}
|
||||
exports.MockMemoryFront = MockMemoryFront;
|
||||
|
||||
function MockTimelineFront () {
|
||||
MockFront.call(this, [
|
||||
["start", 0],
|
||||
["stop", 0],
|
||||
["initialize"],
|
||||
["destroy"],
|
||||
]);
|
||||
}
|
||||
exports.MockTimelineFront = MockTimelineFront;
|
||||
|
||||
/**
|
||||
* Create a fake allocations object, to be used with the MockMemoryFront
|
||||
* so we create a fresh object each time.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function createMockAllocations () {
|
||||
return {
|
||||
allocations: [],
|
||||
allocationsTimestamps: [],
|
||||
frames: [],
|
||||
counts: []
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a TabTarget, and checks through all methods that are needed
|
||||
* on the server's memory actor to determine if a mock or real MemoryActor
|
||||
* should be used. The last of the methods added to MemoryActor
|
||||
* landed in Gecko 35, so previous versions will fail this. Setting the `target`'s
|
||||
* TEST_MOCK_MEMORY_ACTOR property to true will cause this function to indicate that
|
||||
* the memory actor is not supported.
|
||||
*
|
||||
* @param {TabTarget} target
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function* memoryActorSupported (target) {
|
||||
// This `target` property is used only in tests to test
|
||||
// instances where the memory actor is not available.
|
||||
if (target.TEST_MOCK_MEMORY_ACTOR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let method of REQUIRED_MEMORY_ACTOR_METHODS) {
|
||||
if (!(yield target.actorHasMethod("memory", method))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.memoryActorSupported = Task.async(memoryActorSupported);
|
||||
|
||||
/**
|
||||
* Takes a TabTarget, and checks existence of a TimelineActor on
|
||||
* the server, or if TEST_MOCK_TIMELINE_ACTOR is to be used.
|
||||
*
|
||||
* @param {TabTarget} target
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function* timelineActorSupported(target) {
|
||||
// This `target` property is used only in tests to test
|
||||
// instances where the timeline actor is not available.
|
||||
if (target.TEST_MOCK_TIMELINE_ACTOR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return yield target.hasActor("timeline");
|
||||
}
|
||||
exports.timelineActorSupported = Task.async(timelineActorSupported);
|
@ -15,13 +15,13 @@ loader.lazyRequireGetter(this, "TimelineFront",
|
||||
"devtools/server/actors/timeline", true);
|
||||
loader.lazyRequireGetter(this, "MemoryFront",
|
||||
"devtools/server/actors/memory", true);
|
||||
|
||||
loader.lazyRequireGetter(this, "DevToolsUtils",
|
||||
"devtools/toolkit/DevToolsUtils");
|
||||
loader.lazyRequireGetter(this, "compatibility",
|
||||
"devtools/performance/compatibility");
|
||||
|
||||
loader.lazyImporter(this, "gDevTools",
|
||||
"resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
loader.lazyImporter(this, "setTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
loader.lazyImporter(this, "clearTimeout",
|
||||
@ -55,25 +55,6 @@ SharedPerformanceActors.forTarget = function(target) {
|
||||
return instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* A dummy front decorated with the provided methods.
|
||||
*
|
||||
* @param array blueprint
|
||||
* A list of [funcName, retVal] describing the class.
|
||||
*/
|
||||
function MockedFront(blueprint) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
for (let [funcName, retVal] of blueprint) {
|
||||
this[funcName] = (x => x).bind(this, retVal);
|
||||
}
|
||||
}
|
||||
|
||||
MockedFront.prototype = {
|
||||
initialize: function() {},
|
||||
destroy: function() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A connection to underlying actors (profiler, memory, framerate, etc.)
|
||||
* shared by all tools in a target.
|
||||
@ -95,6 +76,11 @@ function PerformanceActorsConnection(target) {
|
||||
}
|
||||
|
||||
PerformanceActorsConnection.prototype = {
|
||||
|
||||
// Properties set when mocks are being used
|
||||
_usingMockMemory: false,
|
||||
_usingMockTimeline: false,
|
||||
|
||||
/**
|
||||
* Initializes a connection to the profiler and other miscellaneous actors.
|
||||
* If in the process of opening, or already open, nothing happens.
|
||||
@ -158,36 +144,29 @@ PerformanceActorsConnection.prototype = {
|
||||
|
||||
/**
|
||||
* Initializes a connection to a timeline actor.
|
||||
* TODO: use framework level feature detection from bug 1069673
|
||||
*/
|
||||
_connectTimelineActor: function() {
|
||||
if (this._target.form && this._target.form.timelineActor) {
|
||||
let supported = yield compatibility.timelineActorSupported(this._target);
|
||||
if (supported) {
|
||||
this._timeline = new TimelineFront(this._target.client, this._target.form);
|
||||
} else {
|
||||
this._timeline = new MockedFront([
|
||||
["start", 0],
|
||||
["stop", 0]
|
||||
]);
|
||||
this._usingMockTimeline = true;
|
||||
this._timeline = new compatibility.MockTimelineFront();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes a connection to a memory actor.
|
||||
* TODO: use framework level feature detection from bug 1069673
|
||||
*/
|
||||
_connectMemoryActor: function() {
|
||||
if (this._target.form && this._target.form.memoryActor) {
|
||||
_connectMemoryActor: Task.async(function* () {
|
||||
let supported = yield compatibility.memoryActorSupported(this._target);
|
||||
if (supported) {
|
||||
this._memory = new MemoryFront(this._target.client, this._target.form);
|
||||
} else {
|
||||
this._memory = new MockedFront([
|
||||
["attach"],
|
||||
["detach"],
|
||||
["startRecordingAllocations", 0],
|
||||
["stopRecordingAllocations", 0],
|
||||
["getAllocations"]
|
||||
]);
|
||||
this._usingMockMemory = true;
|
||||
this._memory = new compatibility.MockMemoryFront();
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Closes the connections to non-profiler actors.
|
||||
@ -251,11 +230,16 @@ function PerformanceFront(connection) {
|
||||
connection._timeline.on("memory", (delta, measurement) => this.emit("memory", delta, measurement));
|
||||
connection._timeline.on("ticks", (delta, timestamps) => this.emit("ticks", delta, timestamps));
|
||||
|
||||
// Set when mocks are being used
|
||||
this._usingMockMemory = connection._usingMockMemory;
|
||||
this._usingMockTimeline = connection._usingMockTimeline;
|
||||
|
||||
this._pullAllocationSites = this._pullAllocationSites.bind(this);
|
||||
this._sitesPullTimeout = 0;
|
||||
}
|
||||
|
||||
PerformanceFront.prototype = {
|
||||
|
||||
/**
|
||||
* Manually begins a recording session.
|
||||
*
|
||||
@ -396,6 +380,16 @@ PerformanceFront.prototype = {
|
||||
entries: 1000000,
|
||||
interval: 1,
|
||||
features: ["js"]
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an object indicating if mock actors are being used or not.
|
||||
*/
|
||||
getMocksInUse: function () {
|
||||
return {
|
||||
memory: this._usingMockMemory,
|
||||
timeline: this._usingMockTimeline
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES.devtools.performance += [
|
||||
'modules/compatibility.js',
|
||||
'modules/front.js',
|
||||
'modules/io.js',
|
||||
'modules/recording-model.js',
|
||||
|
@ -10,6 +10,8 @@ support-files =
|
||||
|
||||
[browser_perf-aaa-run-first-leaktest.js]
|
||||
[browser_perf-allocations-to-samples.js]
|
||||
[browser_perf-compatibility-01.js]
|
||||
[browser_perf-compatibility-02.js]
|
||||
[browser_perf-clear-01.js]
|
||||
[browser_perf-clear-02.js]
|
||||
[browser_perf-data-massaging-01.js]
|
||||
|
@ -0,0 +1,63 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test basic functionality of PerformanceFront with mock memory and timeline actors.
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 100;
|
||||
|
||||
function spawnTest () {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, {
|
||||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true
|
||||
});
|
||||
|
||||
let { memory, timeline } = front.getMocksInUse();
|
||||
ok(memory, "memory should be mocked.");
|
||||
ok(timeline, "timeline should be mocked.");
|
||||
|
||||
let {
|
||||
profilerStartTime,
|
||||
timelineStartTime,
|
||||
memoryStartTime
|
||||
} = yield front.startRecording({
|
||||
withTicks: true,
|
||||
withMemory: true,
|
||||
withAllocations: true
|
||||
});
|
||||
|
||||
ok(typeof profilerStartTime === "number",
|
||||
"The front.startRecording() emits a profiler start time.");
|
||||
ok(typeof timelineStartTime === "number",
|
||||
"The front.startRecording() emits a timeline start time.");
|
||||
ok(typeof memoryStartTime === "number",
|
||||
"The front.startRecording() emits a memory start time.");
|
||||
|
||||
yield busyWait(WAIT_TIME);
|
||||
|
||||
let {
|
||||
profilerEndTime,
|
||||
timelineEndTime,
|
||||
memoryEndTime
|
||||
} = yield front.stopRecording({
|
||||
withAllocations: true
|
||||
});
|
||||
|
||||
ok(typeof profilerEndTime === "number",
|
||||
"The front.stopRecording() emits a profiler end time.");
|
||||
ok(typeof timelineEndTime === "number",
|
||||
"The front.stopRecording() emits a timeline end time.");
|
||||
ok(typeof memoryEndTime === "number",
|
||||
"The front.stopRecording() emits a memory end time.");
|
||||
|
||||
ok(profilerEndTime > profilerStartTime,
|
||||
"The profilerEndTime is after profilerStartTime.");
|
||||
is(timelineEndTime, timelineStartTime,
|
||||
"The timelineEndTime is the same as timelineStartTime.");
|
||||
is(memoryEndTime, memoryStartTime,
|
||||
"The memoryEndTime is the same as memoryStartTime.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the recording model is populated correctly when using timeline
|
||||
* and memory actor mocks.
|
||||
*/
|
||||
|
||||
const WAIT_TIME = 1000;
|
||||
|
||||
let test = Task.async(function*() {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
|
||||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true
|
||||
});
|
||||
let { EVENTS, gFront, PerformanceController, PerformanceView } = panel.panelWin;
|
||||
|
||||
let { memory: memoryMock, timeline: timelineMock } = gFront.getMocksInUse();
|
||||
ok(memoryMock, "memory should be mocked.");
|
||||
ok(timelineMock, "timeline should be mocked.");
|
||||
|
||||
yield startRecording(panel);
|
||||
busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
|
||||
yield stopRecording(panel);
|
||||
|
||||
let {
|
||||
label, duration, markers, frames, memory, ticks, allocations, profile
|
||||
} = PerformanceController.getCurrentRecording().getAllData();
|
||||
|
||||
is(label, "", "Empty label for mock.");
|
||||
is(typeof duration, "number", "duration is a number");
|
||||
ok(duration > 0, "duration is not 0");
|
||||
|
||||
isEmptyArray(markers, "markers");
|
||||
isEmptyArray(frames, "frames");
|
||||
isEmptyArray(memory, "memory");
|
||||
isEmptyArray(ticks, "ticks");
|
||||
isEmptyArray(allocations.sites, "allocations.sites");
|
||||
isEmptyArray(allocations.timestamps, "allocations.timestamps");
|
||||
isEmptyArray(allocations.frames, "allocations.frames");
|
||||
isEmptyArray(allocations.counts, "allocations.counts");
|
||||
|
||||
let sampleCount = 0;
|
||||
|
||||
for (let thread of profile.threads) {
|
||||
info("Checking thread: " + thread.name);
|
||||
|
||||
for (let sample of thread.samples) {
|
||||
sampleCount++;
|
||||
|
||||
if (sample.frames[0].location != "(root)") {
|
||||
ok(false, "The sample " + sample.toSource() + " doesn't have a root node.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok(sampleCount > 0,
|
||||
"At least some samples have been iterated over, checking for root nodes.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
});
|
||||
|
||||
function isEmptyArray (array, name) {
|
||||
ok(Array.isArray(array), `${name} is an array`);
|
||||
is(array.length, 0, `${name} is empty`);
|
||||
}
|
@ -12,6 +12,7 @@ let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
let { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
|
||||
let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let { merge } = devtools.require("sdk/util/object");
|
||||
let { getPerformanceActorsConnection, PerformanceFront } = devtools.require("devtools/performance/front");
|
||||
|
||||
let nsIProfilerModule = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
|
||||
@ -161,7 +162,7 @@ function test () {
|
||||
Task.spawn(spawnTest).then(finish, handleError);
|
||||
}
|
||||
|
||||
function initBackend(aUrl) {
|
||||
function initBackend(aUrl, targetOps={}) {
|
||||
info("Initializing a performance front.");
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
@ -175,6 +176,13 @@ function initBackend(aUrl) {
|
||||
|
||||
yield target.makeRemote();
|
||||
|
||||
// Attach addition options to `target`. This is used to force mock fronts
|
||||
// to smokescreen test different servers where memory or timeline actors
|
||||
// may not exist. Possible options that will actually work:
|
||||
// TEST_MOCK_MEMORY_ACTOR = true
|
||||
// TEST_MOCK_TIMELINE_ACTOR = true
|
||||
merge(target, targetOps);
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
|
||||
let connection = getPerformanceActorsConnection(target);
|
||||
@ -185,7 +193,7 @@ function initBackend(aUrl) {
|
||||
});
|
||||
}
|
||||
|
||||
function initPerformance(aUrl, selectedTool="performance") {
|
||||
function initPerformance(aUrl, selectedTool="performance", targetOps={}) {
|
||||
info("Initializing a performance pane.");
|
||||
|
||||
return Task.spawn(function*() {
|
||||
@ -194,6 +202,13 @@ function initPerformance(aUrl, selectedTool="performance") {
|
||||
|
||||
yield target.makeRemote();
|
||||
|
||||
// Attach addition options to `target`. This is used to force mock fronts
|
||||
// to smokescreen test different servers where memory or timeline actors
|
||||
// may not exist. Possible options that will actually work:
|
||||
// TEST_MOCK_MEMORY_ACTOR = true
|
||||
// TEST_MOCK_TIMELINE_ACTOR = true
|
||||
merge(target, targetOps);
|
||||
|
||||
let toolbox = yield gDevTools.showToolbox(target, selectedTool);
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
return { target, panel, toolbox };
|
||||
|
Loading…
Reference in New Issue
Block a user