Chromium Code Reviews| Index: runtime/observatory/lib/src/cpu_profile/cpu_profile.dart |
| diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart |
| index 1c6d9801228b0a47cb4b21762f6c3e80252521f2..b3059914a564783ae50533d53440bdf5bf21f0d6 100644 |
| --- a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart |
| +++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart |
| @@ -8,6 +8,8 @@ abstract class CallTreeNode<NodeT extends M.CallTreeNode> |
| implements M.CallTreeNode { |
| final List<NodeT> children; |
| final int count; |
| + final int inclusiveNativeAllocations; |
| + final int exclusiveNativeAllocations; |
| double get percentage => _percentage; |
| double _percentage = 0.0; |
| final Set<String> attributes = new Set<String>(); |
| @@ -16,7 +18,8 @@ abstract class CallTreeNode<NodeT extends M.CallTreeNode> |
| Object get profileData; |
| String get name; |
| - CallTreeNode(this.children, this.count); |
| + CallTreeNode(this.children, this.count, this.inclusiveNativeAllocations, |
| + this.exclusiveNativeAllocations); |
| } |
| class CodeCallTreeNode extends CallTreeNode<CodeCallTreeNode> |
| @@ -28,8 +31,10 @@ class CodeCallTreeNode extends CallTreeNode<CodeCallTreeNode> |
| String get name => profileCode.code.name; |
| final Set<String> attributes = new Set<String>(); |
| - CodeCallTreeNode(this.profileCode, int count) |
| - : super(new List<CodeCallTreeNode>(), count) { |
| + CodeCallTreeNode(this.profileCode, int count, int inclusiveNativeAllocations, |
| + int exclusiveNativeAllocations) |
| + : super(new List<CodeCallTreeNode>(), count, inclusiveNativeAllocations, |
| + exclusiveNativeAllocations) { |
| attributes.addAll(profileCode.attributes); |
| } |
| } |
| @@ -44,13 +49,21 @@ class CallTree<NodeT extends CallTreeNode> { |
| class CodeCallTree extends CallTree<CodeCallTreeNode> |
| implements M.CodeCallTree { |
| CodeCallTree(bool inclusive, CodeCallTreeNode root) : super(inclusive, root) { |
| - _setCodePercentage(null, root); |
| + if (root.inclusiveNativeAllocations != 0) { |
| + _setCodeMemoryPercentage(null, root); |
| + } else { |
| + _setCodePercentage(null, root); |
| + } |
| } |
| CodeCallTree filtered(CallTreeNodeFilter filter) { |
| var treeFilter = new _FilteredCodeCallTreeBuilder(filter, this); |
| treeFilter.build(); |
| - _setCodePercentage(null, treeFilter.filtered.root); |
| + if (treeFilter.filtered.root.inclusiveNativeAllocations != 0) { |
| + _setCodeMemoryPercentage(null, treeFilter.filtered.root); |
| + } else { |
| + _setCodePercentage(null, treeFilter.filtered.root); |
| + } |
| return treeFilter.filtered; |
| } |
| @@ -72,6 +85,25 @@ class CodeCallTree extends CallTree<CodeCallTreeNode> |
| } |
| } |
| + _setCodeMemoryPercentage(CodeCallTreeNode parent, CodeCallTreeNode node) { |
| + assert(node != null); |
| + var parentPercentage = 1.0; |
| + var parentMemory = node.inclusiveNativeAllocations; |
| + if (parent != null) { |
| + parentPercentage = parent._percentage; |
| + parentMemory = parent.inclusiveNativeAllocations; |
| + } |
| + if (inclusive) { |
| + node._percentage = parentPercentage * |
| + (node.inclusiveNativeAllocations / parentMemory); |
| + } else { |
| + node._percentage = (node.inclusiveNativeAllocations / parentMemory); |
| + } |
| + for (var child in node.children) { |
| + _setCodeMemoryPercentage(node, child); |
| + } |
| + } |
| + |
| _recordCallerAndCalleesInner( |
| CodeCallTreeNode caller, CodeCallTreeNode callee) { |
| if (caller != null) { |
| @@ -106,8 +138,10 @@ class FunctionCallTreeNode extends CallTreeNode { |
| String get name => M.getFunctionFullName(profileFunction.function); |
| Object get profileData => profileFunction; |
| - FunctionCallTreeNode(this.profileFunction, int count) |
| - : super(new List<FunctionCallTreeNode>(), count) { |
| + FunctionCallTreeNode(this.profileFunction, int count, |
| + inclusiveNativeAllocations, exclusiveNativeAllocations) |
| + : super(new List<FunctionCallTreeNode>(), count, |
| + inclusiveNativeAllocations, exclusiveNativeAllocations) { |
| profileFunction._addKindBasedAttributes(attributes); |
| } |
| @@ -290,10 +324,13 @@ class _FilteredFunctionCallTreeBuilder extends _FilteredCallTreeBuilder { |
| new FunctionCallTree( |
| tree.inclusive, |
| new FunctionCallTreeNode( |
| - tree.root.profileData, tree.root.count))); |
| + tree.root.profileData, tree.root.count, |
| + tree.root.inclusiveNativeAllocations, |
| + tree.root.exclusiveNativeAllocations))); |
| _copyNode(FunctionCallTreeNode node) { |
| - return new FunctionCallTreeNode(node.profileData, node.count); |
| + return new FunctionCallTreeNode(node.profileData, node.count, |
| + node.inclusiveNativeAllocations, node.exclusiveNativeAllocations); |
| } |
| } |
| @@ -303,23 +340,34 @@ class _FilteredCodeCallTreeBuilder extends _FilteredCallTreeBuilder { |
| filter, |
| tree, |
| new CodeCallTree(tree.inclusive, |
| - new CodeCallTreeNode(tree.root.profileData, tree.root.count))); |
| + new CodeCallTreeNode(tree.root.profileData, tree.root.count, |
| + tree.root.inclusiveNativeAllocations, |
| + tree.root.exclusiveNativeAllocations))); |
| _copyNode(CodeCallTreeNode node) { |
| - return new CodeCallTreeNode(node.profileData, node.count); |
| + return new CodeCallTreeNode(node.profileData, node.count, |
| + node.inclusiveNativeAllocations, node.exclusiveNativeAllocations); |
| } |
| } |
| class FunctionCallTree extends CallTree implements M.FunctionCallTree { |
| FunctionCallTree(bool inclusive, FunctionCallTreeNode root) |
| : super(inclusive, root) { |
| - _setFunctionPercentage(null, root); |
| + if (root.inclusiveNativeAllocations != 0) { |
|
Cutch
2017/03/21 20:27:10
it looks like inclusiveNativeAllocations be null w
bkonyi
2017/03/22 21:25:21
Done.
|
| + _setFunctionMemoryPercentage(null, root); |
| + } else { |
| + _setFunctionPercentage(null, root); |
| + } |
| } |
| FunctionCallTree filtered(CallTreeNodeFilter filter) { |
| var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this); |
| treeFilter.build(); |
| - _setFunctionPercentage(null, treeFilter.filtered.root); |
| + if (treeFilter.filtered.root.inclusiveNativeAllocations != 0) { |
|
Cutch
2017/03/21 20:27:10
ditto
bkonyi
2017/03/22 21:25:21
Done.
|
| + _setFunctionMemoryPercentage(null, treeFilter.filtered.root); |
| + } else { |
| + _setFunctionPercentage(null, treeFilter.filtered.root); |
| + } |
| return treeFilter.filtered; |
| } |
| @@ -342,6 +390,25 @@ class FunctionCallTree extends CallTree implements M.FunctionCallTree { |
| } |
| } |
| + void _setFunctionMemoryPercentage(FunctionCallTreeNode parent, FunctionCallTreeNode node) { |
|
Cutch
2017/03/21 20:27:10
long line, you probably want to run dartfmt on it.
bkonyi
2017/03/22 21:25:21
Done.
|
| + assert(node != null); |
| + var parentPercentage = 1.0; |
| + var parentMemory = node.inclusiveNativeAllocations; |
| + if (parent != null) { |
| + parentPercentage = parent._percentage; |
| + parentMemory = parent.inclusiveNativeAllocations; |
| + } |
| + if (inclusive) { |
| + node._percentage = parentPercentage * |
| + (node.inclusiveNativeAllocations / parentMemory); |
| + } else { |
| + node._percentage = (node.inclusiveNativeAllocations / parentMemory); |
| + } |
| + for (var child in node.children) { |
| + _setFunctionMemoryPercentage(node, child); |
| + } |
| + } |
| + |
| _markFunctionCallsInner( |
| FunctionCallTreeNode caller, FunctionCallTreeNode callee) { |
| if (caller != null) { |
| @@ -382,6 +449,8 @@ class ProfileCode implements M.ProfileCode { |
| final Code code; |
| int exclusiveTicks; |
| int inclusiveTicks; |
| + int exclusiveNativeAllocations; |
| + int inclusiveNativeAllocations; |
| double normalizedExclusiveTicks = 0.0; |
| double normalizedInclusiveTicks = 0.0; |
| final addressTicks = new Map<int, CodeTick>(); |
| @@ -458,6 +527,14 @@ class ProfileCode implements M.ProfileCode { |
| _processTicks(ticks); |
| } |
| + if (data.containsKey('exclusiveNativeAllocations') && |
| + data.containsKey('inclusiveNativeAllocations')) { |
| + exclusiveNativeAllocations = |
| + int.parse(data['exclusiveNativeAllocations']); |
| + inclusiveNativeAllocations = |
| + int.parse(data['inclusiveNativeAllocations']); |
| + } |
| + |
| formattedExclusivePercent = |
| Utils.formatPercent(exclusiveTicks, profile.sampleCount); |
| @@ -509,6 +586,10 @@ class ProfileFunction implements M.ProfileFunction { |
| double normalizedExclusiveTicks = 0.0; |
| double normalizedInclusiveTicks = 0.0; |
| + // Native allocations: |
| + int exclusiveNativeAllocations = 0; |
| + int inclusiveNativeAllocations = 0; |
| + |
| String formattedInclusiveTicks = ''; |
| String formattedExclusiveTicks = ''; |
| String formattedExclusivePercent = ''; |
| @@ -606,6 +687,14 @@ class ProfileFunction implements M.ProfileFunction { |
| normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount; |
| normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount; |
| + if (data.containsKey('exclusiveNativeAllocations') && |
| + data.containsKey('inclusiveNativeAllocations')) { |
| + exclusiveNativeAllocations = |
| + int.parse(data['exclusiveNativeAllocations']); |
| + inclusiveNativeAllocations = |
| + int.parse(data['inclusiveNativeAllocations']); |
| + } |
| + |
| formattedExclusivePercent = |
| Utils.formatPercent(exclusiveTicks, profile.sampleCount); |
| @@ -710,8 +799,8 @@ class CpuProfile extends M.SampleProfile { |
| _builtFunctionCalls = false; |
| } |
| - Future load(Isolate isolate, ServiceMap profile) async { |
| - await loadProgress(isolate, profile).last; |
| + Future load(Object owner, ServiceMap profile) async { |
| + await loadProgress(owner, profile).last; |
| } |
| static Future sleep([Duration duration = const Duration(microseconds: 0)]) { |
| @@ -720,7 +809,7 @@ class CpuProfile extends M.SampleProfile { |
| return completer.future; |
| } |
| - Stream<double> loadProgress(Isolate isolate, ServiceMap profile) { |
| + Stream<double> loadProgress(Object owner, ServiceMap profile) { |
| var progress = new StreamController<double>.broadcast(); |
| (() async { |
| @@ -742,12 +831,14 @@ class CpuProfile extends M.SampleProfile { |
| try { |
| clear(); |
| progress.add(0.0); |
| - if ((isolate == null) || (profile == null)) { |
| + if (profile == null) { |
| return; |
| } |
| - this.isolate = isolate; |
| - isolate.resetCachedProfileData(); |
| + if (owner != null && owner is Isolate) { |
| + isolate = owner as Isolate; |
| + isolate.resetCachedProfileData(); |
| + } |
| sampleCount = profile['sampleCount']; |
| samplePeriod = profile['samplePeriod']; |
| @@ -824,8 +915,13 @@ class CpuProfile extends M.SampleProfile { |
| var count = data[_dataCursor++]; |
| // Child node count. |
| var children = data[_dataCursor++]; |
| + // Inclusive native allocations. |
| + var inclusiveNativeAllocations = data[_dataCursor++]; |
| + // Exclusive native allocations. |
| + var exclusiveNativeAllocations = data[_dataCursor++]; |
| // Create node. |
| - var node = new CodeCallTreeNode(code, count); |
| + var node = new CodeCallTreeNode(code, count, inclusiveNativeAllocations, |
| + exclusiveNativeAllocations); |
| node.children.length = children; |
| return node; |
| } |
| @@ -894,8 +990,13 @@ class CpuProfile extends M.SampleProfile { |
| var function = functions[index]; |
| // Counter. |
| var count = data[_dataCursor++]; |
| + // Inclusive native allocations. |
| + var inclusiveNativeAllocations = data[_dataCursor++]; |
| + // Exclusive native allocations. |
| + var exclusiveNativeAllocations = data[_dataCursor++]; |
| // Create node. |
| - var node = new FunctionCallTreeNode(function, count); |
| + var node = new FunctionCallTreeNode(function, count, |
| + inclusiveNativeAllocations, exclusiveNativeAllocations); |
| // Number of code index / count pairs. |
| var codeCount = data[_dataCursor++]; |
| node.codes.length = codeCount; |