| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of cpu_profiler; | 5 part of cpu_profiler; |
| 6 | 6 |
| 7 class CodeCallTreeNode { | 7 abstract class CallTreeNode { |
| 8 final ProfileCode profileCode; | 8 final List<CallTreeNode> children; |
| 9 final int count; | 9 final int count; |
| 10 double get percentage => _percentage; | 10 double get percentage => _percentage; |
| 11 double _percentage = 0.0; | 11 double _percentage = 0.0; |
| 12 final children; | |
| 13 final Set<String> attributes = new Set<String>(); | 12 final Set<String> attributes = new Set<String>(); |
| 14 CodeCallTreeNode(this.profileCode, this.count, int childCount) | 13 |
| 15 : children = new List<CodeCallTreeNode>(childCount) { | 14 // Either a ProfileCode or a ProfileFunction. |
| 15 Object get profileData; |
| 16 String get name; |
| 17 |
| 18 CallTreeNode(this.children, this.count); |
| 19 } |
| 20 |
| 21 class CodeCallTreeNode extends CallTreeNode { |
| 22 final ProfileCode profileCode; |
| 23 |
| 24 Object get profileData => profileCode; |
| 25 |
| 26 String get name => profileCode.code.name; |
| 27 |
| 28 final Set<String> attributes = new Set<String>(); |
| 29 CodeCallTreeNode(this.profileCode, int count) |
| 30 : super(new List<CodeCallTreeNode>(), count) { |
| 16 attributes.addAll(profileCode.attributes); | 31 attributes.addAll(profileCode.attributes); |
| 17 } | 32 } |
| 18 } | 33 } |
| 19 | 34 |
| 20 class CodeCallTree { | 35 class CallTree { |
| 21 final bool inclusive; | 36 final bool inclusive; |
| 22 final CodeCallTreeNode root; | 37 final CallTreeNode root; |
| 23 CodeCallTree(this.inclusive, this.root) { | 38 |
| 39 CallTree(this.inclusive, this.root); |
| 40 } |
| 41 |
| 42 class CodeCallTree extends CallTree { |
| 43 CodeCallTree(bool inclusive, CodeCallTreeNode root) |
| 44 : super(inclusive, root) { |
| 24 _setCodePercentage(null, root); | 45 _setCodePercentage(null, root); |
| 25 } | 46 } |
| 26 | 47 |
| 48 CodeCallTree filtered(CallTreeNodeFilter filter) { |
| 49 var treeFilter = new _FilteredCodeCallTreeBuilder(filter, this); |
| 50 treeFilter.build(); |
| 51 _setCodePercentage(null, treeFilter.filtered.root); |
| 52 return treeFilter.filtered; |
| 53 } |
| 54 |
| 27 _setCodePercentage(CodeCallTreeNode parent, CodeCallTreeNode node) { | 55 _setCodePercentage(CodeCallTreeNode parent, CodeCallTreeNode node) { |
| 28 assert(node != null); | 56 assert(node != null); |
| 29 var parentPercentage = 1.0; | 57 var parentPercentage = 1.0; |
| 30 var parentCount = node.count; | 58 var parentCount = node.count; |
| 31 if (parent != null) { | 59 if (parent != null) { |
| 32 parentPercentage = parent._percentage; | 60 parentPercentage = parent._percentage; |
| 33 parentCount = parent.count; | 61 parentCount = parent.count; |
| 34 } | 62 } |
| 35 if (inclusive) { | 63 if (inclusive) { |
| 36 node._percentage = parentPercentage * (node.count / parentCount); | 64 node._percentage = parentPercentage * (node.count / parentCount); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 60 } | 88 } |
| 61 } | 89 } |
| 62 } | 90 } |
| 63 | 91 |
| 64 class FunctionCallTreeNodeCode { | 92 class FunctionCallTreeNodeCode { |
| 65 final ProfileCode code; | 93 final ProfileCode code; |
| 66 final int ticks; | 94 final int ticks; |
| 67 FunctionCallTreeNodeCode(this.code, this.ticks); | 95 FunctionCallTreeNodeCode(this.code, this.ticks); |
| 68 } | 96 } |
| 69 | 97 |
| 70 class FunctionCallTreeNode { | 98 class FunctionCallTreeNode extends CallTreeNode { |
| 71 final ProfileFunction profileFunction; | 99 final ProfileFunction profileFunction; |
| 72 final int count; | |
| 73 double get percentage => _percentage; | |
| 74 double _percentage = 0.0; | |
| 75 final children = new List<FunctionCallTreeNode>(); | |
| 76 final Set<String> attributes = new Set<String>(); | |
| 77 final codes = new List<FunctionCallTreeNodeCode>(); | 100 final codes = new List<FunctionCallTreeNodeCode>(); |
| 78 int _totalCodeTicks = 0; | 101 int _totalCodeTicks = 0; |
| 79 int get totalCodesTicks => _totalCodeTicks; | 102 int get totalCodesTicks => _totalCodeTicks; |
| 80 | 103 |
| 81 FunctionCallTreeNode(this.profileFunction, this.count){ | 104 String get name => profileFunction.function.name; |
| 105 Object get profileData => profileFunction; |
| 106 |
| 107 FunctionCallTreeNode(this.profileFunction, int count) |
| 108 : super(new List<FunctionCallTreeNode>(), count) { |
| 82 profileFunction._addKindBasedAttributes(attributes); | 109 profileFunction._addKindBasedAttributes(attributes); |
| 83 } | 110 } |
| 84 | 111 |
| 85 // Does this function have an optimized version of itself? | 112 // Does this function have an optimized version of itself? |
| 86 bool hasOptimizedCode() { | 113 bool hasOptimizedCode() { |
| 87 for (var nodeCode in codes) { | 114 for (var nodeCode in codes) { |
| 88 var profileCode = nodeCode.code; | 115 var profileCode = nodeCode.code; |
| 89 if (!profileCode.code.isDartCode) { | 116 if (!profileCode.code.isDartCode) { |
| 90 continue; | 117 continue; |
| 91 } | 118 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 } | 160 } |
| 134 return false; | 161 return false; |
| 135 } | 162 } |
| 136 | 163 |
| 137 setCodeAttributes() { | 164 setCodeAttributes() { |
| 138 } | 165 } |
| 139 } | 166 } |
| 140 | 167 |
| 141 /// Predicate filter function. Returns true if path from root to [node] and all | 168 /// Predicate filter function. Returns true if path from root to [node] and all |
| 142 /// of [node]'s children should be added to the filtered tree. | 169 /// of [node]'s children should be added to the filtered tree. |
| 143 typedef bool FunctionCallTreeNodeFilter(FunctionCallTreeNode node); | 170 typedef bool CallTreeNodeFilter(CallTreeNode node); |
| 144 | 171 |
| 145 /// Build a filter version of a FunctionCallTree. | 172 /// Build a filter version of a FunctionCallTree. |
| 146 class _FilteredFunctionCallTreeBuilder { | 173 abstract class _FilteredCallTreeBuilder { |
| 147 /// The filter. | 174 /// The filter. |
| 148 final FunctionCallTreeNodeFilter filter; | 175 final CallTreeNodeFilter filter; |
| 149 /// The unfiltered tree. | 176 /// The unfiltered tree. |
| 150 final FunctionCallTree _unfilteredTree; | 177 final CallTree _unfilteredTree; |
| 151 /// The filtered tree (construct by [build]). | 178 /// The filtered tree (construct by [build]). |
| 152 final FunctionCallTree filtered; | 179 final CallTree filtered; |
| 153 final List _currentPath = []; | 180 final List _currentPath = []; |
| 154 | 181 |
| 155 /// Construct a filtered tree builder using [filter] and [tree]. | 182 /// Construct a filtered tree builder using [filter] and [tree]. |
| 156 _FilteredFunctionCallTreeBuilder(this.filter, FunctionCallTree tree) | 183 _FilteredCallTreeBuilder(this.filter, CallTree tree, this.filtered) |
| 157 : _unfilteredTree = tree, | 184 : _unfilteredTree = tree; |
| 158 filtered = | |
| 159 new FunctionCallTree( | |
| 160 tree.inclusive, | |
| 161 new FunctionCallTreeNode( | |
| 162 tree.root.profileFunction, | |
| 163 tree.root.count)); | |
| 164 | 185 |
| 165 /// Build the filtered tree. | 186 /// Build the filtered tree. |
| 166 build() { | 187 build() { |
| 167 assert(filtered != null); | 188 assert(filtered != null); |
| 168 assert(filter != null); | 189 assert(filter != null); |
| 169 assert(_unfilteredTree != null); | 190 assert(_unfilteredTree != null); |
| 170 _descend(_unfilteredTree.root); | 191 _descend(_unfilteredTree.root); |
| 171 } | 192 } |
| 172 | 193 |
| 173 FunctionCallTreeNode _findFunctionInChildren(FunctionCallTreeNode current, | 194 CallTreeNode _findInChildren(CallTreeNode current, |
| 174 FunctionCallTreeNode needle) { | 195 CallTreeNode needle) { |
| 175 for (var child in current.children) { | 196 for (var child in current.children) { |
| 176 if (child.profileFunction == needle.profileFunction) { | 197 if (child.profileData == needle.profileData) { |
| 177 return child; | 198 return child; |
| 178 } | 199 } |
| 179 } | 200 } |
| 180 return null; | 201 return null; |
| 181 } | 202 } |
| 182 | 203 |
| 204 CallTreeNode _copyNode(CallTreeNode node); |
| 205 |
| 183 /// Add all nodes in [_currentPath]. | 206 /// Add all nodes in [_currentPath]. |
| 184 FunctionCallTreeNode _addCurrentPath() { | 207 FunctionCallTreeNode _addCurrentPath() { |
| 185 FunctionCallTreeNode current = filtered.root; | 208 FunctionCallTreeNode current = filtered.root; |
| 186 // Tree root is always the first element of the current path. | 209 // Tree root is always the first element of the current path. |
| 187 assert(_unfilteredTree.root == _currentPath[0]); | 210 assert(_unfilteredTree.root == _currentPath[0]); |
| 188 // Assert that unfiltered tree's root and filtered tree's root are different
. | 211 // Assert that unfiltered tree's root and filtered tree's root are different
. |
| 189 assert(_unfilteredTree.root != current); | 212 assert(_unfilteredTree.root != current); |
| 190 for (var i = 1; i < _currentPath.length; i++) { | 213 for (var i = 1; i < _currentPath.length; i++) { |
| 191 // toAdd is from the unfiltered tree. | 214 // toAdd is from the unfiltered tree. |
| 192 var toAdd = _currentPath[i]; | 215 var toAdd = _currentPath[i]; |
| 193 // See if we already have a node for toAdd in the filtered tree. | 216 // See if we already have a node for toAdd in the filtered tree. |
| 194 var child = _findFunctionInChildren(current, toAdd); | 217 var child = _findInChildren(current, toAdd); |
| 195 if (child == null) { | 218 if (child == null) { |
| 196 // New node. | 219 // New node. |
| 197 child = new FunctionCallTreeNode(toAdd.profileFunction, toAdd.count); | 220 child = _copyNode(toAdd); |
| 198 current.children.add(child); | 221 current.children.add(child); |
| 199 } | 222 } |
| 200 current = child; | 223 current = child; |
| 201 assert(current.count == toAdd.count); | 224 assert(current.count == toAdd.count); |
| 202 } | 225 } |
| 203 return current; | 226 return current; |
| 204 } | 227 } |
| 205 | 228 |
| 206 /// Starting at [current] append [next] and all of [next]'s sub-trees | 229 /// Starting at [current] append [next] and all of [next]'s sub-trees |
| 207 _appendTree(FunctionCallTreeNode current, FunctionCallTreeNode next) { | 230 _appendTree(CallTreeNode current, CallTreeNode next) { |
| 208 if (next == null) { | 231 if (next == null) { |
| 209 return; | 232 return; |
| 210 } | 233 } |
| 211 var child = _findFunctionInChildren(current, next); | 234 var child = _findInChildren(current, next); |
| 212 if (child == null) { | 235 if (child == null) { |
| 213 child = new FunctionCallTreeNode(next.profileFunction, next.count); | 236 child = _copyNode(next); |
| 214 current.children.add(child); | 237 current.children.add(child); |
| 215 } | 238 } |
| 216 current = child; | 239 current = child; |
| 217 for (var nextChild in next.children) { | 240 for (var nextChild in next.children) { |
| 218 _appendTree(current, nextChild); | 241 _appendTree(current, nextChild); |
| 219 } | 242 } |
| 220 } | 243 } |
| 221 | 244 |
| 222 /// Add path from root to [child], [child], and all of [child]'s sub-trees | 245 /// Add path from root to [child], [child], and all of [child]'s sub-trees |
| 223 /// to filtered tree. | 246 /// to filtered tree. |
| 224 _addTree(FunctionCallTreeNode child) { | 247 _addTree(CallTreeNode child) { |
| 225 var current = _addCurrentPath(); | 248 var current = _addCurrentPath(); |
| 226 _appendTree(current, child); | 249 _appendTree(current, child); |
| 227 } | 250 } |
| 228 | 251 |
| 229 /// Descend further into the tree. [current] is from the unfiltered tree. | 252 /// Descend further into the tree. [current] is from the unfiltered tree. |
| 230 _descend(FunctionCallTreeNode current) { | 253 _descend(CallTreeNode current) { |
| 231 if (current == null) { | 254 if (current == null) { |
| 232 return; | 255 return; |
| 233 } | 256 } |
| 234 _currentPath.add(current); | 257 _currentPath.add(current); |
| 235 | 258 |
| 236 if (filter(current)) { | 259 if (filter(current)) { |
| 237 // Filter matched. | 260 // Filter matched. |
| 238 if (current.children.length == 0) { | 261 if (current.children.length == 0) { |
| 239 // Have no children. Add this path. | 262 // Have no children. Add this path. |
| 240 _addTree(null); | 263 _addTree(null); |
| 241 } else { | 264 } else { |
| 242 // Add all child trees. | 265 // Add all child trees. |
| 243 for (var child in current.children) { | 266 for (var child in current.children) { |
| 244 _addTree(child); | 267 _addTree(child); |
| 245 } | 268 } |
| 246 } | 269 } |
| 247 } else { | 270 } else { |
| 248 // Did not match, descend to each child. | 271 // Did not match, descend to each child. |
| 249 for (var child in current.children) { | 272 for (var child in current.children) { |
| 250 _descend(child); | 273 _descend(child); |
| 251 } | 274 } |
| 252 } | 275 } |
| 253 | 276 |
| 254 var last = _currentPath.removeLast(); | 277 var last = _currentPath.removeLast(); |
| 255 assert(current == last); | 278 assert(current == last); |
| 256 } | 279 } |
| 257 } | 280 } |
| 258 | 281 |
| 259 class FunctionCallTree { | 282 class _FilteredFunctionCallTreeBuilder extends _FilteredCallTreeBuilder { |
| 260 final bool inclusive; | 283 _FilteredFunctionCallTreeBuilder(CallTreeNodeFilter filter, |
| 261 final FunctionCallTreeNode root; | 284 FunctionCallTree tree) |
| 262 FunctionCallTree(this.inclusive, this.root) { | 285 : super(filter, tree, |
| 286 new FunctionCallTree(tree.inclusive, |
| 287 new FunctionCallTreeNode(tree.root.profileData, |
| 288 tree.root.count))); |
| 289 |
| 290 _copyNode(FunctionCallTreeNode node) { |
| 291 return new FunctionCallTreeNode(node.profileData, node.count); |
| 292 } |
| 293 } |
| 294 |
| 295 class _FilteredCodeCallTreeBuilder extends _FilteredCallTreeBuilder { |
| 296 _FilteredCodeCallTreeBuilder(CallTreeNodeFilter filter, |
| 297 CodeCallTree tree) |
| 298 : super(filter, tree, |
| 299 new CodeCallTree(tree.inclusive, |
| 300 new CodeCallTreeNode(tree.root.profileData, |
| 301 tree.root.count))); |
| 302 |
| 303 _copyNode(FunctionCallTreeNode node) { |
| 304 return new FunctionCallTreeNode(node.profileData, node.count); |
| 305 } |
| 306 } |
| 307 |
| 308 class FunctionCallTree extends CallTree { |
| 309 FunctionCallTree(bool inclusive, FunctionCallTreeNode root) |
| 310 : super(inclusive, root) { |
| 263 _setFunctionPercentage(null, root); | 311 _setFunctionPercentage(null, root); |
| 264 } | 312 } |
| 265 | 313 |
| 266 FunctionCallTree filtered(FunctionCallTreeNodeFilter filter) { | 314 FunctionCallTree filtered(CallTreeNodeFilter filter) { |
| 267 var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this); | 315 var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this); |
| 268 treeFilter.build(); | 316 treeFilter.build(); |
| 269 _setFunctionPercentage(null, treeFilter.filtered.root); | 317 _setFunctionPercentage(null, treeFilter.filtered.root); |
| 270 return treeFilter.filtered; | 318 return treeFilter.filtered; |
| 271 } | 319 } |
| 272 | 320 |
| 273 void _setFunctionPercentage(FunctionCallTreeNode parent, | 321 void _setFunctionPercentage(FunctionCallTreeNode parent, |
| 274 FunctionCallTreeNode node) { | 322 FunctionCallTreeNode node) { |
| 275 assert(node != null); | 323 assert(node != null); |
| 276 var parentPercentage = 1.0; | 324 var parentPercentage = 1.0; |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 | 773 |
| 726 CodeCallTreeNode _readCodeTrieNode(List<int> data) { | 774 CodeCallTreeNode _readCodeTrieNode(List<int> data) { |
| 727 // Lookup code object. | 775 // Lookup code object. |
| 728 var codeIndex = data[_dataCursor++]; | 776 var codeIndex = data[_dataCursor++]; |
| 729 var code = codes[codeIndex]; | 777 var code = codes[codeIndex]; |
| 730 // Node tick counter. | 778 // Node tick counter. |
| 731 var count = data[_dataCursor++]; | 779 var count = data[_dataCursor++]; |
| 732 // Child node count. | 780 // Child node count. |
| 733 var children = data[_dataCursor++]; | 781 var children = data[_dataCursor++]; |
| 734 // Create node. | 782 // Create node. |
| 735 var node = new CodeCallTreeNode(code, count, children); | 783 var node = new CodeCallTreeNode(code, count); |
| 784 node.children.length = children; |
| 736 return node; | 785 return node; |
| 737 } | 786 } |
| 738 | 787 |
| 739 CodeCallTreeNode _readCodeTrie(List<int> data) { | 788 CodeCallTreeNode _readCodeTrie(List<int> data) { |
| 740 final nodeStack = new List<CodeCallTreeNode>(); | 789 final nodeStack = new List<CodeCallTreeNode>(); |
| 741 final childIndexStack = new List<int>(); | 790 final childIndexStack = new List<int>(); |
| 742 | 791 |
| 743 _dataCursor = 0; | 792 _dataCursor = 0; |
| 744 // Read root. | 793 // Read root. |
| 745 var root = _readCodeTrieNode(data); | 794 var root = _readCodeTrieNode(data); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 871 int approximateMillisecondsForCount(count) { | 920 int approximateMillisecondsForCount(count) { |
| 872 var MICROSECONDS_PER_MILLISECOND = 1000.0; | 921 var MICROSECONDS_PER_MILLISECOND = 1000.0; |
| 873 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND; | 922 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND; |
| 874 } | 923 } |
| 875 | 924 |
| 876 double approximateSecondsForCount(count) { | 925 double approximateSecondsForCount(count) { |
| 877 var MICROSECONDS_PER_SECOND = 1000000.0; | 926 var MICROSECONDS_PER_SECOND = 1000000.0; |
| 878 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; | 927 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; |
| 879 } | 928 } |
| 880 } | 929 } |
| OLD | NEW |