Files
tubestation/browser/devtools/performance/views/overview.js

212 lines
7.2 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";
// No sense updating the overview more often than receiving data from the
// backend. Make sure this isn't lower than DEFAULT_TIMELINE_DATA_PULL_TIMEOUT
// in toolkit/devtools/server/actors/timeline.js
const OVERVIEW_UPDATE_INTERVAL = 200; // ms
const FRAMERATE_GRAPH_LOW_RES_INTERVAL = 100; // ms
const FRAMERATE_GRAPH_HIGH_RES_INTERVAL = 16; // ms
const FRAMERATE_GRAPH_HEIGHT = 45; // px
const MARKERS_GRAPH_HEADER_HEIGHT = 12; // px
const MARKERS_GRAPH_BODY_HEIGHT = 45; // 9px * 5 groups
const MARKERS_GROUP_VERTICAL_PADDING = 3.5; // px
const MEMORY_GRAPH_HEIGHT = 30; // px
const GRAPH_SCROLL_EVENTS_DRAIN = 50; // ms
/**
* 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 *() {
this._onRecordingStarted = this._onRecordingStarted.bind(this);
this._onRecordingStopped = this._onRecordingStopped.bind(this);
this._onRecordingTick = this._onRecordingTick.bind(this);
this._onGraphMouseUp = this._onGraphMouseUp.bind(this);
this._onGraphScroll = this._onGraphScroll.bind(this);
yield this._showFramerateGraph();
yield this._showMarkersGraph();
yield this._showMemoryGraph();
this.framerateGraph.on("mouseup", this._onGraphMouseUp);
this.framerateGraph.on("scroll", this._onGraphScroll);
this.markersOverview.on("mouseup", this._onGraphMouseUp);
this.markersOverview.on("scroll", this._onGraphScroll);
this.memoryOverview.on("mouseup", this._onGraphMouseUp);
this.memoryOverview.on("scroll", this._onGraphScroll);
PerformanceController.on(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
}),
/**
* Unbinds events.
*/
destroy: function () {
this.framerateGraph.off("mouseup", this._onGraphMouseUp);
this.framerateGraph.off("scroll", this._onGraphScroll);
this.markersOverview.off("mouseup", this._onGraphMouseUp);
this.markersOverview.off("scroll", this._onGraphScroll);
this.memoryOverview.off("mouseup", this._onGraphMouseUp);
this.memoryOverview.off("scroll", this._onGraphScroll);
clearNamedTimeout("graph-scroll");
PerformanceController.off(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
},
/**
* Sets up the framerate graph.
*/
_showFramerateGraph: Task.async(function *() {
this.framerateGraph = new LineGraphWidget($("#time-framerate"), L10N.getStr("graphs.fps"));
this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
yield this.framerateGraph.ready();
}),
/**
* Sets up the markers overivew graph.
*/
_showMarkersGraph: Task.async(function *() {
this.markersOverview = new MarkersOverview($("#markers-overview"));
this.markersOverview.headerHeight = MARKERS_GRAPH_HEADER_HEIGHT;
this.markersOverview.bodyHeight = MARKERS_GRAPH_BODY_HEIGHT;
this.markersOverview.groupPadding = MARKERS_GROUP_VERTICAL_PADDING;
yield this.markersOverview.ready();
CanvasGraphUtils.linkAnimation(this.framerateGraph, this.markersOverview);
CanvasGraphUtils.linkSelection(this.framerateGraph, this.markersOverview);
}),
/**
* Sets up the memory overview graph.
*/
_showMemoryGraph: Task.async(function *() {
this.memoryOverview = new MemoryOverview($("#memory-overview"));
this.memoryOverview.fixedHeight = MEMORY_GRAPH_HEIGHT;
yield this.memoryOverview.ready();
CanvasGraphUtils.linkAnimation(this.framerateGraph, this.memoryOverview);
CanvasGraphUtils.linkSelection(this.framerateGraph, this.memoryOverview);
}),
/**
* 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 interval = PerformanceController.getInterval();
let markers = PerformanceController.getMarkers();
let memory = PerformanceController.getMemory();
let timestamps = PerformanceController.getTicks();
this.markersOverview.setData({ interval, markers });
this.emit(EVENTS.MARKERS_GRAPH_RENDERED);
this.memoryOverview.setData({ interval, memory });
this.emit(EVENTS.MEMORY_GRAPH_RENDERED);
yield this.framerateGraph.setDataFromTimestamps(timestamps, resolution);
this.emit(EVENTS.FRAMERATE_GRAPH_RENDERED);
// Finished rendering all graphs in this overview.
this.emit(EVENTS.OVERVIEW_RENDERED);
}),
/**
* Called at most every OVERVIEW_UPDATE_INTERVAL milliseconds
* and uses data fetched from the controller to render
* data into all the corresponding overview graphs.
*/
_onRecordingTick: Task.async(function *() {
yield this.render(FRAMERATE_GRAPH_LOW_RES_INTERVAL);
this._prepareNextTick();
}),
/**
* Fired when the graph selection has changed. Called by
* mouseup and scroll events.
*/
_onSelectionChange: function () {
if (this.framerateGraph.hasSelection()) {
let { min: beginAt, max: endAt } = this.framerateGraph.getMappedSelection();
this.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { beginAt, endAt });
} else {
this.emit(EVENTS.OVERVIEW_RANGE_CLEARED);
}
},
/**
* Listener handling the "mouseup" event for the framerate graph.
* Fires an event to be handled elsewhere.
*/
_onGraphMouseUp: function () {
// Only fire a selection change event if the selection is actually enabled.
if (this.framerateGraph.selectionEnabled) {
this._onSelectionChange();
}
},
/**
* Listener handling the "scroll" event for the framerate graph.
* Fires a debounced event to be handled elsewhere.
*/
_onGraphScroll: function () {
setNamedTimeout("graph-scroll", GRAPH_SCROLL_EVENTS_DRAIN, () => {
this._onSelectionChange();
});
},
/**
* 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 starts.
*/
_onRecordingStarted: function () {
this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
this.framerateGraph.dropSelection();
this.framerateGraph.selectionEnabled = false;
this.markersOverview.selectionEnabled = false;
this.memoryOverview.selectionEnabled = false;
},
/**
* Called when recording stops.
*/
_onRecordingStopped: function () {
clearTimeout(this._timeoutId);
this._timeoutId = null;
this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
this.framerateGraph.selectionEnabled = true;
this.markersOverview.selectionEnabled = true;
this.memoryOverview.selectionEnabled = true;
}
};
// Decorates the OverviewView as an EventEmitter
EventEmitter.decorate(OverviewView);