--- a/browser/devtools/performance/performance-controller.js
+++ b/browser/devtools/performance/performance-controller.js
@@ -55,19 +55,18 @@ devtools.lazyImporter(this, "SideMenuWid
const BRANCH_NAME = "devtools.performance.ui.";
// Events emitted by various objects in the panel.
const EVENTS = {
// Fired by the OptionsView when a preference changes.
PREF_CHANGED: "Performance:PrefChanged",
- // Emitted by the PerformanceController or RecordingView
- // when a recording model is selected
- RECORDING_SELECTED: "Performance:RecordingSelected",
+ // Emitted by the PerformanceView when the state (display mode) changes.
+ UI_STATE_CHANGED: "Performance:UI:StateChanged",
// Emitted by the PerformanceView on clear button click
UI_CLEAR_RECORDINGS: "Performance:UI:ClearRecordings",
// Emitted by the PerformanceView on record button click
UI_START_RECORDING: "Performance:UI:StartRecording",
UI_STOP_RECORDING: "Performance:UI:StopRecording",
@@ -77,16 +76,20 @@ const EVENTS = {
UI_EXPORT_RECORDING: "Performance:UI:ExportRecording",
// When a recording is started or stopped via the PerformanceController
RECORDING_STARTED: "Performance:RecordingStarted",
RECORDING_STOPPED: "Performance:RecordingStopped",
RECORDING_WILL_START: "Performance:RecordingWillStart",
RECORDING_WILL_STOP: "Performance:RecordingWillStop",
+ // Emitted by the PerformanceController or RecordingView
+ // when a recording model is selected
+ RECORDING_SELECTED: "Performance:RecordingSelected",
+
// When recordings have been cleared out
RECORDINGS_CLEARED: "Performance:RecordingsCleared",
// When a recording is imported or exported via the PerformanceController
RECORDING_IMPORTED: "Performance:RecordingImported",
RECORDING_EXPORTED: "Performance:RecordingExported",
// When the PerformanceController has new recording data
@@ -236,17 +239,16 @@ let PerformanceController = {
/**
* Stops recording with the PerformanceFront. Emits `EVENTS.RECORDING_STOPPED`
* when the front has stopped recording.
*/
stopRecording: Task.async(function *() {
let recording = this._getLatestRecording();
this.emit(EVENTS.RECORDING_WILL_STOP, recording);
-
yield recording.stopRecording();
this.emit(EVENTS.RECORDING_STOPPED, recording);
}),
/**
* Saves the given recording to a file. Emits `EVENTS.RECORDING_EXPORTED`
* when the file was saved.
*
--- a/browser/devtools/performance/performance-view.js
+++ b/browser/devtools/performance/performance-view.js
@@ -24,17 +24,17 @@ let PerformanceView = {
{ deck: "#performance-view", pane: "#performance-view-content" },
{ deck: "#details-pane-container", pane: "#details-pane" }
]
},
/**
* Sets up the view with event binding and main subviews.
*/
- initialize: function () {
+ initialize: Task.async(function* () {
this._recordButton = $("#main-record-button");
this._importButton = $("#import-button");
this._clearButton = $("#clear-button");
this._onRecordButtonClick = this._onRecordButtonClick.bind(this);
this._onImportButtonClick = this._onImportButtonClick.bind(this);
this._onClearButtonClick = this._onClearButtonClick.bind(this);
this._lockRecordButton = this._lockRecordButton.bind(this);
@@ -54,61 +54,60 @@ let PerformanceView = {
PerformanceController.on(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.on(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
PerformanceController.on(EVENTS.RECORDING_STARTED, this._unlockRecordButton);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
this.setState("empty");
- return promise.all([
- RecordingsView.initialize(),
- OverviewView.initialize(),
- ToolbarView.initialize(),
- DetailsView.initialize()
- ]);
- },
+ // Initialize the ToolbarView first, because other views may need access
+ // to the OptionsView via the controller, to read prefs.
+ yield ToolbarView.initialize();
+ yield RecordingsView.initialize();
+ yield OverviewView.initialize();
+ yield DetailsView.initialize();
+ }),
/**
* Unbinds events and destroys subviews.
*/
- destroy: function () {
+ destroy: Task.async(function* () {
for (let button of $$(".record-button")) {
button.removeEventListener("click", this._onRecordButtonClick);
}
this._importButton.removeEventListener("click", this._onImportButtonClick);
PerformanceController.off(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.off(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
PerformanceController.off(EVENTS.RECORDING_STARTED, this._unlockRecordButton);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
- return promise.all([
- RecordingsView.destroy(),
- OverviewView.destroy(),
- ToolbarView.destroy(),
- DetailsView.destroy()
- ]);
- },
+ yield ToolbarView.destroy();
+ yield RecordingsView.destroy();
+ yield OverviewView.destroy();
+ yield DetailsView.destroy();
+ }),
/**
* Sets the state of the profiler view. Possible options are "empty",
* "recording", "recorded".
*/
setState: function (state) {
let viewConfig = this.states[state];
if (!viewConfig) {
throw new Error(`Invalid state for PerformanceView: ${state}`);
}
for (let { deck, pane } of viewConfig) {
$(deck).selectedPanel = $(pane);
}
this._state = state;
+ this.emit(EVENTS.UI_STATE_CHANGED, state);
},
/**
* Returns the state of the PerformanceView.
*/
getState: function () {
return this._state;
},
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -50,16 +50,17 @@ support-files =
[browser_perf-overview-render-02.js]
[browser_perf-overview-render-03.js]
[browser_perf-overview-selection-01.js]
[browser_perf-overview-selection-02.js]
[browser_perf-overview-selection-03.js]
[browser_perf-overview-time-interval.js]
[browser_perf-shared-connection-02.js]
[browser_perf-shared-connection-03.js]
+[browser_perf-states.js]
[browser_perf-ui-recording.js]
[browser_perf-recording-notices-01.js]
[browser_perf-recording-notices-02.js]
[browser_perf_recordings-io-01.js]
[browser_perf_recordings-io-02.js]
[browser_perf_recordings-io-03.js]
[browser_perf_recordings-io-04.js]
[browser_perf-range-changed-render.js]
--- a/browser/devtools/performance/test/browser_perf-allocations-to-samples.js
+++ b/browser/devtools/performance/test/browser_perf-allocations-to-samples.js
@@ -15,32 +15,29 @@ function test() {
finish();
}
let TEST_DATA = {
sites: [0, 0, 1, 2, 3],
timestamps: [50, 100, 150, 200, 250],
frames: [
- null,
- {
+ null, {
source: "A",
line: 1,
column: 2,
functionDisplayName: "x",
parent: 0
- },
- {
+ }, {
source: "B",
line: 3,
column: 4,
functionDisplayName: "y",
parent: 1
- },
- {
+ }, {
source: "C",
line: 5,
column: 6,
functionDisplayName: null,
parent: 2
}
],
counts: [11, 22, 33, 44]
--- a/browser/devtools/performance/test/browser_perf-clear-01.js
+++ b/browser/devtools/performance/test/browser_perf-clear-01.js
@@ -3,17 +3,17 @@
/**
* Tests that clearing recordings empties out the recordings list and toggles
* the empty notice state.
*/
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
- let { EVENTS, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
+ let { EVENTS, PerformanceController, PerformanceView, RecordingsView, OverviewView } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
yield startRecording(panel);
yield stopRecording(panel);
yield PerformanceController.clearRecordings();
--- a/browser/devtools/performance/test/browser_perf-details-02.js
+++ b/browser/devtools/performance/test/browser_perf-details-02.js
@@ -9,33 +9,33 @@ function spawnTest () {
let { EVENTS, DetailsView } = panel.panelWin;
let { WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
ok(DetailsView.isViewSelected(WaterfallView),
"The waterfall view is selected by default in the details view.");
let selected = DetailsView.whenViewSelected(JsCallTreeView);
let notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(JsCallTreeView),
"The waterfall view is now selected in the details view.");
selected = DetailsView.whenViewSelected(JsFlameGraphView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
- DetailsView.selectView("js-flamegraph");
+ yield DetailsView.selectView("js-flamegraph");
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(JsFlameGraphView),
"The flamegraph view is now selected in the details view.");
selected = DetailsView.whenViewSelected(WaterfallView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
- DetailsView.selectView("waterfall");
+ yield DetailsView.selectView("waterfall");
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(WaterfallView),
"The waterfall view is now selected in the details view.");
yield teardown(panel);
finish();
}
--- a/browser/devtools/performance/test/browser_perf-details-03.js
+++ b/browser/devtools/performance/test/browser_perf-details-03.js
@@ -35,16 +35,17 @@ function spawnTest () {
selected = DetailsView.whenViewSelected(WaterfallView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
Services.prefs.setBoolPref(MEMORY_PREF, false);
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(WaterfallView),
"The waterfall view is now selected when toggling off enable-memory when a memory panel is selected.");
+
Services.prefs.setBoolPref(MEMORY_PREF, true);
selected = DetailsView.whenViewSelected(MemoryFlameGraphView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
DetailsView.selectView("memory-flamegraph");
yield Promise.all([selected, notified]);
selected = DetailsView.whenViewSelected(WaterfallView);
--- a/browser/devtools/performance/test/browser_perf-details-calltree-render.js
+++ b/browser/devtools/performance/test/browser_perf-details-calltree-render.js
@@ -3,17 +3,17 @@
/**
* Tests that the call tree view renders content after recording.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-details-flamegraph-render.js
+++ b/browser/devtools/performance/test/browser_perf-details-flamegraph-render.js
@@ -3,17 +3,17 @@
/**
* Tests that the flamegraph view renders content after recording.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
- DetailsView.selectView("js-flamegraph");
+ yield DetailsView.selectView("js-flamegraph");
ok(DetailsView.isViewSelected(JsFlameGraphView), "The flamegraph is now selected.");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-details-memory-calltree-render.js
+++ b/browser/devtools/performance/test/browser_perf-details-memory-calltree-render.js
@@ -3,17 +3,17 @@
/**
* Tests that the memory call tree view renders content after recording.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
- DetailsView.selectView("memory-calltree");
+ yield DetailsView.selectView("memory-calltree");
ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-details-memory-flamegraph-render.js
+++ b/browser/devtools/performance/test/browser_perf-details-memory-flamegraph-render.js
@@ -3,17 +3,17 @@
/**
* Tests that the memory flamegraph view renders content after recording.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
- DetailsView.selectView("memory-flamegraph");
+ yield DetailsView.selectView("memory-flamegraph");
ok(DetailsView.isViewSelected(MemoryFlameGraphView), "The flamegraph is now selected.");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-front-basic-profiler-01.js
+++ b/browser/devtools/performance/test/browser_perf-front-basic-profiler-01.js
@@ -5,29 +5,51 @@
* Test basic functionality of PerformanceFront
*/
let WAIT_TIME = 1000;
function spawnTest () {
let { target, front } = yield initBackend(SIMPLE_URL);
- let { profilerStartTime, timelineStartTime } = yield front.startRecording();
+ let startData = yield front.startRecording();
+ let { profilerStartTime, timelineStartTime, memoryStartTime } = startData;
+
+ ok("profilerStartTime" in startData,
+ "A `profilerStartTime` property is properly set in the recording data.");
+ ok("timelineStartTime" in startData,
+ "A `timelineStartTime` property is properly set in the recording data.");
+ ok("memoryStartTime" in startData,
+ "A `memoryStartTime` property is properly set in the recording data.");
ok(profilerStartTime !== undefined,
"A `profilerStartTime` property exists in the recording data.");
ok(timelineStartTime !== undefined,
"A `timelineStartTime` property exists in the recording data.");
+ is(memoryStartTime, 0,
+ "A `memoryStartTime` property exists in the recording data, but it's 0.");
yield busyWait(WAIT_TIME);
- let { profile, profilerEndTime, timelineEndTime } = yield front.stopRecording();
+ let stopData = yield front.stopRecording();
+ let { profile, profilerEndTime, timelineEndTime, memoryEndTime } = stopData;
+
+ ok("profile" in stopData,
+ "A `profile` property is properly set in the recording data.");
+ ok("profilerEndTime" in stopData,
+ "A `profilerEndTime` property is properly set in the recording data.");
+ ok("timelineEndTime" in stopData,
+ "A `timelineEndTime` property is properly set in the recording data.");
+ ok("memoryEndTime" in stopData,
+ "A `memoryEndTime` property is properly set in the recording data.");
ok(profile,
"A `profile` property exists in the recording data.");
ok(profilerEndTime !== undefined,
"A `profilerEndTime` property exists in the recording data.");
ok(timelineEndTime !== undefined,
"A `timelineEndTime` property exists in the recording data.");
+ is(memoryEndTime, 0,
+ "A `memoryEndTime` property exists in the recording data, but it's 0.");
yield removeTab(target.tab);
finish();
}
--- a/browser/devtools/performance/test/browser_perf-front-basic-timeline-01.js
+++ b/browser/devtools/performance/test/browser_perf-front-basic-timeline-01.js
@@ -23,19 +23,17 @@ function spawnTest () {
ticks: Promise.defer()
};
front.on("markers", handler);
front.on("memory", handler);
front.on("ticks", handler);
yield front.startRecording({ withMemory: true, withTicks: true });
-
yield Promise.all(Object.keys(deferreds).map(type => deferreds[type].promise));
-
yield front.stopRecording();
is(counters.markers.length, 1, "one marker event fired.");
is(counters.memory.length, 3, "three memory events fired.");
is(counters.ticks.length, 3, "three ticks events fired.");
yield removeTab(target.tab);
finish();
--- a/browser/devtools/performance/test/browser_perf-front.js
+++ b/browser/devtools/performance/test/browser_perf-front.js
@@ -26,17 +26,19 @@ function spawnTest () {
"The front.startRecording() emits a memory start time.");
yield busyWait(WAIT_TIME);
let {
profilerEndTime,
timelineEndTime,
memoryEndTime
- } = yield front.stopRecording();
+ } = 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.");
--- a/browser/devtools/performance/test/browser_perf-jump-to-debugger-02.js
+++ b/browser/devtools/performance/test/browser_perf-jump-to-debugger-02.js
@@ -1,14 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests if the performance tool can jump to the debugger, when the source was already
- * loaded in that tool.
+ * Tests if the performance tool can jump to the debugger, when the source was
+ * already loaded in that tool.
*/
function spawnTest() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "jsdebugger");
let debuggerWin = panel.panelWin;
let debuggerEvents = debuggerWin.EVENTS;
let { DebuggerView } = debuggerWin;
let Sources = DebuggerView.Sources;
--- a/browser/devtools/performance/test/browser_perf-options-01.js
+++ b/browser/devtools/performance/test/browser_perf-options-01.js
@@ -3,17 +3,17 @@
/**
* Tests that toggling preferences before there are any recordings does not throw.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
// Manually call the _onPrefChanged function so we can catch an error
try {
JsCallTreeView._onPrefChanged(null, "invert-call-tree", true);
ok(true, "Toggling preferences before there are any recordings should not fail.");
} catch (e) {
ok(false, "Toggling preferences before there are any recordings should not fail.");
}
--- a/browser/devtools/performance/test/browser_perf-options-02.js
+++ b/browser/devtools/performance/test/browser_perf-options-02.js
@@ -3,17 +3,17 @@
/**
* Tests that toggling preferences during a recording does not throw.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
yield startRecording(panel);
// Manually call the _onPrefChanged function so we can catch an error
try {
JsCallTreeView._onPrefChanged(null, "invert-call-tree", true);
ok(true, "Toggling preferences during a recording should not fail.");
} catch (e) {
--- a/browser/devtools/performance/test/browser_perf-options-enable-memory-02.js
+++ b/browser/devtools/performance/test/browser_perf-options-enable-memory-02.js
@@ -20,16 +20,17 @@ function spawnTest () {
"The recording finished without tracking memory.");
is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
"The recording finished without tracking allocations.");
// Test starting with memory, and stopping without it.
yield startRecording(panel);
Services.prefs.setBoolPref(MEMORY_PREF, false);
yield stopRecording(panel);
+
is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, true,
"The recording finished with tracking memory.");
is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, true,
"The recording finished with tracking allocations.");
yield teardown(panel);
finish();
}
--- a/browser/devtools/performance/test/browser_perf-options-flatten-tree-recursion-01.js
+++ b/browser/devtools/performance/test/browser_perf-options-flatten-tree-recursion-01.js
@@ -1,21 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the js Flamegraphs gets rerendered when toggling `flatten-tree-recursion`
+ * Tests that the js flamegraphs get rerendered when toggling `flatten-tree-recursion`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
- DetailsView.selectView("js-flamegraph");
+ Services.prefs.setBoolPref(FLATTEN_PREF, true);
- Services.prefs.setBoolPref(FLATTEN_PREF, true);
+ yield DetailsView.selectView("js-flamegraph");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-options-flatten-tree-recursion-02.js
+++ b/browser/devtools/performance/test/browser_perf-options-flatten-tree-recursion-02.js
@@ -1,24 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the memory Flamegraphs gets rerendered when toggling `flatten-tree-recursion`
+ * Tests that the memory flamegraphs get rerendered when toggling `flatten-tree-recursion`
*/
function spawnTest () {
- // Enable memory to test
- Services.prefs.setBoolPref(MEMORY_PREF, true);
-
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
- DetailsView.selectView("memory-flamegraph");
+ // Enable memory to test
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+ Services.prefs.setBoolPref(FLATTEN_PREF, true);
- Services.prefs.setBoolPref(FLATTEN_PREF, true);
+ yield DetailsView.selectView("memory-flamegraph");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-options-invert-call-tree-01.js
+++ b/browser/devtools/performance/test/browser_perf-options-invert-call-tree-01.js
@@ -1,22 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the js call tree view is re-rendered after the
- * "invert-call-tree" pref is changed.
+ * Tests that the js call tree views get rerendered when toggling `invert-call-tree`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
Services.prefs.setBoolPref(INVERT_PREF, true);
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-options-invert-call-tree-02.js
+++ b/browser/devtools/performance/test/browser_perf-options-invert-call-tree-02.js
@@ -1,24 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the memory call tree view is re-rendered after the
- * "invert-call-tree" pref is changed.
+ * Tests that the memory call tree views get rerendered when toggling `invert-call-tree`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
// Enable memory to test
Services.prefs.setBoolPref(MEMORY_PREF, true);
Services.prefs.setBoolPref(INVERT_PREF, true);
- DetailsView.selectView("memory-calltree");
+ yield DetailsView.selectView("memory-calltree");
ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-options-show-idle-blocks-01.js
+++ b/browser/devtools/performance/test/browser_perf-options-show-idle-blocks-01.js
@@ -1,21 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the js Flamegraphs gets rerendered when toggling `show-idle-blocks`
+ * Tests that the js flamegraphs get rerendered when toggling `show-idle-blocks`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
- DetailsView.selectView("js-flamegraph");
+ Services.prefs.setBoolPref(IDLE_PREF, true);
- Services.prefs.setBoolPref(IDLE_PREF, true);
+ yield DetailsView.selectView("js-flamegraph");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-options-show-idle-blocks-02.js
+++ b/browser/devtools/performance/test/browser_perf-options-show-idle-blocks-02.js
@@ -1,23 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the memory Flamegraphs gets rerendered when toggling `show-idle-blocks`
+ * Tests that the memory flamegraphs get rerendered when toggling `show-idle-blocks`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
// Enable memory to test
Services.prefs.setBoolPref(MEMORY_PREF, true);
- DetailsView.selectView("memory-flamegraph");
+ Services.prefs.setBoolPref(IDLE_PREF, true);
- Services.prefs.setBoolPref(IDLE_PREF, true);
+ yield DetailsView.selectView("memory-flamegraph");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-options-show-platform-data-01.js
+++ b/browser/devtools/performance/test/browser_perf-options-show-platform-data-01.js
@@ -1,22 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the JsCallTree get rerendered when toggling `show-platform-data`
+ * Tests that the js call tree views get rerendered when toggling `show-platform-data`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
- let { EVENTS, DetailsView, JsFlameGraphView, JsCallTreeView } = panel.panelWin;
-
- DetailsView.selectView("js-calltree");
+ let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+ yield DetailsView.selectView("js-calltree");
+
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
yield stopRecording(panel);
yield rendered;
rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
--- a/browser/devtools/performance/test/browser_perf-options-show-platform-data-02.js
+++ b/browser/devtools/performance/test/browser_perf-options-show-platform-data-02.js
@@ -1,20 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests that the JsFlamegraphs get rerendered when toggling `show-platform-data`
+ * Tests that the js flamegraphs get rerendered when toggling `show-platform-data`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
- DetailsView.selectView("js-flamegraph");
+
+ yield DetailsView.selectView("js-flamegraph");
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
--- a/browser/devtools/performance/test/browser_perf-overview-render-01.js
+++ b/browser/devtools/performance/test/browser_perf-overview-render-01.js
@@ -3,16 +3,19 @@
/**
* Tests that the overview continuously renders content when recording.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
+ // Enable memory to test all the overview graphs.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+
yield startRecording(panel);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
]);
--- a/browser/devtools/performance/test/browser_perf-overview-render-02.js
+++ b/browser/devtools/performance/test/browser_perf-overview-render-02.js
@@ -4,18 +4,28 @@
/**
* Tests that the overview graphs cannot be selected during recording
* and that they're cleared upon rerecording.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
+ // Enable memory to test all the overview graphs.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+
yield startRecording(panel);
+ yield Promise.all([
+ once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.OVERVIEW_RENDERED),
+ ]);
+
ok("selectionEnabled" in OverviewView.framerateGraph,
"The selection should not be enabled for the framerate overview (1).");
is(OverviewView.framerateGraph.selectionEnabled, false,
"The selection should not be enabled for the framerate overview (2).");
is(OverviewView.framerateGraph.hasSelection(), false,
"The framerate overview shouldn't have a selection before recording.");
ok("selectionEnabled" in OverviewView.markersOverview,
--- a/browser/devtools/performance/test/browser_perf-overview-render-03.js
+++ b/browser/devtools/performance/test/browser_perf-overview-render-03.js
@@ -3,35 +3,32 @@
/**
* Tests that the overview graphs share the exact same width and scaling.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
- Services.prefs.setBoolPref("devtools.performance.ui.enable-memory", true);
- Services.prefs.setBoolPref("devtools.performance.ui.enable-framerate", true);
+ // Enable memory to test all the overview graphs.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
yield startRecording(panel);
let updated = 0;
OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
yield busyWait(100);
yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
yield waitUntil(() => PerformanceController.getCurrentRecording().getMemory().length);
yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
yield waitUntil(() => updated > 10);
yield stopRecording(panel);
- // Wait for the overview graph to be rerendered *after* recording.
- yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-
ok(OverviewView.markersOverview.width > 0,
"The overview's framerate graph has a width.");
ok(OverviewView.markersOverview.dataScaleX > 0,
"The overview's framerate graph has a data scale factor.");
ok(OverviewView.memoryOverview.width > 0,
"The overview's framerate graph has a width.");
ok(OverviewView.memoryOverview.dataDuration > 0,
--- a/browser/devtools/performance/test/browser_perf-overview-selection-01.js
+++ b/browser/devtools/performance/test/browser_perf-overview-selection-01.js
@@ -6,24 +6,24 @@
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
let startTime, endTime, params, _;
yield startRecording(panel);
- // Wait for the overview graph to be rendered while recording.
- yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
+ yield Promise.all([
+ once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.OVERVIEW_RENDERED)
+ ]);
yield stopRecording(panel);
- // Wait for the overview graph to be rerendered *after* recording.
- yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-
let graph = OverviewView.markersOverview;
let MAX = graph.width;
// Select the first half of the graph
let results = onceSpread(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
dragStart(graph, 0);
dragStop(graph, MAX / 2);
[_, { startTime, endTime }] = yield results;
--- a/browser/devtools/performance/test/browser_perf-overview-selection-02.js
+++ b/browser/devtools/performance/test/browser_perf-overview-selection-02.js
@@ -2,21 +2,39 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the graphs' selection is correctly disabled or enabled.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
- let framerateGraph = OverviewView.framerateGraph;
+
+ // Enable memory to test all the overview graphs.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+
+ yield startRecording(panel);
+
+ yield Promise.all([
+ once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.OVERVIEW_RENDERED),
+ ]);
+
let markersOverview = OverviewView.markersOverview;
let memoryOverview = OverviewView.memoryOverview;
+ let framerateGraph = OverviewView.framerateGraph;
- yield startRecording(panel);
+ ok(markersOverview,
+ "The markers graph should have been created now.");
+ ok(memoryOverview,
+ "The memory graph should have been created now.");
+ ok(framerateGraph,
+ "The framerate graph should have been created now.");
ok(!framerateGraph.selectionEnabled,
"Selection shouldn't be enabled when the first recording started (1).");
ok(!markersOverview.selectionEnabled,
"Selection shouldn't be enabled when the first recording started (2).");
ok(!memoryOverview.selectionEnabled,
"Selection shouldn't be enabled when the first recording started (3).");
@@ -26,16 +44,23 @@ function spawnTest () {
"Selection should be enabled when the first recording finishes (1).");
ok(markersOverview.selectionEnabled,
"Selection should be enabled when the first recording finishes (2).");
ok(memoryOverview.selectionEnabled,
"Selection should be enabled when the first recording finishes (3).");
yield startRecording(panel);
+ yield Promise.all([
+ once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.OVERVIEW_RENDERED),
+ ]);
+
ok(!framerateGraph.selectionEnabled,
"Selection shouldn't be enabled when the second recording started (1).");
ok(!markersOverview.selectionEnabled,
"Selection shouldn't be enabled when the second recording started (2).");
ok(!memoryOverview.selectionEnabled,
"Selection shouldn't be enabled when the second recording started (3).");
yield stopRecording(panel);
--- a/browser/devtools/performance/test/browser_perf-overview-selection-03.js
+++ b/browser/devtools/performance/test/browser_perf-overview-selection-03.js
@@ -2,25 +2,36 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the graphs' selections are linked.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
+
+ // Enable memory to test all the overview graphs.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+
+ yield startRecording(panel);
+
+ yield Promise.all([
+ once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.OVERVIEW_RENDERED),
+ ]);
+
+ yield stopRecording(panel);
+
let framerateGraph = OverviewView.framerateGraph;
let markersOverview = OverviewView.markersOverview;
let memoryOverview = OverviewView.memoryOverview;
-
let MAX = framerateGraph.width;
- yield startRecording(panel);
- yield stopRecording(panel);
-
// Perform a selection inside the framerate graph.
let selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
dragStart(framerateGraph, 0);
dragStop(framerateGraph, MAX / 2);
yield selected;
is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 2) + "})",
--- a/browser/devtools/performance/test/browser_perf-overview-time-interval.js
+++ b/browser/devtools/performance/test/browser_perf-overview-time-interval.js
@@ -19,21 +19,24 @@ function spawnTest () {
try {
OverviewView.getTimeInterval();
ok(false, "Getting the time interval shouldn't have worked.");
} catch (e) {
ok(true, "Getting the time interval didn't work, as expected.");
}
yield startRecording(panel);
- busyWait(100);
- let rendered = once(OverviewView, EVENTS.OVERVIEW_RENDERED);
+ yield Promise.all([
+ once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
+ once(OverviewView, EVENTS.OVERVIEW_RENDERED)
+ ]);
+
yield stopRecording(panel);
- yield rendered;
// Get/set the time interval and wait for the event propagation.
let notified = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
OverviewView.setTimeInterval({ startTime: 10, endTime: 20 });
yield notified;
let firstInterval = OverviewView.getTimeInterval();
--- a/browser/devtools/performance/test/browser_perf-range-changed-render.js
+++ b/browser/devtools/performance/test/browser_perf-range-changed-render.js
@@ -22,37 +22,37 @@ function spawnTest () {
yield stopRecording(panel);
let rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: 10 });
yield rendered;
ok(true, "Waterfall rerenders when a range in the overview graph is selected.");
rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
yield rendered;
ok(true, "Call tree rerenders after its corresponding pane is shown.");
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
- DetailsView.selectView("js-flamegraph");
+ yield DetailsView.selectView("js-flamegraph");
yield rendered;
ok(true, "Flamegraph rerenders after its corresponding pane is shown.");
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
OverviewView.emit(EVENTS.OVERVIEW_RANGE_CLEARED);
yield rendered;
ok(true, "Flamegraph rerenders when a range in the overview graph is removed.");
rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
- DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-calltree");
yield rendered;
ok(true, "Call tree rerenders after its corresponding pane is shown.");
rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
- DetailsView.selectView("waterfall");
+ yield DetailsView.selectView("waterfall");
yield rendered;
ok(true, "Waterfall rerenders after its corresponding pane is shown.");
is(updatedWaterfall, 3, "WaterfallView rerendered 3 times.");
is(updatedCallTree, 2, "JsCallTreeView rerendered 2 times.");
is(updatedFlameGraph, 2, "JsFlameGraphView rerendered 2 times.");
yield teardown(panel);
--- a/browser/devtools/performance/test/browser_perf-recording-selected-04.js
+++ b/browser/devtools/performance/test/browser_perf-recording-selected-04.js
@@ -3,20 +3,33 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that all components can get rerendered for a profile when switching.
*/
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
- let { $, EVENTS, PerformanceController, DetailsSubview, RecordingsView } = panel.panelWin;
+ let { $, EVENTS, PerformanceController, DetailsView, DetailsSubview, RecordingsView } = panel.panelWin;
+
+ // Enable memory to test the memory-calltree and memory-flamegraph.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+ // Need to allow widgets to be updated while hidden, otherwise we can't use
+ // `waitForWidgetsRendered`.
DetailsSubview.canUpdateWhileHidden = true;
+ // Cycle through all the views to initialize them, otherwise we can't use
+ // `waitForWidgetsRendered`. The waterfall is shown by default, but all the
+ // other views are created lazily, so won't emit any events.
+ yield DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-flamegraph");
+ yield DetailsView.selectView("memory-calltree");
+ yield DetailsView.selectView("memory-flamegraph");
+
yield startRecording(panel);
yield stopRecording(panel);
yield startRecording(panel);
yield stopRecording(panel);
let rerender = waitForWidgetsRendered(panel);
RecordingsView.selectedIndex = 0;
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-states.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that view states and lazy component intialization works.
+ */
+function spawnTest () {
+ let { panel } = yield initPerformance(SIMPLE_URL);
+ let { EVENTS, PerformanceView, OverviewView, DetailsView } = panel.panelWin;
+
+ is(PerformanceView.getState(), "empty",
+ "The intial state of the performance panel view is correct.");
+
+ ok(!("markersOverview" in OverviewView),
+ "The markers graph should not have been created yet.");
+ ok(!("memoryOverview" in OverviewView),
+ "The memory graph should not have been created yet.");
+ ok(!("framerateGraph" in OverviewView),
+ "The framerate graph should not have been created yet.");
+
+ ok(DetailsView.components["waterfall"].initialized,
+ "The waterfall detail view should have been created by default.");
+ ok(!DetailsView.components["js-calltree"].initialized,
+ "The js-calltree detail view should not have been created yet.");
+ ok(!DetailsView.components["js-flamegraph"].initialized,
+ "The js-flamegraph detail view should not have been created yet.");
+ ok(!DetailsView.components["memory-calltree"].initialized,
+ "The memory-calltree detail view should not have been created yet.");
+ ok(!DetailsView.components["memory-flamegraph"].initialized,
+ "The memory-flamegraph detail view should not have been created yet.");
+
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+
+ ok(!("markersOverview" in OverviewView),
+ "The markers graph should still not have been created yet.");
+ ok(!("memoryOverview" in OverviewView),
+ "The memory graph should still not have been created yet.");
+ ok(!("framerateGraph" in OverviewView),
+ "The framerate graph should still not have been created yet.");
+
+ let stateChanged = once(PerformanceView, EVENTS.UI_STATE_CHANGED);
+ yield startRecording(panel);
+ yield stateChanged;
+
+ is(PerformanceView.getState(), "recording",
+ "The current state of the performance panel view is 'recording'.");
+ ok(OverviewView.memoryOverview,
+ "The memory graph should have been created now.");
+ ok(OverviewView.framerateGraph,
+ "The framerate graph should have been created now.");
+
+ stateChanged = once(PerformanceView, EVENTS.UI_STATE_CHANGED);
+ yield stopRecording(panel);
+ yield stateChanged;
+
+ is(PerformanceView.getState(), "recorded",
+ "The current state of the performance panel view is 'recorded'.");
+ ok(!DetailsView.components["js-calltree"].initialized,
+ "The js-calltree detail view should still not have been created yet.");
+ ok(!DetailsView.components["js-flamegraph"].initialized,
+ "The js-flamegraph detail view should still not have been created yet.");
+ ok(!DetailsView.components["memory-calltree"].initialized,
+ "The memory-calltree detail view should still not have been created yet.");
+ ok(!DetailsView.components["memory-flamegraph"].initialized,
+ "The memory-flamegraph detail view should still not have been created yet.");
+
+ yield DetailsView.selectView("js-calltree");
+
+ is(PerformanceView.getState(), "recorded",
+ "The current state of the performance panel view is still 'recorded'.");
+ ok(DetailsView.components["js-calltree"].initialized,
+ "The js-calltree detail view should still have been created now.");
+ ok(!DetailsView.components["js-flamegraph"].initialized,
+ "The js-flamegraph detail view should still not have been created yet.");
+ ok(!DetailsView.components["memory-calltree"].initialized,
+ "The memory-calltree detail view should still not have been created yet.");
+ ok(!DetailsView.components["memory-flamegraph"].initialized,
+ "The memory-flamegraph detail view should still not have been created yet.");
+
+ yield DetailsView.selectView("memory-calltree");
+
+ is(PerformanceView.getState(), "recorded",
+ "The current state of the performance panel view is still 'recorded'.");
+ ok(DetailsView.components["js-calltree"].initialized,
+ "The js-calltree detail view should still register as being created.");
+ ok(!DetailsView.components["js-flamegraph"].initialized,
+ "The js-flamegraph detail view should still not have been created yet.");
+ ok(DetailsView.components["memory-calltree"].initialized,
+ "The memory-calltree detail view should still have been created now.");
+ ok(!DetailsView.components["memory-flamegraph"].initialized,
+ "The memory-flamegraph detail view should still not have been created yet.");
+
+ yield teardown(panel);
+ finish();
+}
--- a/browser/devtools/performance/test/browser_perf_recordings-io-01.js
+++ b/browser/devtools/performance/test/browser_perf_recordings-io-01.js
@@ -2,18 +2,31 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the performance tool is able to save and load recordings.
*/
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
- let { EVENTS, PerformanceController, DetailsSubview } = panel.panelWin;
+ let { EVENTS, PerformanceController, DetailsView, DetailsSubview } = panel.panelWin;
+
+ // Enable memory to test the memory-calltree and memory-flamegraph.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+ // Cycle through all the views to initialize them, otherwise we can't use
+ // `waitForWidgetsRendered`. The waterfall is shown by default, but all the
+ // other views are created lazily, so won't emit any events.
+ yield DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-flamegraph");
+ yield DetailsView.selectView("memory-calltree");
+ yield DetailsView.selectView("memory-flamegraph");
+
+ // Need to allow widgets to be updated while hidden, otherwise we can't use
+ // `waitForWidgetsRendered`.
DetailsSubview.canUpdateWhileHidden = true;
yield startRecording(panel);
yield stopRecording(panel);
// Verify original recording.
let originalData = PerformanceController.getCurrentRecording().getAllData();
--- a/browser/devtools/performance/test/browser_perf_recordings-io-04.js
+++ b/browser/devtools/performance/test/browser_perf_recordings-io-04.js
@@ -3,18 +3,31 @@
/**
* Tests if the performance tool can import profiler data from the
* original profiler tool.
*/
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
- let { EVENTS, PerformanceController, DetailsSubview } = panel.panelWin;
+ let { EVENTS, PerformanceController, DetailsView, DetailsSubview } = panel.panelWin;
+
+ // Enable memory to test the memory-calltree and memory-flamegraph.
+ Services.prefs.setBoolPref(MEMORY_PREF, true);
+ // Cycle through all the views to initialize them, otherwise we can't use
+ // `waitForWidgetsRendered`. The waterfall is shown by default, but all the
+ // other views are created lazily, so won't emit any events.
+ yield DetailsView.selectView("js-calltree");
+ yield DetailsView.selectView("js-flamegraph");
+ yield DetailsView.selectView("memory-calltree");
+ yield DetailsView.selectView("memory-flamegraph");
+
+ // Need to allow widgets to be updated while hidden, otherwise we can't use
+ // `waitForWidgetsRendered`.
DetailsSubview.canUpdateWhileHidden = true;
yield startRecording(panel);
yield stopRecording(panel);
// Get data from the current profiler
let data = PerformanceController.getCurrentRecording().getAllData();
--- a/browser/devtools/performance/test/head.js
+++ b/browser/devtools/performance/test/head.js
@@ -250,31 +250,38 @@ function* startRecording(panel) {
let win = panel.panelWin;
let clicked = panel.panelWin.PerformanceView.once(win.EVENTS.UI_START_RECORDING);
let willStart = panel.panelWin.PerformanceController.once(win.EVENTS.RECORDING_WILL_START);
let hasStarted = panel.panelWin.PerformanceController.once(win.EVENTS.RECORDING_STARTED);
let button = win.$("#main-record-button");
ok(!button.hasAttribute("checked"),
"The record button should not be checked yet.");
-
ok(!button.hasAttribute("locked"),
"The record button should not be locked yet.");
click(win, button);
-
yield clicked;
ok(button.hasAttribute("checked"),
"The record button should now be checked.");
ok(button.hasAttribute("locked"),
"The record button should be locked.");
yield willStart;
+ let stateChanged = once(win.PerformanceView, win.EVENTS.UI_STATE_CHANGED);
+
yield hasStarted;
+ let overviewRendered = once(win.OverviewView, win.EVENTS.OVERVIEW_RENDERED);
+
+ yield stateChanged;
+ yield overviewRendered;
+
+ is(win.PerformanceView.getState(), "recording",
+ "The current state is 'recording'.");
ok(button.hasAttribute("checked"),
"The record button should still be checked.");
ok(!button.hasAttribute("locked"),
"The record button should not be locked.");
}
function* stopRecording(panel) {
@@ -285,50 +292,62 @@ function* stopRecording(panel) {
let button = win.$("#main-record-button");
ok(button.hasAttribute("checked"),
"The record button should already be checked.");
ok(!button.hasAttribute("locked"),
"The record button should not be locked yet.");
click(win, button);
-
yield clicked;
ok(!button.hasAttribute("checked"),
"The record button should not be checked.");
ok(button.hasAttribute("locked"),
"The record button should be locked.");
yield willStop;
+ let stateChanged = once(win.PerformanceView, win.EVENTS.UI_STATE_CHANGED);
+
yield hasStopped;
+ let overviewRendered = once(win.OverviewView, win.EVENTS.OVERVIEW_RENDERED);
+
+ yield stateChanged;
+ yield overviewRendered;
+
+ is(win.PerformanceView.getState(), "recorded",
+ "The current state is 'recorded'.");
ok(!button.hasAttribute("checked"),
"The record button should not be checked.");
ok(!button.hasAttribute("locked"),
"The record button should not be locked.");
}
function waitForWidgetsRendered(panel) {
let {
EVENTS,
OverviewView,
WaterfallView,
JsCallTreeView,
- JsFlameGraphView
+ JsFlameGraphView,
+ MemoryCallTreeView,
+ MemoryFlameGraphView,
} = panel.panelWin;
return Promise.all([
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
once(WaterfallView, EVENTS.WATERFALL_RENDERED),
once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED),
- once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED)
+ once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED),
+ once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED),
+ once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED),
]);
}
/**
* Waits until a predicate returns true.
*
* @param function predicate
* Invoked once in a while until it returns true.
--- a/browser/devtools/performance/views/details-abstract-subview.js
+++ b/browser/devtools/performance/views/details-abstract-subview.js
@@ -97,21 +97,20 @@ let DetailsSubview = {
this.render(OverviewView.getTimeInterval());
this.shouldUpdateWhenShown = false;
}
},
/**
* Fired when a preference in `devtools.performance.ui.` is changed.
*/
- _onPrefChanged: function (_, prefName, value) {
+ _onPrefChanged: function (_, prefName) {
// All detail views require a recording to be complete, so do not
// attempt to render if recording is in progress or does not exist.
let recording = PerformanceController.getCurrentRecording();
-
if (!recording || recording.isRecording()) {
return;
}
if (!~this.rerenderPrefs.indexOf(prefName)) {
return;
}
--- a/browser/devtools/performance/views/details.js
+++ b/browser/devtools/performance/views/details.js
@@ -30,79 +30,81 @@ let DetailsView = {
this._onViewToggle = this._onViewToggle.bind(this);
this.setAvailableViews = this.setAvailableViews.bind(this);
for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
button.addEventListener("command", this._onViewToggle);
}
- for (let [_, { view }] of Iterator(this.components)) {
- yield view.initialize();
- }
+ yield this.selectView(DEFAULT_DETAILS_SUBVIEW);
+ this.setAvailableViews();
- this.selectView(DEFAULT_DETAILS_SUBVIEW);
- this.setAvailableViews();
PerformanceController.on(EVENTS.PREF_CHANGED, this.setAvailableViews);
}),
/**
* Unbinds events, destroys subviews.
*/
destroy: Task.async(function *() {
for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
button.removeEventListener("command", this._onViewToggle);
}
- for (let [_, { view }] of Iterator(this.components)) {
- yield view.destroy();
+ for (let [_, component] of Iterator(this.components)) {
+ component.initialized && (yield component.view.destroy());
}
+
PerformanceController.off(EVENTS.PREF_CHANGED, this.setAvailableViews);
}),
/**
* Sets the possible views based off of prefs by hiding/showing the
* buttons that select them and going to default view if currently selected.
* Called when a preference changes in `devtools.performance.ui.`.
*/
setAvailableViews: function () {
for (let [name, { view, pref }] of Iterator(this.components)) {
if (!pref) {
continue;
}
let value = PerformanceController.getPref(pref);
$(`toolbarbutton[data-view=${name}]`).hidden = !value;
- // If the view is currently selected and not enabled, go back to the default view
+ // If the view is currently selected and not enabled, go back to the
+ // default view.
if (!value && this.isViewSelected(view)) {
this.selectView(DEFAULT_DETAILS_SUBVIEW);
}
}
},
/**
* Select one of the DetailView's subviews to be rendered,
* hiding the others.
*
* @param String viewName
* Name of the view to be shown.
*/
- selectView: function (viewName) {
- this.el.selectedPanel = $("#" + this.components[viewName].id);
+ selectView: Task.async(function *(viewName) {
+ let component = this.components[viewName];
+ this.el.selectedPanel = $("#" + component.id);
+
+ yield this._whenViewInitialized(component);
for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
if (button.getAttribute("data-view") === viewName) {
button.setAttribute("checked", true);
} else {
button.removeAttribute("checked");
}
}
this.emit(EVENTS.DETAILS_VIEW_SELECTED, viewName);
- },
+ }),
/**
* Checks if the provided view is currently selected.
*
* @param object viewObject
* @return boolean
*/
isViewSelected: function(viewObject) {
@@ -129,16 +131,40 @@ let DetailsView = {
if (this.isViewSelected(viewObject)) {
return promise.resolve();
}
yield this.once(EVENTS.DETAILS_VIEW_SELECTED);
return this.whenViewSelected(viewObject);
}),
/**
+ * Initializes a subview if it wasn't already set up, and makes sure
+ * it's populated with recording data if there is some available.
+ *
+ * @param object component
+ * A component descriptor from DetailsView.components
+ */
+ _whenViewInitialized: Task.async(function *(component) {
+ if (component.initialized) {
+ return;
+ }
+ component.initialized = true;
+ yield component.view.initialize();
+
+ // If this view is initialized *after* a recording is shown, it won't display
+ // any data. Make sure it's populated by setting `shouldUpdateWhenShown`.
+ // All detail views require a recording to be complete, so do not
+ // attempt to render if recording is in progress or does not exist.
+ let recording = PerformanceController.getCurrentRecording();
+ if (recording && !recording.isRecording()) {
+ component.view.shouldUpdateWhenShown = true;
+ }
+ }),
+
+ /**
* Called when a view button is clicked.
*/
_onViewToggle: function (e) {
this.selectView(e.target.getAttribute("data-view"));
}
};
/**
--- a/browser/devtools/performance/views/overview.js
+++ b/browser/devtools/performance/views/overview.js
@@ -20,59 +20,45 @@ const MEMORY_GRAPH_HEIGHT = 30; // px
/**
* View handler for the overview panel's time view, displaying
* framerate, markers and memory over time.
*/
let OverviewView = {
/**
* Sets up the view with event binding.
*/
- initialize: Task.async(function *() {
+ initialize: function () {
this._onRecordingWillStart = this._onRecordingWillStart.bind(this);
this._onRecordingStarted = this._onRecordingStarted.bind(this);
this._onRecordingWillStop = this._onRecordingWillStop.bind(this);
this._onRecordingStopped = this._onRecordingStopped.bind(this);
this._onRecordingSelected = this._onRecordingSelected.bind(this);
this._onRecordingTick = this._onRecordingTick.bind(this);
this._onGraphSelecting = this._onGraphSelecting.bind(this);
this._onPrefChanged = this._onPrefChanged.bind(this);
- yield this._showMarkersGraph();
- yield this._showMemoryGraph();
- yield this._showFramerateGraph();
-
- this.markersOverview.on("selecting", this._onGraphSelecting);
-
- PerformanceController.on(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
-
- // Toggle the initial state of memory and framerate graph based off of
- // the prefs.
+ // Toggle the initial visibility of memory and framerate graph containers
+ // based off of prefs.
$("#memory-overview").hidden = !PerformanceController.getPref("enable-memory");
$("#time-framerate").hidden = !PerformanceController.getPref("enable-framerate");
PerformanceController.on(EVENTS.PREF_CHANGED, this._onPrefChanged);
+ PerformanceController.on(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.on(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.on(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
-
- // Populate this overview with some dummy initial data.
- this.markersOverview.setData({ duration: 1000, markers: [] });
- this.memoryOverview.setData([]);
- this.framerateGraph.setData([]);
- }),
+ },
/**
* Unbinds events.
*/
destroy: function () {
- this.markersOverview.off("selecting", this._onGraphSelecting);
-
+ PerformanceController.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
PerformanceController.off(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
- PerformanceController.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
PerformanceController.off(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.off(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
},
/**
* Sets the time interval selection for all graphs in this overview.
@@ -106,86 +92,108 @@ let OverviewView = {
}
let mapStart = () => 0;
let mapEnd = () => recording.getDuration();
let selection = this.markersOverview.getMappedSelection({ mapStart, mapEnd });
return { startTime: selection.min, endTime: selection.max };
},
/**
- * Sets up the framerate graph.
+ * Sets up the markers overivew graph, if needed.
+ *
+ * @return object
+ * A promise resolved to `true` when the graph was initialized.
*/
- _showFramerateGraph: Task.async(function *() {
- this.framerateGraph = new LineGraphWidget($("#time-framerate"), {
- metric: L10N.getStr("graphs.fps")
- });
- this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
- yield this.framerateGraph.ready();
- }),
-
- /**
- * Sets up the markers overivew graph.
- */
- _showMarkersGraph: Task.async(function *() {
+ _markersGraphAvailable: Task.async(function *() {
+ if (this.markersOverview) {
+ yield this.markersOverview.ready();
+ return true;
+ }
this.markersOverview = new MarkersOverview($("#markers-overview"), TIMELINE_BLUEPRINT);
this.markersOverview.headerHeight = MARKERS_GRAPH_HEADER_HEIGHT;
this.markersOverview.rowHeight = MARKERS_GRAPH_ROW_HEIGHT;
this.markersOverview.groupPadding = MARKERS_GROUP_VERTICAL_PADDING;
+ this.markersOverview.on("selecting", this._onGraphSelecting);
yield this.markersOverview.ready();
+ return true;
}),
/**
- * Sets up the memory overview graph.
+ * Sets up the memory overview graph, if allowed and needed.
+ *
+ * @return object
+ * A promise resolved to `true` if the graph was initialized and is
+ * ready to use, `false` if the graph is disabled.
*/
- _showMemoryGraph: Task.async(function *() {
+ _memoryGraphAvailable: Task.async(function *() {
+ if (!PerformanceController.getPref("enable-memory")) {
+ return false;
+ }
+ if (this.memoryOverview) {
+ yield this.memoryOverview.ready();
+ return true;
+ }
this.memoryOverview = new MemoryOverview($("#memory-overview"));
this.memoryOverview.fixedHeight = MEMORY_GRAPH_HEIGHT;
yield this.memoryOverview.ready();
CanvasGraphUtils.linkAnimation(this.markersOverview, this.memoryOverview);
CanvasGraphUtils.linkSelection(this.markersOverview, this.memoryOverview);
+ return true;
}),
/**
- * Sets up the framerate graph.
+ * Sets up the framerate graph, if allowed and needed.
+ *
+ * @return object
+ * A promise resolved to `true` if the graph was initialized and is
+ * ready to use, `false` if the graph is disabled.
*/
- _showFramerateGraph: Task.async(function *() {
+ _framerateGraphAvailable: Task.async(function *() {
+ if (!PerformanceController.getPref("enable-framerate")) {
+ return false;
+ }
+ if (this.framerateGraph) {
+ yield this.framerateGraph.ready();
+ return true;
+ }
let metric = L10N.getStr("graphs.fps");
this.framerateGraph = new LineGraphWidget($("#time-framerate"), { metric });
this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
yield this.framerateGraph.ready();
CanvasGraphUtils.linkAnimation(this.markersOverview, this.framerateGraph);
CanvasGraphUtils.linkSelection(this.markersOverview, this.framerateGraph);
+ return true;
}),
/**
* Method for handling all the set up for rendering the overview graphs.
*
* @param number resolution
* The fps graph resolution. @see Graphs.jsm
*/
render: Task.async(function *(resolution) {
let recording = PerformanceController.getCurrentRecording();
let duration = recording.getDuration();
let markers = recording.getMarkers();
let memory = recording.getMemory();
let timestamps = recording.getTicks();
// Empty or older recordings might yield no markers, memory or timestamps.
- if (markers) {
+ if (markers && (yield this._markersGraphAvailable())) {
this.markersOverview.setData({ markers, duration });
this.emit(EVENTS.MARKERS_GRAPH_RENDERED);
}
- if (memory) {
+ if (memory && (yield this._memoryGraphAvailable())) {
this.memoryOverview.dataDuration = duration;
this.memoryOverview.setData(memory);
this.emit(EVENTS.MEMORY_GRAPH_RENDERED);
}
- if (timestamps) {
+ if (timestamps && (yield this._framerateGraphAvailable())) {
this.framerateGraph.dataDuration = duration;
yield this.framerateGraph.setDataFromTimestamps(timestamps, resolution);
this.emit(EVENTS.FRAMERATE_GRAPH_RENDERED);
}
// Finished rendering all graphs in this overview.
this.emit(EVENTS.OVERVIEW_RENDERED);
}),
@@ -196,16 +204,27 @@ let OverviewView = {
* data into all the corresponding overview graphs.
*/
_onRecordingTick: Task.async(function *() {
yield this.render(FRAMERATE_GRAPH_LOW_RES_INTERVAL);
this._prepareNextTick();
}),
/**
+ * Called to refresh the timer to keep firing _onRecordingTick.
+ */
+ _prepareNextTick: function () {
+ // Check here to see if there's still a _timeoutId, incase
+ // `stop` was called before the _prepareNextTick call was executed.
+ if (this._timeoutId) {
+ this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
+ }
+ },
+
+ /**
* Fired when the graph selection has changed. Called by
* mouseup and scroll events.
*/
_onGraphSelecting: function () {
let recording = PerformanceController.getCurrentRecording();
if (recording == null || this._stopSelectionChangeEventPropagation) {
return;
}
@@ -215,33 +234,22 @@ let OverviewView = {
if (interval.endTime - interval.startTime < 1) {
this.emit(EVENTS.OVERVIEW_RANGE_CLEARED);
} else {
this.emit(EVENTS.OVERVIEW_RANGE_SELECTED, interval);
}
},
/**
- * Called to refresh the timer to keep firing _onRecordingTick.
- */
- _prepareNextTick: function () {
- // Check here to see if there's still a _timeoutId, incase
- // `stop` was called before the _prepareNextTick call was executed.
- if (this._timeoutId) {
- this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
- }
- },
-
- /**
* Called when recording will start.
*/
- _onRecordingWillStart: function (_, recording) {
- this._checkSelection(recording);
- this.framerateGraph.dropSelection();
- },
+ _onRecordingWillStart: Task.async(function* (_, recording) {
+ yield this._checkSelection(recording);
+ this.markersOverview.dropSelection();
+ }),
/**
* Called when recording actually starts.
*/
_onRecordingStarted: function (_, recording) {
this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
},
@@ -251,50 +259,60 @@ let OverviewView = {
_onRecordingWillStop: function(_, recording) {
clearTimeout(this._timeoutId);
this._timeoutId = null;
},
/**
* Called when recording actually stops.
*/
- _onRecordingStopped: function (_, recording) {
- this._checkSelection(recording);
+ _onRecordingStopped: Task.async(function* (_, recording) {
this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
- },
+ yield this._checkSelection(recording);
+ }),
/**
* Called when a new recording is selected.
*/
- _onRecordingSelected: function (_, recording) {
+ _onRecordingSelected: Task.async(function* (_, recording) {
if (!recording) {
return;
}
- this.markersOverview.dropSelection();
- this._checkSelection(recording);
-
// If timeout exists, we have something recording, so
// this will still tick away at rendering. Otherwise, force a render.
if (!this._timeoutId) {
- this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
+ yield this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
}
- },
+ yield this._checkSelection(recording);
+ this.markersOverview.dropSelection();
+ }),
- _checkSelection: function (recording) {
+ /**
+ * Makes sure the selection is enabled or disabled in all the graphs,
+ * based on whether a recording currently exists and is not in progress.
+ */
+ _checkSelection: Task.async(function* (recording) {
let selectionEnabled = !recording.isRecording();
- this.markersOverview.selectionEnabled = selectionEnabled;
- this.memoryOverview.selectionEnabled = selectionEnabled;
- this.framerateGraph.selectionEnabled = selectionEnabled;
- },
+
+ if (yield this._markersGraphAvailable()) {
+ this.markersOverview.selectionEnabled = selectionEnabled;
+ }
+ if (yield this._memoryGraphAvailable()) {
+ this.memoryOverview.selectionEnabled = selectionEnabled;
+ }
+ if (yield this._framerateGraphAvailable()) {
+ this.framerateGraph.selectionEnabled = selectionEnabled;
+ }
+ }),
/**
* Called whenever a preference in `devtools.performance.ui.` changes. Used
* to toggle the visibility of memory and framerate graphs.
*/
- _onPrefChanged: function (_, prefName, value) {
+ _onPrefChanged: function (_, prefName) {
if (prefName === "enable-memory") {
$("#memory-overview").hidden = !PerformanceController.getPref("enable-memory");
}
if (prefName === "enable-framerate") {
$("#time-framerate").hidden = !PerformanceController.getPref("enable-framerate");
}
}
};