| 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..521fc192d323d6dac0914164bc65818e5058659d 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,23 @@ 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 != null) &&
|
| + (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 != null) &&
|
| + (treeFilter.filtered.root.inclusiveNativeAllocations != 0)) {
|
| + _setCodeMemoryPercentage(null, treeFilter.filtered.root);
|
| + } else {
|
| + _setCodePercentage(null, treeFilter.filtered.root);
|
| + }
|
| return treeFilter.filtered;
|
| }
|
|
|
| @@ -72,6 +87,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 +140,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 +326,14 @@ 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);
|
| }
|
| }
|
|
|
| @@ -302,24 +342,40 @@ class _FilteredCodeCallTreeBuilder extends _FilteredCallTreeBuilder {
|
| : super(
|
| filter,
|
| tree,
|
| - new CodeCallTree(tree.inclusive,
|
| - new CodeCallTreeNode(tree.root.profileData, tree.root.count)));
|
| + new CodeCallTree(
|
| + tree.inclusive,
|
| + 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 != null) &&
|
| + (root.inclusiveNativeAllocations != 0)) {
|
| + _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 != null) &&
|
| + (treeFilter.filtered.root.inclusiveNativeAllocations != 0)) {
|
| + _setFunctionMemoryPercentage(null, treeFilter.filtered.root);
|
| + } else {
|
| + _setFunctionPercentage(null, treeFilter.filtered.root);
|
| + }
|
| return treeFilter.filtered;
|
| }
|
|
|
| @@ -342,6 +398,26 @@ class FunctionCallTree extends CallTree implements M.FunctionCallTree {
|
| }
|
| }
|
|
|
| + void _setFunctionMemoryPercentage(
|
| + FunctionCallTreeNode parent, FunctionCallTreeNode 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) {
|
| + _setFunctionMemoryPercentage(node, child);
|
| + }
|
| + }
|
| +
|
| _markFunctionCallsInner(
|
| FunctionCallTreeNode caller, FunctionCallTreeNode callee) {
|
| if (caller != null) {
|
| @@ -382,6 +458,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 +536,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 +595,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 +696,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 +808,8 @@ class CpuProfile extends M.SampleProfile {
|
| _builtFunctionCalls = false;
|
| }
|
|
|
| - Future load(Isolate isolate, ServiceMap profile) async {
|
| - await loadProgress(isolate, profile).last;
|
| + Future load(ServiceObjectOwner owner, ServiceMap profile) async {
|
| + await loadProgress(owner, profile).last;
|
| }
|
|
|
| static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
|
| @@ -720,7 +818,7 @@ class CpuProfile extends M.SampleProfile {
|
| return completer.future;
|
| }
|
|
|
| - Stream<double> loadProgress(Isolate isolate, ServiceMap profile) {
|
| + Stream<double> loadProgress(ServiceObjectOwner owner, ServiceMap profile) {
|
| var progress = new StreamController<double>.broadcast();
|
|
|
| (() async {
|
| @@ -742,12 +840,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 +924,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 +999,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;
|
|
|