| Index: third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js
|
| index a4b1350c057abceb65823b281ddd36f2ae5b6822..0bd9ee63c92ef3234f87ba97309d61e00c5da29a 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js
|
| @@ -1,55 +1,53 @@
|
| // Copyright 2014 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
| -
|
| /**
|
| - * @constructor
|
| - * @extends {WebInspector.ProfileNode}
|
| - * @param {!ProfilerAgent.ProfileNode} node
|
| - * @param {number} sampleTime
|
| + * @unrestricted
|
| */
|
| -WebInspector.CPUProfileNode = function(node, sampleTime)
|
| -{
|
| +WebInspector.CPUProfileNode = class extends WebInspector.ProfileNode {
|
| + /**
|
| + * @param {!ProfilerAgent.ProfileNode} node
|
| + * @param {number} sampleTime
|
| + */
|
| + constructor(node, sampleTime) {
|
| var callFrame = node.callFrame || /** @type {!RuntimeAgent.CallFrame} */ ({
|
| - // Backward compatibility for old SamplingHeapProfileNode format.
|
| - functionName: node["functionName"],
|
| - scriptId: node["scriptId"],
|
| - url: node["url"],
|
| - lineNumber: node["lineNumber"] - 1,
|
| - columnNumber: node["columnNumber"] - 1
|
| - });
|
| - WebInspector.ProfileNode.call(this, callFrame);
|
| + // Backward compatibility for old SamplingHeapProfileNode format.
|
| + functionName: node['functionName'],
|
| + scriptId: node['scriptId'],
|
| + url: node['url'],
|
| + lineNumber: node['lineNumber'] - 1,
|
| + columnNumber: node['columnNumber'] - 1
|
| + });
|
| + super(callFrame);
|
| this.id = node.id;
|
| this.self = node.hitCount * sampleTime;
|
| this.positionTicks = node.positionTicks;
|
| // Compatibility: legacy backends could provide "no reason" for optimized functions.
|
| - this.deoptReason = node.deoptReason && node.deoptReason !== "no reason" ? node.deoptReason : null;
|
| -};
|
| -
|
| -WebInspector.CPUProfileNode.prototype = {
|
| - __proto__: WebInspector.ProfileNode.prototype
|
| + this.deoptReason = node.deoptReason && node.deoptReason !== 'no reason' ? node.deoptReason : null;
|
| + }
|
| };
|
|
|
| /**
|
| - * @constructor
|
| - * @extends {WebInspector.ProfileTreeModel}
|
| - * @param {!ProfilerAgent.Profile} profile
|
| + * @unrestricted
|
| */
|
| -WebInspector.CPUProfileDataModel = function(profile)
|
| -{
|
| - WebInspector.ProfileTreeModel.call(this);
|
| - var isLegacyFormat = !!profile["head"];
|
| +WebInspector.CPUProfileDataModel = class extends WebInspector.ProfileTreeModel {
|
| + /**
|
| + * @param {!ProfilerAgent.Profile} profile
|
| + */
|
| + constructor(profile) {
|
| + super();
|
| + var isLegacyFormat = !!profile['head'];
|
| if (isLegacyFormat) {
|
| - // Legacy format contains raw timestamps and start/stop times are in seconds.
|
| - this.profileStartTime = profile.startTime * 1000;
|
| - this.profileEndTime = profile.endTime * 1000;
|
| - this.timestamps = profile.timestamps;
|
| - this._compatibilityConversionHeadToNodes(profile);
|
| + // Legacy format contains raw timestamps and start/stop times are in seconds.
|
| + this.profileStartTime = profile.startTime * 1000;
|
| + this.profileEndTime = profile.endTime * 1000;
|
| + this.timestamps = profile.timestamps;
|
| + this._compatibilityConversionHeadToNodes(profile);
|
| } else {
|
| - // Current format encodes timestamps as deltas. Start/stop times are in microseconds.
|
| - this.profileStartTime = profile.startTime / 1000;
|
| - this.profileEndTime = profile.endTime / 1000;
|
| - this.timestamps = this._convertTimeDeltas(profile);
|
| + // Current format encodes timestamps as deltas. Start/stop times are in microseconds.
|
| + this.profileStartTime = profile.startTime / 1000;
|
| + this.profileEndTime = profile.endTime / 1000;
|
| + this.timestamps = this._convertTimeDeltas(profile);
|
| }
|
| this.samples = profile.samples;
|
| this.totalHitCount = 0;
|
| @@ -57,322 +55,311 @@ WebInspector.CPUProfileDataModel = function(profile)
|
| this.initialize(this.profileHead);
|
| this._extractMetaNodes();
|
| if (this.samples) {
|
| - this._buildIdToNodeMap();
|
| - this._sortSamples();
|
| - this._normalizeTimestamps();
|
| + this._buildIdToNodeMap();
|
| + this._sortSamples();
|
| + this._normalizeTimestamps();
|
| }
|
| -};
|
| + }
|
|
|
| -WebInspector.CPUProfileDataModel.prototype = {
|
| + /**
|
| + * @param {!ProfilerAgent.Profile} profile
|
| + */
|
| + _compatibilityConversionHeadToNodes(profile) {
|
| + if (!profile.head || profile.nodes)
|
| + return;
|
| + /** @type {!Array<!ProfilerAgent.ProfileNode>} */
|
| + var nodes = [];
|
| + convertNodesTree(profile.head);
|
| + profile.nodes = nodes;
|
| + delete profile.head;
|
| /**
|
| - * @param {!ProfilerAgent.Profile} profile
|
| + * @param {!ProfilerAgent.ProfileNode} node
|
| + * @return {number}
|
| */
|
| - _compatibilityConversionHeadToNodes: function(profile)
|
| - {
|
| - if (!profile.head || profile.nodes)
|
| - return;
|
| - /** @type {!Array<!ProfilerAgent.ProfileNode>} */
|
| - var nodes = [];
|
| - convertNodesTree(profile.head);
|
| - profile.nodes = nodes;
|
| - delete profile.head;
|
| - /**
|
| - * @param {!ProfilerAgent.ProfileNode} node
|
| - * @return {number}
|
| - */
|
| - function convertNodesTree(node)
|
| - {
|
| - nodes.push(node);
|
| - node.children = (/** @type {!Array<!ProfilerAgent.ProfileNode>} */(node.children)).map(convertNodesTree);
|
| - return node.id;
|
| - }
|
| - },
|
| + function convertNodesTree(node) {
|
| + nodes.push(node);
|
| + node.children = (/** @type {!Array<!ProfilerAgent.ProfileNode>} */ (node.children)).map(convertNodesTree);
|
| + return node.id;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {!ProfilerAgent.Profile} profile
|
| + * @return {?Array<number>}
|
| + */
|
| + _convertTimeDeltas(profile) {
|
| + if (!profile.timeDeltas)
|
| + return null;
|
| + var lastTimeUsec = profile.startTime;
|
| + var timestamps = new Array(profile.timeDeltas.length);
|
| + for (var i = 0; i < timestamps.length; ++i) {
|
| + lastTimeUsec += profile.timeDeltas[i];
|
| + timestamps[i] = lastTimeUsec;
|
| + }
|
| + return timestamps;
|
| + }
|
|
|
| + /**
|
| + * @param {!Array<!ProfilerAgent.ProfileNode>} nodes
|
| + * @return {!WebInspector.CPUProfileNode}
|
| + */
|
| + _translateProfileTree(nodes) {
|
| /**
|
| - * @param {!ProfilerAgent.Profile} profile
|
| - * @return {?Array<number>}
|
| + * @param {!ProfilerAgent.ProfileNode} node
|
| + * @return {boolean}
|
| */
|
| - _convertTimeDeltas: function(profile)
|
| - {
|
| - if (!profile.timeDeltas)
|
| - return null;
|
| - var lastTimeUsec = profile.startTime;
|
| - var timestamps = new Array(profile.timeDeltas.length);
|
| - for (var i = 0; i < timestamps.length; ++i) {
|
| - lastTimeUsec += profile.timeDeltas[i];
|
| - timestamps[i] = lastTimeUsec;
|
| - }
|
| - return timestamps;
|
| - },
|
| -
|
| + function isNativeNode(node) {
|
| + if (node.callFrame)
|
| + return !!node.callFrame.url && node.callFrame.url.startsWith('native ');
|
| + return !!node.url && node.url.startsWith('native ');
|
| + }
|
| /**
|
| * @param {!Array<!ProfilerAgent.ProfileNode>} nodes
|
| - * @return {!WebInspector.CPUProfileNode}
|
| */
|
| - _translateProfileTree: function(nodes)
|
| - {
|
| - /**
|
| - * @param {!ProfilerAgent.ProfileNode} node
|
| - * @return {boolean}
|
| - */
|
| - function isNativeNode(node)
|
| - {
|
| - if (node.callFrame)
|
| - return !!node.callFrame.url && node.callFrame.url.startsWith("native ");
|
| - return !!node.url && node.url.startsWith("native ");
|
| - }
|
| - /**
|
| - * @param {!Array<!ProfilerAgent.ProfileNode>} nodes
|
| - */
|
| - function buildChildrenFromParents(nodes)
|
| - {
|
| - if (nodes[0].children)
|
| - return;
|
| - nodes[0].children = [];
|
| - for (var i = 1; i < nodes.length; ++i) {
|
| - var node = nodes[i];
|
| - var parentNode = nodeByIdMap.get(node.parent);
|
| - if (parentNode.children)
|
| - parentNode.children.push(node.id);
|
| - else
|
| - parentNode.children = [node.id];
|
| - }
|
| - }
|
| - /** @type {!Map<number, !ProfilerAgent.ProfileNode>} */
|
| - var nodeByIdMap = new Map();
|
| - for (var i = 0; i < nodes.length; ++i) {
|
| - var node = nodes[i];
|
| - nodeByIdMap.set(node.id, node);
|
| - }
|
| - buildChildrenFromParents(nodes);
|
| - this.totalHitCount = nodes.reduce((acc, node) => acc + node.hitCount, 0);
|
| - var sampleTime = (this.profileEndTime - this.profileStartTime) / this.totalHitCount;
|
| - var keepNatives = !!WebInspector.moduleSetting("showNativeFunctionsInJSProfile").get();
|
| - var root = nodes[0];
|
| - /** @type {!Map<number, number>} */
|
| - var idMap = new Map([[root.id, root.id]]);
|
| - var resultRoot = new WebInspector.CPUProfileNode(root, sampleTime);
|
| - var parentNodeStack = root.children.map(() => resultRoot);
|
| - var sourceNodeStack = root.children.map(id => nodeByIdMap.get(id));
|
| - while (sourceNodeStack.length) {
|
| - var parentNode = parentNodeStack.pop();
|
| - var sourceNode = sourceNodeStack.pop();
|
| - if (!sourceNode.children)
|
| - sourceNode.children = [];
|
| - var targetNode = new WebInspector.CPUProfileNode(sourceNode, sampleTime);
|
| - if (keepNatives || !isNativeNode(sourceNode)) {
|
| - parentNode.children.push(targetNode);
|
| - parentNode = targetNode;
|
| - } else {
|
| - parentNode.self += targetNode.self;
|
| - }
|
| - idMap.set(sourceNode.id, parentNode.id);
|
| - parentNodeStack.push.apply(parentNodeStack, sourceNode.children.map(() => parentNode));
|
| - sourceNodeStack.push.apply(sourceNodeStack, sourceNode.children.map(id => nodeByIdMap.get(id)));
|
| - }
|
| - if (this.samples)
|
| - this.samples = this.samples.map(id => idMap.get(id));
|
| - return resultRoot;
|
| - },
|
| -
|
| - _sortSamples: function()
|
| - {
|
| - var timestamps = this.timestamps;
|
| - if (!timestamps)
|
| - return;
|
| - var samples = this.samples;
|
| - var indices = timestamps.map((x, index) => index);
|
| - indices.sort((a, b) => timestamps[a] - timestamps[b]);
|
| - for (var i = 0; i < timestamps.length; ++i) {
|
| - var index = indices[i];
|
| - if (index === i)
|
| - continue;
|
| - // Move items in a cycle.
|
| - var savedTimestamp = timestamps[i];
|
| - var savedSample = samples[i];
|
| - var currentIndex = i;
|
| - while (index !== i) {
|
| - samples[currentIndex] = samples[index];
|
| - timestamps[currentIndex] = timestamps[index];
|
| - currentIndex = index;
|
| - index = indices[index];
|
| - indices[currentIndex] = currentIndex;
|
| - }
|
| - samples[currentIndex] = savedSample;
|
| - timestamps[currentIndex] = savedTimestamp;
|
| - }
|
| - },
|
| -
|
| - _normalizeTimestamps: function()
|
| - {
|
| - var timestamps = this.timestamps;
|
| - if (!timestamps) {
|
| - // Support loading old CPU profiles that are missing timestamps.
|
| - // Derive timestamps from profile start and stop times.
|
| - var profileStartTime = this.profileStartTime;
|
| - var interval = (this.profileEndTime - profileStartTime) / this.samples.length;
|
| - timestamps = new Float64Array(this.samples.length + 1);
|
| - for (var i = 0; i < timestamps.length; ++i)
|
| - timestamps[i] = profileStartTime + i * interval;
|
| - this.timestamps = timestamps;
|
| - return;
|
| - }
|
| + function buildChildrenFromParents(nodes) {
|
| + if (nodes[0].children)
|
| + return;
|
| + nodes[0].children = [];
|
| + for (var i = 1; i < nodes.length; ++i) {
|
| + var node = nodes[i];
|
| + var parentNode = nodeByIdMap.get(node.parent);
|
| + if (parentNode.children)
|
| + parentNode.children.push(node.id);
|
| + else
|
| + parentNode.children = [node.id];
|
| + }
|
| + }
|
| + /** @type {!Map<number, !ProfilerAgent.ProfileNode>} */
|
| + var nodeByIdMap = new Map();
|
| + for (var i = 0; i < nodes.length; ++i) {
|
| + var node = nodes[i];
|
| + nodeByIdMap.set(node.id, node);
|
| + }
|
| + buildChildrenFromParents(nodes);
|
| + this.totalHitCount = nodes.reduce((acc, node) => acc + node.hitCount, 0);
|
| + var sampleTime = (this.profileEndTime - this.profileStartTime) / this.totalHitCount;
|
| + var keepNatives = !!WebInspector.moduleSetting('showNativeFunctionsInJSProfile').get();
|
| + var root = nodes[0];
|
| + /** @type {!Map<number, number>} */
|
| + var idMap = new Map([[root.id, root.id]]);
|
| + var resultRoot = new WebInspector.CPUProfileNode(root, sampleTime);
|
| + var parentNodeStack = root.children.map(() => resultRoot);
|
| + var sourceNodeStack = root.children.map(id => nodeByIdMap.get(id));
|
| + while (sourceNodeStack.length) {
|
| + var parentNode = parentNodeStack.pop();
|
| + var sourceNode = sourceNodeStack.pop();
|
| + if (!sourceNode.children)
|
| + sourceNode.children = [];
|
| + var targetNode = new WebInspector.CPUProfileNode(sourceNode, sampleTime);
|
| + if (keepNatives || !isNativeNode(sourceNode)) {
|
| + parentNode.children.push(targetNode);
|
| + parentNode = targetNode;
|
| + } else {
|
| + parentNode.self += targetNode.self;
|
| + }
|
| + idMap.set(sourceNode.id, parentNode.id);
|
| + parentNodeStack.push.apply(parentNodeStack, sourceNode.children.map(() => parentNode));
|
| + sourceNodeStack.push.apply(sourceNodeStack, sourceNode.children.map(id => nodeByIdMap.get(id)));
|
| + }
|
| + if (this.samples)
|
| + this.samples = this.samples.map(id => idMap.get(id));
|
| + return resultRoot;
|
| + }
|
|
|
| - // Convert samples from usec to msec
|
| - for (var i = 0; i < timestamps.length; ++i)
|
| - timestamps[i] /= 1000;
|
| - var averageSample = (timestamps.peekLast() - timestamps[0]) / (timestamps.length - 1);
|
| - // Add an extra timestamp used to calculate the last sample duration.
|
| - this.timestamps.push(timestamps.peekLast() + averageSample);
|
| - this.profileStartTime = timestamps[0];
|
| - this.profileEndTime = timestamps.peekLast();
|
| - },
|
| + _sortSamples() {
|
| + var timestamps = this.timestamps;
|
| + if (!timestamps)
|
| + return;
|
| + var samples = this.samples;
|
| + var indices = timestamps.map((x, index) => index);
|
| + indices.sort((a, b) => timestamps[a] - timestamps[b]);
|
| + for (var i = 0; i < timestamps.length; ++i) {
|
| + var index = indices[i];
|
| + if (index === i)
|
| + continue;
|
| + // Move items in a cycle.
|
| + var savedTimestamp = timestamps[i];
|
| + var savedSample = samples[i];
|
| + var currentIndex = i;
|
| + while (index !== i) {
|
| + samples[currentIndex] = samples[index];
|
| + timestamps[currentIndex] = timestamps[index];
|
| + currentIndex = index;
|
| + index = indices[index];
|
| + indices[currentIndex] = currentIndex;
|
| + }
|
| + samples[currentIndex] = savedSample;
|
| + timestamps[currentIndex] = savedTimestamp;
|
| + }
|
| + }
|
|
|
| - _buildIdToNodeMap: function()
|
| - {
|
| - /** @type {!Map<number, !WebInspector.CPUProfileNode>} */
|
| - this._idToNode = new Map();
|
| - var idToNode = this._idToNode;
|
| - var stack = [this.profileHead];
|
| - while (stack.length) {
|
| - var node = stack.pop();
|
| - idToNode.set(node.id, node);
|
| - stack.push.apply(stack, node.children);
|
| - }
|
| - },
|
| + _normalizeTimestamps() {
|
| + var timestamps = this.timestamps;
|
| + if (!timestamps) {
|
| + // Support loading old CPU profiles that are missing timestamps.
|
| + // Derive timestamps from profile start and stop times.
|
| + var profileStartTime = this.profileStartTime;
|
| + var interval = (this.profileEndTime - profileStartTime) / this.samples.length;
|
| + timestamps = new Float64Array(this.samples.length + 1);
|
| + for (var i = 0; i < timestamps.length; ++i)
|
| + timestamps[i] = profileStartTime + i * interval;
|
| + this.timestamps = timestamps;
|
| + return;
|
| + }
|
|
|
| - _extractMetaNodes: function()
|
| - {
|
| - var topLevelNodes = this.profileHead.children;
|
| - for (var i = 0; i < topLevelNodes.length && !(this.gcNode && this.programNode && this.idleNode); i++) {
|
| - var node = topLevelNodes[i];
|
| - if (node.functionName === "(garbage collector)")
|
| - this.gcNode = node;
|
| - else if (node.functionName === "(program)")
|
| - this.programNode = node;
|
| - else if (node.functionName === "(idle)")
|
| - this.idleNode = node;
|
| - }
|
| - },
|
| + // Convert samples from usec to msec
|
| + for (var i = 0; i < timestamps.length; ++i)
|
| + timestamps[i] /= 1000;
|
| + var averageSample = (timestamps.peekLast() - timestamps[0]) / (timestamps.length - 1);
|
| + // Add an extra timestamp used to calculate the last sample duration.
|
| + this.timestamps.push(timestamps.peekLast() + averageSample);
|
| + this.profileStartTime = timestamps[0];
|
| + this.profileEndTime = timestamps.peekLast();
|
| + }
|
|
|
| - /**
|
| - * @param {function(number, !WebInspector.CPUProfileNode, number)} openFrameCallback
|
| - * @param {function(number, !WebInspector.CPUProfileNode, number, number, number)} closeFrameCallback
|
| - * @param {number=} startTime
|
| - * @param {number=} stopTime
|
| - */
|
| - forEachFrame: function(openFrameCallback, closeFrameCallback, startTime, stopTime)
|
| - {
|
| - if (!this.profileHead || !this.samples)
|
| - return;
|
| + _buildIdToNodeMap() {
|
| + /** @type {!Map<number, !WebInspector.CPUProfileNode>} */
|
| + this._idToNode = new Map();
|
| + var idToNode = this._idToNode;
|
| + var stack = [this.profileHead];
|
| + while (stack.length) {
|
| + var node = stack.pop();
|
| + idToNode.set(node.id, node);
|
| + stack.push.apply(stack, node.children);
|
| + }
|
| + }
|
|
|
| - startTime = startTime || 0;
|
| - stopTime = stopTime || Infinity;
|
| - var samples = this.samples;
|
| - var timestamps = this.timestamps;
|
| - var idToNode = this._idToNode;
|
| - var gcNode = this.gcNode;
|
| - var samplesCount = samples.length;
|
| - var startIndex = timestamps.lowerBound(startTime);
|
| - var stackTop = 0;
|
| - var stackNodes = [];
|
| - var prevId = this.profileHead.id;
|
| - var sampleTime = timestamps[samplesCount];
|
| - var gcParentNode = null;
|
| + _extractMetaNodes() {
|
| + var topLevelNodes = this.profileHead.children;
|
| + for (var i = 0; i < topLevelNodes.length && !(this.gcNode && this.programNode && this.idleNode); i++) {
|
| + var node = topLevelNodes[i];
|
| + if (node.functionName === '(garbage collector)')
|
| + this.gcNode = node;
|
| + else if (node.functionName === '(program)')
|
| + this.programNode = node;
|
| + else if (node.functionName === '(idle)')
|
| + this.idleNode = node;
|
| + }
|
| + }
|
|
|
| - if (!this._stackStartTimes)
|
| - this._stackStartTimes = new Float64Array(this.maxDepth + 2);
|
| - var stackStartTimes = this._stackStartTimes;
|
| - if (!this._stackChildrenDuration)
|
| - this._stackChildrenDuration = new Float64Array(this.maxDepth + 2);
|
| - var stackChildrenDuration = this._stackChildrenDuration;
|
| + /**
|
| + * @param {function(number, !WebInspector.CPUProfileNode, number)} openFrameCallback
|
| + * @param {function(number, !WebInspector.CPUProfileNode, number, number, number)} closeFrameCallback
|
| + * @param {number=} startTime
|
| + * @param {number=} stopTime
|
| + */
|
| + forEachFrame(openFrameCallback, closeFrameCallback, startTime, stopTime) {
|
| + if (!this.profileHead || !this.samples)
|
| + return;
|
|
|
| - for (var sampleIndex = startIndex; sampleIndex < samplesCount; sampleIndex++) {
|
| - sampleTime = timestamps[sampleIndex];
|
| - if (sampleTime >= stopTime)
|
| - break;
|
| - var id = samples[sampleIndex];
|
| - if (id === prevId)
|
| - continue;
|
| - var node = idToNode.get(id);
|
| - var prevNode = idToNode.get(prevId);
|
| + startTime = startTime || 0;
|
| + stopTime = stopTime || Infinity;
|
| + var samples = this.samples;
|
| + var timestamps = this.timestamps;
|
| + var idToNode = this._idToNode;
|
| + var gcNode = this.gcNode;
|
| + var samplesCount = samples.length;
|
| + var startIndex = timestamps.lowerBound(startTime);
|
| + var stackTop = 0;
|
| + var stackNodes = [];
|
| + var prevId = this.profileHead.id;
|
| + var sampleTime = timestamps[samplesCount];
|
| + var gcParentNode = null;
|
|
|
| - if (node === gcNode) {
|
| - // GC samples have no stack, so we just put GC node on top of the last recorded sample.
|
| - gcParentNode = prevNode;
|
| - openFrameCallback(gcParentNode.depth + 1, gcNode, sampleTime);
|
| - stackStartTimes[++stackTop] = sampleTime;
|
| - stackChildrenDuration[stackTop] = 0;
|
| - prevId = id;
|
| - continue;
|
| - }
|
| - if (prevNode === gcNode) {
|
| - // end of GC frame
|
| - var start = stackStartTimes[stackTop];
|
| - var duration = sampleTime - start;
|
| - stackChildrenDuration[stackTop - 1] += duration;
|
| - closeFrameCallback(gcParentNode.depth + 1, gcNode, start, duration, duration - stackChildrenDuration[stackTop]);
|
| - --stackTop;
|
| - prevNode = gcParentNode;
|
| - prevId = prevNode.id;
|
| - gcParentNode = null;
|
| - }
|
| + if (!this._stackStartTimes)
|
| + this._stackStartTimes = new Float64Array(this.maxDepth + 2);
|
| + var stackStartTimes = this._stackStartTimes;
|
| + if (!this._stackChildrenDuration)
|
| + this._stackChildrenDuration = new Float64Array(this.maxDepth + 2);
|
| + var stackChildrenDuration = this._stackChildrenDuration;
|
|
|
| - while (node.depth > prevNode.depth) {
|
| - stackNodes.push(node);
|
| - node = node.parent;
|
| - }
|
| + for (var sampleIndex = startIndex; sampleIndex < samplesCount; sampleIndex++) {
|
| + sampleTime = timestamps[sampleIndex];
|
| + if (sampleTime >= stopTime)
|
| + break;
|
| + var id = samples[sampleIndex];
|
| + if (id === prevId)
|
| + continue;
|
| + var node = idToNode.get(id);
|
| + var prevNode = idToNode.get(prevId);
|
|
|
| - // Go down to the LCA and close current intervals.
|
| - while (prevNode !== node) {
|
| - var start = stackStartTimes[stackTop];
|
| - var duration = sampleTime - start;
|
| - stackChildrenDuration[stackTop - 1] += duration;
|
| - closeFrameCallback(prevNode.depth, /** @type {!WebInspector.CPUProfileNode} */(prevNode), start, duration, duration - stackChildrenDuration[stackTop]);
|
| - --stackTop;
|
| - if (node.depth === prevNode.depth) {
|
| - stackNodes.push(node);
|
| - node = node.parent;
|
| - }
|
| - prevNode = prevNode.parent;
|
| - }
|
| + if (node === gcNode) {
|
| + // GC samples have no stack, so we just put GC node on top of the last recorded sample.
|
| + gcParentNode = prevNode;
|
| + openFrameCallback(gcParentNode.depth + 1, gcNode, sampleTime);
|
| + stackStartTimes[++stackTop] = sampleTime;
|
| + stackChildrenDuration[stackTop] = 0;
|
| + prevId = id;
|
| + continue;
|
| + }
|
| + if (prevNode === gcNode) {
|
| + // end of GC frame
|
| + var start = stackStartTimes[stackTop];
|
| + var duration = sampleTime - start;
|
| + stackChildrenDuration[stackTop - 1] += duration;
|
| + closeFrameCallback(gcParentNode.depth + 1, gcNode, start, duration, duration - stackChildrenDuration[stackTop]);
|
| + --stackTop;
|
| + prevNode = gcParentNode;
|
| + prevId = prevNode.id;
|
| + gcParentNode = null;
|
| + }
|
|
|
| - // Go up the nodes stack and open new intervals.
|
| - while (stackNodes.length) {
|
| - node = stackNodes.pop();
|
| - openFrameCallback(node.depth, node, sampleTime);
|
| - stackStartTimes[++stackTop] = sampleTime;
|
| - stackChildrenDuration[stackTop] = 0;
|
| - }
|
| + while (node.depth > prevNode.depth) {
|
| + stackNodes.push(node);
|
| + node = node.parent;
|
| + }
|
|
|
| - prevId = id;
|
| + // Go down to the LCA and close current intervals.
|
| + while (prevNode !== node) {
|
| + var start = stackStartTimes[stackTop];
|
| + var duration = sampleTime - start;
|
| + stackChildrenDuration[stackTop - 1] += duration;
|
| + closeFrameCallback(
|
| + prevNode.depth, /** @type {!WebInspector.CPUProfileNode} */ (prevNode), start, duration,
|
| + duration - stackChildrenDuration[stackTop]);
|
| + --stackTop;
|
| + if (node.depth === prevNode.depth) {
|
| + stackNodes.push(node);
|
| + node = node.parent;
|
| }
|
| + prevNode = prevNode.parent;
|
| + }
|
|
|
| - if (idToNode.get(prevId) === gcNode) {
|
| - var start = stackStartTimes[stackTop];
|
| - var duration = sampleTime - start;
|
| - stackChildrenDuration[stackTop - 1] += duration;
|
| - closeFrameCallback(gcParentNode.depth + 1, node, start, duration, duration - stackChildrenDuration[stackTop]);
|
| - --stackTop;
|
| - }
|
| + // Go up the nodes stack and open new intervals.
|
| + while (stackNodes.length) {
|
| + node = stackNodes.pop();
|
| + openFrameCallback(node.depth, node, sampleTime);
|
| + stackStartTimes[++stackTop] = sampleTime;
|
| + stackChildrenDuration[stackTop] = 0;
|
| + }
|
|
|
| - for (var node = idToNode.get(prevId); node.parent; node = node.parent) {
|
| - var start = stackStartTimes[stackTop];
|
| - var duration = sampleTime - start;
|
| - stackChildrenDuration[stackTop - 1] += duration;
|
| - closeFrameCallback(node.depth, /** @type {!WebInspector.CPUProfileNode} */(node), start, duration, duration - stackChildrenDuration[stackTop]);
|
| - --stackTop;
|
| - }
|
| - },
|
| + prevId = id;
|
| + }
|
|
|
| - /**
|
| - * @param {number} index
|
| - * @return {?WebInspector.CPUProfileNode}
|
| - */
|
| - nodeByIndex: function(index)
|
| - {
|
| - return this._idToNode.get(this.samples[index]) || null;
|
| - },
|
| + if (idToNode.get(prevId) === gcNode) {
|
| + var start = stackStartTimes[stackTop];
|
| + var duration = sampleTime - start;
|
| + stackChildrenDuration[stackTop - 1] += duration;
|
| + closeFrameCallback(gcParentNode.depth + 1, node, start, duration, duration - stackChildrenDuration[stackTop]);
|
| + --stackTop;
|
| + }
|
| +
|
| + for (var node = idToNode.get(prevId); node.parent; node = node.parent) {
|
| + var start = stackStartTimes[stackTop];
|
| + var duration = sampleTime - start;
|
| + stackChildrenDuration[stackTop - 1] += duration;
|
| + closeFrameCallback(
|
| + node.depth, /** @type {!WebInspector.CPUProfileNode} */ (node), start, duration,
|
| + duration - stackChildrenDuration[stackTop]);
|
| + --stackTop;
|
| + }
|
| + }
|
|
|
| - __proto__: WebInspector.ProfileTreeModel.prototype
|
| + /**
|
| + * @param {number} index
|
| + * @return {?WebInspector.CPUProfileNode}
|
| + */
|
| + nodeByIndex(index) {
|
| + return this._idToNode.get(this.samples[index]) || null;
|
| + }
|
| };
|
|
|