зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1214066 - Add the ability to toggle allocation stack recording; r=jsantell
This commit is contained in:
Родитель
89efe3149f
Коммит
554bd61388
|
@ -0,0 +1,20 @@
|
|||
/* 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 { actions, ALLOCATION_RECORDING_OPTIONS } = require("../constants");
|
||||
|
||||
exports.toggleRecordingAllocationStacks = function (front) {
|
||||
return function* (dispatch, getState) {
|
||||
dispatch({ type: actions.TOGGLE_RECORD_ALLOCATION_STACKS_START });
|
||||
|
||||
if (getState().recordingAllocationStacks) {
|
||||
yield front.stopRecordingAllocations();
|
||||
} else {
|
||||
yield front.startRecordingAllocations(ALLOCATION_RECORDING_OPTIONS);
|
||||
}
|
||||
|
||||
dispatch({ type: actions.TOGGLE_RECORD_ALLOCATION_STACKS_END });
|
||||
};
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'allocations.js',
|
||||
'breakdown.js',
|
||||
'snapshot.js',
|
||||
)
|
||||
|
|
|
@ -122,4 +122,3 @@ const selectSnapshot = exports.selectSnapshot = function (snapshot) {
|
|||
snapshot
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { selectSnapshotAndRefresh, takeSnapshotAndCensus } = require("./actions/snapshot");
|
||||
const { toggleRecordingAllocationStacks } = require("./actions/allocations");
|
||||
const { setBreakdownAndRefresh } = require("./actions/breakdown");
|
||||
const { selectSnapshotAndRefresh, takeSnapshotAndCensus } = require("./actions/snapshot");
|
||||
const { breakdownNameToSpec, getBreakdownDisplayData } = require("./utils");
|
||||
const Toolbar = createFactory(require("./components/toolbar"));
|
||||
const List = createFactory(require("./components/list"));
|
||||
|
@ -31,7 +32,15 @@ const App = createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
let { dispatch, snapshots, front, heapWorker, breakdown } = this.props;
|
||||
let {
|
||||
dispatch,
|
||||
snapshots,
|
||||
front,
|
||||
heapWorker,
|
||||
breakdown,
|
||||
allocations,
|
||||
} = this.props;
|
||||
|
||||
let selectedSnapshot = snapshots.find(s => s.selected);
|
||||
|
||||
return (
|
||||
|
@ -42,6 +51,9 @@ const App = createClass({
|
|||
onTakeSnapshotClick: () => dispatch(takeSnapshotAndCensus(front, heapWorker)),
|
||||
onBreakdownChange: breakdown =>
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdownNameToSpec(breakdown))),
|
||||
onToggleRecordAllocationStacks: () =>
|
||||
dispatch(toggleRecordingAllocationStacks(front)),
|
||||
allocations
|
||||
}),
|
||||
|
||||
dom.div({ id: "memory-tool-container" }, [
|
||||
|
@ -66,7 +78,10 @@ const App = createClass({
|
|||
* and passed to components.
|
||||
*/
|
||||
function mapStateToProps (state) {
|
||||
return { snapshots: state.snapshots };
|
||||
return {
|
||||
allocations: state.allocations,
|
||||
snapshots: state.snapshots
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps)(App);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
const { DOM, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const models = require("../models");
|
||||
|
||||
const Toolbar = module.exports = createClass({
|
||||
displayName: "toolbar",
|
||||
propTypes: {
|
||||
|
@ -13,17 +15,38 @@ const Toolbar = module.exports = createClass({
|
|||
})).isRequired,
|
||||
onTakeSnapshotClick: PropTypes.func.isRequired,
|
||||
onBreakdownChange: PropTypes.func.isRequired,
|
||||
onToggleRecordAllocationStacks: PropTypes.func.isRequired,
|
||||
allocations: models.allocations
|
||||
},
|
||||
|
||||
render() {
|
||||
let { onTakeSnapshotClick, onBreakdownChange, breakdowns } = this.props;
|
||||
let {
|
||||
onTakeSnapshotClick,
|
||||
onBreakdownChange,
|
||||
breakdowns,
|
||||
onToggleRecordAllocationStacks,
|
||||
allocations,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
DOM.div({ className: "devtools-toolbar" }, [
|
||||
DOM.button({ className: `take-snapshot devtools-button`, onClick: onTakeSnapshotClick }),
|
||||
|
||||
DOM.select({
|
||||
className: `select-breakdown`,
|
||||
onChange: e => onBreakdownChange(e.target.value),
|
||||
}, breakdowns.map(({ name, displayName }) => DOM.option({ value: name }, displayName)))
|
||||
}, breakdowns.map(({ name, displayName }) => DOM.option({ value: name }, displayName))),
|
||||
|
||||
DOM.label({}, [
|
||||
DOM.input({
|
||||
type: "checkbox",
|
||||
checked: allocations.recording,
|
||||
disabled: allocations.togglingInProgress,
|
||||
onChange: onToggleRecordAllocationStacks,
|
||||
}),
|
||||
// TODO bug 1214799
|
||||
"Record allocation stacks"
|
||||
])
|
||||
])
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,9 +19,19 @@ actions.READ_SNAPSHOT_END = "read-snapshot-end";
|
|||
actions.TAKE_CENSUS_START = "take-census-start";
|
||||
actions.TAKE_CENSUS_END = "take-census-end";
|
||||
|
||||
// When requesting that the server start/stop recording allocation stacks.
|
||||
actions.TOGGLE_RECORD_ALLOCATION_STACKS_START = "toggle-record-allocation-stacks-start";
|
||||
actions.TOGGLE_RECORD_ALLOCATION_STACKS_END = "toggle-record-allocation-stacks-end";
|
||||
|
||||
// Fired by UI to select a snapshot to view.
|
||||
actions.SELECT_SNAPSHOT = "select-snapshot";
|
||||
|
||||
// Options passed to MemoryFront's startRecordingAllocations never change.
|
||||
exports.ALLOCATION_RECORDING_OPTIONS = {
|
||||
probability: 1,
|
||||
maxLogLength: 1
|
||||
};
|
||||
|
||||
const COUNT = { by: "count", count: true, bytes: true };
|
||||
const INTERNAL_TYPE = { by: "internalType", then: COUNT };
|
||||
const ALLOCATION_STACK = { by: "allocationStack", then: COUNT, noStack: COUNT };
|
||||
|
|
|
@ -51,9 +51,19 @@ let snapshotModel = exports.snapshot = PropTypes.shape({
|
|||
},
|
||||
});
|
||||
|
||||
let allocationsModel = exports.allocations = PropTypes.shape({
|
||||
// True iff we are recording allocation stacks right now.
|
||||
recording: PropTypes.bool.isRequired,
|
||||
// True iff we are in the process of toggling the recording of allocation
|
||||
// stacks on or off right now.
|
||||
togglingInProgress: PropTypes.bool.isRequired,
|
||||
});
|
||||
|
||||
let appModel = exports.app = {
|
||||
// {MemoryFront} Used to communicate with platform
|
||||
front: PropTypes.instanceOf(MemoryFront),
|
||||
// Allocations recording related data.
|
||||
allocations: allocationsModel,
|
||||
// {HeapAnalysesClient} Used to interface with snapshots
|
||||
heapWorker: PropTypes.instanceOf(HeapAnalysesClient),
|
||||
// The breakdown object DSL describing how we want
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/* 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";
|
||||
|
||||
exports.allocations = require("./reducers/allocations");
|
||||
exports.snapshots = require("./reducers/snapshots");
|
||||
exports.breakdown = require("./reducers/breakdown");
|
||||
exports.errors = require("./reducers/errors");
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* 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/. */
|
||||
|
||||
const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
const { actions } = require("../constants");
|
||||
|
||||
let handlers = Object.create(null);
|
||||
|
||||
handlers[actions.TOGGLE_RECORD_ALLOCATION_STACKS_START] = function (state, action) {
|
||||
assert(!state.togglingInProgress,
|
||||
"Changing recording state must not be reentrant.");
|
||||
|
||||
return {
|
||||
recording: !state.recording,
|
||||
togglingInProgress: true,
|
||||
};
|
||||
};
|
||||
|
||||
handlers[actions.TOGGLE_RECORD_ALLOCATION_STACKS_END] = function (state, action) {
|
||||
assert(state.togglingInProgress,
|
||||
"Should not complete changing recording state if we weren't changing "
|
||||
+ "recording state already.");
|
||||
|
||||
return {
|
||||
recording: state.recording,
|
||||
togglingInProgress: false,
|
||||
};
|
||||
};
|
||||
|
||||
const DEFAULT_ALLOCATIONS_STATE = {
|
||||
recording: false,
|
||||
togglingInProgress: false
|
||||
};
|
||||
|
||||
module.exports = function (state = DEFAULT_ALLOCATIONS_STATE, action) {
|
||||
let handle = handlers[action.type];
|
||||
if (handle) {
|
||||
return handle(state, action);
|
||||
}
|
||||
return state;
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'allocations.js',
|
||||
'breakdown.js',
|
||||
'errors.js',
|
||||
'snapshots.js',
|
||||
|
|
|
@ -28,6 +28,8 @@ function initDebugger () {
|
|||
}
|
||||
|
||||
function StubbedMemoryFront () {
|
||||
this.state = "detached";
|
||||
this.recordingAllocations = false;
|
||||
this.dbg = initDebugger();
|
||||
}
|
||||
|
||||
|
@ -43,6 +45,14 @@ StubbedMemoryFront.prototype.saveHeapSnapshot = expectState("attached", Task.asy
|
|||
return ThreadSafeChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
}), "saveHeapSnapshot");
|
||||
|
||||
StubbedMemoryFront.prototype.startRecordingAllocations = expectState("attached", Task.async(function* () {
|
||||
this.recordingAllocations = true;
|
||||
}));
|
||||
|
||||
StubbedMemoryFront.prototype.stopRecordingAllocations = expectState("attached", Task.async(function* () {
|
||||
this.recordingAllocations = false;
|
||||
}));
|
||||
|
||||
function waitUntilState (store, predicate) {
|
||||
let deferred = promise.defer();
|
||||
let unsubscribe = store.subscribe(check);
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests the action creator `setBreakdown()` for breakdown changing.
|
||||
* Does not test refreshing the census information, check `setBreakdownAndRefresh` action
|
||||
* for that.
|
||||
*/
|
||||
|
||||
let { toggleRecordingAllocationStacks } = require("devtools/client/memory/actions/allocations");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function *() {
|
||||
let front = new StubbedMemoryFront();
|
||||
let heapWorker = new HeapAnalysesClient();
|
||||
yield front.attach();
|
||||
let store = Store();
|
||||
const { getState, dispatch } = store;
|
||||
|
||||
equal(getState().allocations.recording, false, "not recording by default");
|
||||
equal(getState().allocations.togglingInProgress, false,
|
||||
"not in the process of toggling by default");
|
||||
|
||||
dispatch(toggleRecordingAllocationStacks(front));
|
||||
yield waitUntilState(store, () => getState().allocations.togglingInProgress);
|
||||
ok(true, "`togglingInProgress` set to true when toggling on");
|
||||
yield waitUntilState(store, () => !getState().allocations.togglingInProgress);
|
||||
|
||||
equal(getState().allocations.recording, true, "now we are recording");
|
||||
ok(front.recordingAllocations, "front is recording too");
|
||||
|
||||
dispatch(toggleRecordingAllocationStacks(front));
|
||||
yield waitUntilState(store, () => getState().allocations.togglingInProgress);
|
||||
ok(true, "`togglingInProgress` set to true when toggling off");
|
||||
yield waitUntilState(store, () => !getState().allocations.togglingInProgress);
|
||||
|
||||
equal(getState().allocations.recording, false, "now we are not recording");
|
||||
ok(front.recordingAllocations, "front is not recording anymore");
|
||||
});
|
|
@ -5,6 +5,7 @@ tail =
|
|||
firefox-appdir = browser
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
|
||||
[test_action-toggle-recording-allocations.js]
|
||||
[test_action-select-snapshot.js]
|
||||
[test_action-set-breakdown.js]
|
||||
[test_action-set-breakdown-and-refresh-01.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче