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 CodeTrieNode { | 7 class CodeCallTreeNode { |
8 final ProfileCode profileCode; | 8 final ProfileCode profileCode; |
9 final int count; | 9 final int count; |
10 final children = new List<CodeTrieNode>(); | 10 double get percentage => _percentage; |
11 CodeTrieNode(this.profileCode, this.count); | 11 double _percentage = 0.0; |
| 12 final children = new List<CodeCallTreeNode>(); |
| 13 final Set<String> attributes = new Set<String>(); |
| 14 CodeCallTreeNode(this.profileCode, this.count) { |
| 15 attributes.addAll(profileCode.attributes); |
| 16 } |
12 } | 17 } |
13 | 18 |
14 class FunctionTrieNodeCode { | 19 class CodeCallTree { |
| 20 final bool inclusive; |
| 21 final CodeCallTreeNode root; |
| 22 CodeCallTree(this.inclusive, this.root) { |
| 23 _setCodePercentage(null, root); |
| 24 } |
| 25 |
| 26 _setCodePercentage(CodeCallTreeNode parent, CodeCallTreeNode node) { |
| 27 assert(node != null); |
| 28 var parentPercentage = 1.0; |
| 29 var parentCount = node.count; |
| 30 if (parent != null) { |
| 31 parentPercentage = parent._percentage; |
| 32 parentCount = parent.count; |
| 33 } |
| 34 if (inclusive) { |
| 35 node._percentage = parentPercentage * (node.count / parentCount); |
| 36 } else { |
| 37 node._percentage = (node.count / parentCount); |
| 38 } |
| 39 for (var child in node.children) { |
| 40 _setCodePercentage(node, child); |
| 41 } |
| 42 } |
| 43 } |
| 44 |
| 45 class FunctionCallTreeNodeCode { |
15 final ProfileCode code; | 46 final ProfileCode code; |
16 final int ticks; | 47 final int ticks; |
17 FunctionTrieNodeCode(this.code, this.ticks); | 48 FunctionCallTreeNodeCode(this.code, this.ticks); |
18 } | 49 } |
19 | 50 |
20 class FunctionTrieNode { | 51 class FunctionCallTreeNode { |
21 final ProfileFunction profileFunction; | 52 final ProfileFunction profileFunction; |
22 final int count; | 53 final int count; |
23 final children = new List<FunctionTrieNode>(); | 54 double get percentage => _percentage; |
24 final codes = new List<FunctionTrieNodeCode>(); | 55 double _percentage = 0.0; |
| 56 final children = new List<FunctionCallTreeNode>(); |
| 57 final Set<String> attributes = new Set<String>(); |
| 58 final codes = new List<FunctionCallTreeNodeCode>(); |
25 int _totalCodeTicks = 0; | 59 int _totalCodeTicks = 0; |
26 int get totalCodesTicks => _totalCodeTicks; | 60 int get totalCodesTicks => _totalCodeTicks; |
27 FunctionTrieNode(this.profileFunction, this.count); | 61 |
| 62 // Does this function have an optimized version of itself? |
| 63 bool hasOptimizedCode() { |
| 64 for (var nodeCode in codes) { |
| 65 var profileCode = nodeCode.code; |
| 66 if (!profileCode.code.isDartCode) { |
| 67 continue; |
| 68 } |
| 69 if (profileCode.code.function != profileFunction.function) { |
| 70 continue; |
| 71 } |
| 72 if (profileCode.code.isOptimized) { |
| 73 return true; |
| 74 } |
| 75 } |
| 76 return false; |
| 77 } |
| 78 |
| 79 // Does this function have an unoptimized version of itself? |
| 80 bool hasUnoptimizedCode() { |
| 81 for (var nodeCode in codes) { |
| 82 var profileCode = nodeCode.code; |
| 83 if (!profileCode.code.isDartCode) { |
| 84 continue; |
| 85 } |
| 86 if (profileCode.code.kind == CodeKind.Stub) { |
| 87 continue; |
| 88 } |
| 89 if (!profileCode.code.isOptimized) { |
| 90 return true; |
| 91 } |
| 92 } |
| 93 return false; |
| 94 } |
| 95 |
| 96 // Has this function been inlined in another function? |
| 97 bool isInlined() { |
| 98 for (var nodeCode in codes) { |
| 99 var profileCode = nodeCode.code; |
| 100 if (!profileCode.code.isDartCode) { |
| 101 continue; |
| 102 } |
| 103 if (profileCode.code.kind == CodeKind.Stub) { |
| 104 continue; |
| 105 } |
| 106 // If the code's function isn't this function. |
| 107 if (profileCode.code.function != profileFunction.function) { |
| 108 return true; |
| 109 } |
| 110 } |
| 111 return false; |
| 112 } |
| 113 |
| 114 setCodeAttributes() { |
| 115 if (hasOptimizedCode()) { |
| 116 attributes.add('optimized'); |
| 117 } |
| 118 if (hasUnoptimizedCode()) { |
| 119 attributes.add('unoptimized'); |
| 120 } |
| 121 if (isInlined()) { |
| 122 attributes.add('inlined'); |
| 123 } |
| 124 } |
| 125 |
| 126 FunctionCallTreeNode(this.profileFunction, this.count) { |
| 127 profileFunction._addKindBasedAttributes(attributes); |
| 128 } |
| 129 } |
| 130 |
| 131 class FunctionCallTree { |
| 132 final bool inclusive; |
| 133 final FunctionCallTreeNode root; |
| 134 FunctionCallTree(this.inclusive, this.root) { |
| 135 _setFunctionPercentage(null, root); |
| 136 } |
| 137 |
| 138 void _setFunctionPercentage(FunctionCallTreeNode parent, |
| 139 FunctionCallTreeNode node) { |
| 140 assert(node != null); |
| 141 var parentPercentage = 1.0; |
| 142 var parentCount = node.count; |
| 143 if (parent != null) { |
| 144 parentPercentage = parent._percentage; |
| 145 parentCount = parent.count; |
| 146 } |
| 147 if (inclusive) { |
| 148 node._percentage = parentPercentage * (node.count / parentCount); |
| 149 } else { |
| 150 node._percentage = (node.count / parentCount); |
| 151 } |
| 152 for (var child in node.children) { |
| 153 _setFunctionPercentage(node, child); |
| 154 } |
| 155 } |
28 } | 156 } |
29 | 157 |
30 class CodeTick { | 158 class CodeTick { |
31 final int exclusiveTicks; | 159 final int exclusiveTicks; |
32 final int inclusiveTicks; | 160 final int inclusiveTicks; |
33 CodeTick(this.exclusiveTicks, this.inclusiveTicks); | 161 CodeTick(this.exclusiveTicks, this.inclusiveTicks); |
34 } | 162 } |
35 | 163 |
36 class InlineIntervalTick { | 164 class InlineIntervalTick { |
37 final int startAddress; | 165 final int startAddress; |
38 int _inclusiveTicks = 0; | 166 int _inclusiveTicks = 0; |
39 int get inclusiveTicks => _inclusiveTicks; | 167 int get inclusiveTicks => _inclusiveTicks; |
40 int _exclusiveTicks = 0; | 168 int _exclusiveTicks = 0; |
41 int get exclusiveTicks => _exclusiveTicks; | 169 int get exclusiveTicks => _exclusiveTicks; |
42 InlineIntervalTick(this.startAddress); | 170 InlineIntervalTick(this.startAddress); |
43 } | 171 } |
44 | 172 |
45 class ProfileCode { | 173 class ProfileCode { |
46 final CpuProfile profile; | 174 final CpuProfile profile; |
47 final Code code; | 175 final Code code; |
48 int exclusiveTicks; | 176 int exclusiveTicks; |
49 int inclusiveTicks; | 177 int inclusiveTicks; |
| 178 double normalizedExclusiveTicks = 0.0; |
| 179 double normalizedInclusiveTicks = 0.0; |
50 final addressTicks = new Map<int, CodeTick>(); | 180 final addressTicks = new Map<int, CodeTick>(); |
51 final intervalTicks = new Map<int, InlineIntervalTick>(); | 181 final intervalTicks = new Map<int, InlineIntervalTick>(); |
52 String formattedInclusiveTicks = ''; | 182 String formattedInclusiveTicks = ''; |
53 String formattedExclusiveTicks = ''; | 183 String formattedExclusiveTicks = ''; |
| 184 String formattedExclusivePercent = ''; |
| 185 String formattedCpuTime = ''; |
| 186 String formattedOnStackTime = ''; |
| 187 final Set<String> attributes = new Set<String>(); |
54 | 188 |
55 void _processTicks(List<String> profileTicks) { | 189 void _processTicks(List<String> profileTicks) { |
56 assert(profileTicks != null); | 190 assert(profileTicks != null); |
57 assert((profileTicks.length % 3) == 0); | 191 assert((profileTicks.length % 3) == 0); |
58 for (var i = 0; i < profileTicks.length; i += 3) { | 192 for (var i = 0; i < profileTicks.length; i += 3) { |
59 var address = int.parse(profileTicks[i], radix:16); | 193 var address = int.parse(profileTicks[i], radix:16); |
60 var exclusive = int.parse(profileTicks[i + 1]); | 194 var exclusive = int.parse(profileTicks[i + 1]); |
61 var inclusive = int.parse(profileTicks[i + 2]); | 195 var inclusive = int.parse(profileTicks[i + 2]); |
62 var tick = new CodeTick(exclusive, inclusive); | 196 var tick = new CodeTick(exclusive, inclusive); |
63 addressTicks[address] = tick; | 197 addressTicks[address] = tick; |
(...skipping 11 matching lines...) Expand all Loading... |
75 } | 209 } |
76 } | 210 } |
77 } | 211 } |
78 | 212 |
79 ProfileCode.fromMap(this.profile, this.code, Map data) { | 213 ProfileCode.fromMap(this.profile, this.code, Map data) { |
80 assert(profile != null); | 214 assert(profile != null); |
81 assert(code != null); | 215 assert(code != null); |
82 | 216 |
83 code.profile = this; | 217 code.profile = this; |
84 | 218 |
| 219 if (code.isDartCode) { |
| 220 if (code.isOptimized) { |
| 221 attributes.add('optimized'); |
| 222 } else { |
| 223 attributes.add('unoptimized'); |
| 224 } |
| 225 } |
| 226 if (code.isDartCode) { |
| 227 attributes.add('dart'); |
| 228 } else if (code.kind == CodeKind.Tag) { |
| 229 attributes.add('tag'); |
| 230 } else if (code.kind == CodeKind.Native) { |
| 231 attributes.add('native'); |
| 232 } |
85 inclusiveTicks = int.parse(data['inclusiveTicks']); | 233 inclusiveTicks = int.parse(data['inclusiveTicks']); |
86 exclusiveTicks = int.parse(data['exclusiveTicks']); | 234 exclusiveTicks = int.parse(data['exclusiveTicks']); |
| 235 |
| 236 normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount; |
| 237 |
| 238 normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount; |
| 239 |
87 var ticks = data['ticks']; | 240 var ticks = data['ticks']; |
88 if (ticks != null) { | 241 if (ticks != null) { |
89 _processTicks(ticks); | 242 _processTicks(ticks); |
90 } | 243 } |
91 | 244 |
| 245 formattedExclusivePercent = |
| 246 Utils.formatPercent(exclusiveTicks, profile.sampleCount); |
| 247 |
| 248 formattedCpuTime = |
| 249 Utils.formatTimeMilliseconds( |
| 250 profile.approximateMillisecondsForCount(exclusiveTicks)); |
| 251 |
| 252 formattedOnStackTime = |
| 253 Utils.formatTimeMilliseconds( |
| 254 profile.approximateMillisecondsForCount(inclusiveTicks)); |
| 255 |
92 formattedInclusiveTicks = | 256 formattedInclusiveTicks = |
93 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} ' | 257 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} ' |
94 '($inclusiveTicks)'; | 258 '($inclusiveTicks)'; |
95 | 259 |
96 formattedExclusiveTicks = | 260 formattedExclusiveTicks = |
97 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} ' | 261 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} ' |
98 '($exclusiveTicks)'; | 262 '($exclusiveTicks)'; |
99 } | 263 } |
100 } | 264 } |
101 | 265 |
102 class ProfileFunction { | 266 class ProfileFunction { |
103 final CpuProfile profile; | 267 final CpuProfile profile; |
104 final ServiceFunction function; | 268 final ServiceFunction function; |
105 // List of compiled code objects containing this function. | 269 // List of compiled code objects containing this function. |
106 final List<ProfileCode> profileCodes = new List<ProfileCode>(); | 270 final List<ProfileCode> profileCodes = new List<ProfileCode>(); |
107 | |
108 // Absolute ticks: | 271 // Absolute ticks: |
109 int exclusiveTicks = 0; | 272 int exclusiveTicks = 0; |
110 int inclusiveTicks = 0; | 273 int inclusiveTicks = 0; |
111 | 274 |
112 // Global percentages: | 275 // Global percentages: |
113 double globalExclusiveTicks = 0.0; | 276 double normalizedExclusiveTicks = 0.0; |
114 double globalInclusiveTicks = 0.0; | 277 double normalizedInclusiveTicks = 0.0; |
| 278 |
| 279 String formattedInclusiveTicks = ''; |
| 280 String formattedExclusiveTicks = ''; |
| 281 String formattedExclusivePercent = ''; |
| 282 String formattedCpuTime = ''; |
| 283 String formattedOnStackTime = ''; |
| 284 final Set<String> attributes = new Set<String>(); |
115 | 285 |
116 int _sortCodes(ProfileCode a, ProfileCode b) { | 286 int _sortCodes(ProfileCode a, ProfileCode b) { |
117 if (a.code.isOptimized == b.code.isOptimized) { | 287 if (a.code.isOptimized == b.code.isOptimized) { |
118 return b.code.profile.exclusiveTicks - a.code.profile.exclusiveTicks; | 288 return b.code.profile.exclusiveTicks - a.code.profile.exclusiveTicks; |
119 } | 289 } |
120 if (a.code.isOptimized) { | 290 if (a.code.isOptimized) { |
121 return -1; | 291 return -1; |
122 } | 292 } |
123 return 1; | 293 return 1; |
124 } | 294 } |
125 | 295 |
| 296 // Does this function have an optimized version of itself? |
| 297 bool hasOptimizedCode() { |
| 298 for (var profileCode in profileCodes) { |
| 299 if (profileCode.code.function != function) { |
| 300 continue; |
| 301 } |
| 302 if (profileCode.code.isOptimized) { |
| 303 return true; |
| 304 } |
| 305 } |
| 306 return false; |
| 307 } |
| 308 |
| 309 // Does this function have an unoptimized version of itself? |
| 310 bool hasUnoptimizedCode() { |
| 311 for (var profileCode in profileCodes) { |
| 312 if (profileCode.code.kind == CodeKind.Stub) { |
| 313 continue; |
| 314 } |
| 315 if (!profileCode.code.isDartCode) { |
| 316 continue; |
| 317 } |
| 318 if (!profileCode.code.isOptimized) { |
| 319 return true; |
| 320 } |
| 321 } |
| 322 return false; |
| 323 } |
| 324 |
| 325 // Has this function been inlined in another function? |
| 326 bool isInlined() { |
| 327 for (var profileCode in profileCodes) { |
| 328 if (profileCode.code.kind == CodeKind.Stub) { |
| 329 continue; |
| 330 } |
| 331 if (!profileCode.code.isDartCode) { |
| 332 continue; |
| 333 } |
| 334 // If the code's function isn't this function. |
| 335 if (profileCode.code.function != function) { |
| 336 return true; |
| 337 } |
| 338 } |
| 339 return false; |
| 340 } |
| 341 |
| 342 void _addKindBasedAttributes(Set<String> attribs) { |
| 343 if (function.kind == FunctionKind.kTag) { |
| 344 attribs.add('tag'); |
| 345 } else if (function.kind == FunctionKind.kStub) { |
| 346 attribs.add('dart'); |
| 347 attribs.add('stub'); |
| 348 } else if (function.kind == FunctionKind.kNative) { |
| 349 attribs.add('native'); |
| 350 } else if (function.kind.isSynthetic()) { |
| 351 attribs.add('synthetic'); |
| 352 } else { |
| 353 attribs.add('dart'); |
| 354 } |
| 355 } |
| 356 |
126 ProfileFunction.fromMap(this.profile, this.function, Map data) { | 357 ProfileFunction.fromMap(this.profile, this.function, Map data) { |
127 for (var codeIndex in data['codes']) { | 358 for (var codeIndex in data['codes']) { |
128 var profileCode = profile.codes[codeIndex]; | 359 var profileCode = profile.codes[codeIndex]; |
129 profileCodes.add(profileCode); | 360 profileCodes.add(profileCode); |
130 } | 361 } |
131 profileCodes.sort(_sortCodes); | 362 profileCodes.sort(_sortCodes); |
132 | 363 |
| 364 if (hasOptimizedCode()) { |
| 365 attributes.add('optimized'); |
| 366 } |
| 367 if (hasUnoptimizedCode()) { |
| 368 attributes.add('unoptimized'); |
| 369 } |
| 370 if (isInlined()) { |
| 371 attributes.add('inlined'); |
| 372 } |
| 373 _addKindBasedAttributes(attributes); |
133 exclusiveTicks = int.parse(data['exclusiveTicks']); | 374 exclusiveTicks = int.parse(data['exclusiveTicks']); |
134 inclusiveTicks = int.parse(data['inclusiveTicks']); | 375 inclusiveTicks = int.parse(data['inclusiveTicks']); |
135 | 376 |
136 globalExclusiveTicks = exclusiveTicks / profile.sampleCount; | 377 normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount; |
137 globalInclusiveTicks = inclusiveTicks / profile.sampleCount; | 378 normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount; |
| 379 |
| 380 formattedExclusivePercent = |
| 381 Utils.formatPercent(exclusiveTicks, profile.sampleCount); |
| 382 |
| 383 formattedCpuTime = |
| 384 Utils.formatTimeMilliseconds( |
| 385 profile.approximateMillisecondsForCount(exclusiveTicks)); |
| 386 |
| 387 formattedOnStackTime = |
| 388 Utils.formatTimeMilliseconds( |
| 389 profile.approximateMillisecondsForCount(inclusiveTicks)); |
| 390 |
| 391 formattedInclusiveTicks = |
| 392 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} ' |
| 393 '($inclusiveTicks)'; |
| 394 |
| 395 formattedExclusiveTicks = |
| 396 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} ' |
| 397 '($exclusiveTicks)'; |
138 } | 398 } |
139 } | 399 } |
140 | 400 |
141 | 401 |
142 class CpuProfile { | 402 class CpuProfile { |
143 final double MICROSECONDS_PER_SECOND = 1000000.0; | 403 final double MICROSECONDS_PER_SECOND = 1000000.0; |
144 final double displayThreshold = 0.0002; // 0.02%. | 404 final double displayThreshold = 0.0002; // 0.02%. |
145 | 405 |
146 Isolate isolate; | 406 Isolate isolate; |
147 | 407 |
148 int sampleCount = 0; | 408 int sampleCount = 0; |
149 int samplePeriod = 0; | 409 int samplePeriod = 0; |
150 double sampleRate = 0.0; | 410 double sampleRate = 0.0; |
151 | 411 |
152 int stackDepth = 0; | 412 int stackDepth = 0; |
153 | 413 |
154 double timeSpan = 0.0; | 414 double timeSpan = 0.0; |
155 | 415 |
156 CodeTrieNode codeTrieRoot; | 416 final Map<String, CodeCallTree> codeTrees = |
157 FunctionTrieNode functionTrieRoot; | 417 <String, CodeCallTree>{}; |
| 418 final Map<String, FunctionCallTree> functionTrees = |
| 419 <String, FunctionCallTree>{}; |
158 | 420 |
159 final List<ProfileCode> codes = new List<ProfileCode>(); | 421 final List<ProfileCode> codes = new List<ProfileCode>(); |
160 final List<ProfileFunction> functions = new List<ProfileFunction>(); | 422 final List<ProfileFunction> functions = new List<ProfileFunction>(); |
161 | 423 |
162 void clear() { | 424 void clear() { |
163 sampleCount = 0; | 425 sampleCount = 0; |
164 samplePeriod = 0; | 426 samplePeriod = 0; |
165 sampleRate = 0.0; | 427 sampleRate = 0.0; |
166 stackDepth = 0; | 428 stackDepth = 0; |
167 timeSpan = 0.0; | 429 timeSpan = 0.0; |
168 codeTrieRoot = null; | 430 codeTrees.clear(); |
169 functionTrieRoot = null; | 431 functionTrees.clear(); |
170 codes.clear(); | 432 codes.clear(); |
171 functions.clear(); | 433 functions.clear(); |
172 } | 434 } |
173 | 435 |
174 void load(Isolate isolate, ServiceMap profile) { | 436 void load(Isolate isolate, ServiceMap profile) { |
175 if ((isolate == null) || (profile == null)) { | 437 if ((isolate == null) || (profile == null)) { |
176 return; | 438 return; |
177 } | 439 } |
178 | 440 |
179 this.isolate = isolate; | 441 this.isolate = isolate; |
(...skipping 15 matching lines...) Expand all Loading... |
195 } | 457 } |
196 | 458 |
197 // Process function table. | 459 // Process function table. |
198 for (var profileFunction in profile['functions']) { | 460 for (var profileFunction in profile['functions']) { |
199 ServiceFunction function = profileFunction['function']; | 461 ServiceFunction function = profileFunction['function']; |
200 assert(function != null); | 462 assert(function != null); |
201 functions.add( | 463 functions.add( |
202 new ProfileFunction.fromMap(this, function, profileFunction)); | 464 new ProfileFunction.fromMap(this, function, profileFunction)); |
203 } | 465 } |
204 | 466 |
205 // Process code trie. | 467 // Process code trees. |
206 var exclusiveCodeTrie = profile['exclusiveCodeTrie']; | 468 var exclusiveCodeTrie = profile['exclusiveCodeTrie']; |
207 assert(exclusiveCodeTrie != null); | 469 if (exclusiveCodeTrie != null) { |
208 codeTrieRoot = _processCodeTrie(exclusiveCodeTrie); | 470 codeTrees['exclusive'] = _loadCodeTree(false, exclusiveCodeTrie); |
| 471 } |
| 472 var inclusiveCodeTrie = profile['inclusiveCodeTrie']; |
| 473 if (inclusiveCodeTrie != null) { |
| 474 codeTrees['inclusive'] = _loadCodeTree(true, inclusiveCodeTrie); |
| 475 } |
209 | 476 |
210 // Process function trie. | 477 // Process function trees. |
211 var exclusiveFunctionTrie = profile['exclusiveFunctionTrie']; | 478 var exclusiveFunctionTrie = profile['exclusiveFunctionTrie']; |
212 assert(exclusiveFunctionTrie != null); | 479 if (exclusiveFunctionTrie != null) { |
213 functionTrieRoot = _processFunctionTrie(exclusiveFunctionTrie); | 480 functionTrees['exclusive'] = |
| 481 _loadFunctionTree(false, exclusiveFunctionTrie); |
| 482 } |
| 483 var inclusiveFunctionTrie = profile['inclusiveFunctionTrie']; |
| 484 if (inclusiveFunctionTrie != null) { |
| 485 functionTrees['inclusive'] = |
| 486 _loadFunctionTree(true, inclusiveFunctionTrie); |
| 487 } |
214 } | 488 } |
215 | 489 |
216 // Data shared across calls to _read*TrieNode. | 490 // Data shared across calls to _read*TrieNode. |
217 int _trieDataCursor; | 491 int _trieDataCursor; |
218 List<int> _trieData; | 492 List<int> _trieData; |
219 | 493 |
220 // The code trie is serialized as a list of integers. Each node | 494 // The code trie is serialized as a list of integers. Each node |
221 // is recreated by consuming some portion of the list. The format is as | 495 // is recreated by consuming some portion of the list. The format is as |
222 // follows: | 496 // follows: |
223 // [0] index into codeTable of code object. | 497 // [0] index into codeTable of code object. |
224 // [1] tick count (number of times this stack frame occured). | 498 // [1] tick count (number of times this stack frame occured). |
225 // [2] child node count | 499 // [2] child node count |
226 // Reading the trie is done by recursively reading the tree depth-first | 500 // Reading the trie is done by recursively reading the tree depth-first |
227 // pre-order. | 501 // pre-order. |
228 CodeTrieNode _processCodeTrie(List<int> data) { | 502 CodeCallTree _loadCodeTree(bool inclusive, List<int> data) { |
229 // Setup state shared across calls to _readTrieNode. | 503 // Setup state shared across calls to _readTrieNode. |
230 _trieDataCursor = 0; | 504 _trieDataCursor = 0; |
231 _trieData = data; | 505 _trieData = data; |
232 if (_trieData == null) { | 506 if (_trieData == null) { |
233 return null; | 507 return null; |
234 } | 508 } |
235 if (_trieData.length < 3) { | 509 if (_trieData.length < 3) { |
236 // Not enough integers for 1 node. | 510 // Not enough integers for 1 node. |
237 return null; | 511 return null; |
238 } | 512 } |
239 // Read the tree, returns the root node. | 513 // Read the tree, returns the root node. |
240 return _readCodeTrieNode(); | 514 var root = _readCodeTrieNode(); |
| 515 return new CodeCallTree(inclusive, root); |
241 } | 516 } |
242 | 517 |
243 CodeTrieNode _readCodeTrieNode() { | 518 CodeCallTreeNode _readCodeTrieNode() { |
244 // Read index into code table. | 519 // Read index into code table. |
245 var index = _trieData[_trieDataCursor++]; | 520 var index = _trieData[_trieDataCursor++]; |
246 // Lookup code object. | 521 // Lookup code object. |
247 var code = codes[index]; | 522 var code = codes[index]; |
248 // Frame counter. | 523 // Frame counter. |
249 var count = _trieData[_trieDataCursor++]; | 524 var count = _trieData[_trieDataCursor++]; |
250 // Create node. | 525 // Create node. |
251 var node = new CodeTrieNode(code, count); | 526 var node = new CodeCallTreeNode(code, count); |
252 // Number of children. | 527 // Number of children. |
253 var children = _trieData[_trieDataCursor++]; | 528 var children = _trieData[_trieDataCursor++]; |
254 // Recursively read child nodes. | 529 // Recursively read child nodes. |
255 for (var i = 0; i < children; i++) { | 530 for (var i = 0; i < children; i++) { |
256 var child = _readCodeTrieNode(); | 531 var child = _readCodeTrieNode(); |
257 node.children.add(child); | 532 node.children.add(child); |
258 } | 533 } |
259 return node; | 534 return node; |
260 } | 535 } |
261 | 536 |
262 FunctionTrieNode _processFunctionTrie(List<int> data) { | 537 FunctionCallTree _loadFunctionTree(bool inclusive, List<int> data) { |
263 // Setup state shared across calls to _readTrieNode. | 538 // Setup state shared across calls to _readTrieNode. |
264 _trieDataCursor = 0; | 539 _trieDataCursor = 0; |
265 _trieData = data; | 540 _trieData = data; |
266 if (_trieData == null) { | 541 if (_trieData == null) { |
267 return null; | 542 return null; |
268 } | 543 } |
269 if (_trieData.length < 3) { | 544 if (_trieData.length < 3) { |
270 // Not enough integers for 1 node. | 545 // Not enough integers for 1 node. |
271 return null; | 546 return null; |
272 } | 547 } |
273 // Read the tree, returns the root node. | 548 // Read the tree, returns the root node. |
274 return _readFunctionTrieNode(); | 549 var root = _readFunctionTrieNode(); |
| 550 return new FunctionCallTree(inclusive, root); |
275 } | 551 } |
276 | 552 |
277 FunctionTrieNode _readFunctionTrieNode() { | 553 FunctionCallTreeNode _readFunctionTrieNode() { |
278 // Read index into function table. | 554 // Read index into function table. |
279 var index = _trieData[_trieDataCursor++]; | 555 var index = _trieData[_trieDataCursor++]; |
280 // Lookup function object. | 556 // Lookup function object. |
281 var function = functions[index]; | 557 var function = functions[index]; |
282 // Frame counter. | 558 // Frame counter. |
283 var count = _trieData[_trieDataCursor++]; | 559 var count = _trieData[_trieDataCursor++]; |
284 // Create node. | 560 // Create node. |
285 var node = new FunctionTrieNode(function, count); | 561 var node = new FunctionCallTreeNode(function, count); |
286 // Number of code index / count pairs. | 562 // Number of code index / count pairs. |
287 var codeCount = _trieData[_trieDataCursor++]; | 563 var codeCount = _trieData[_trieDataCursor++]; |
288 var totalCodeTicks = 0; | 564 var totalCodeTicks = 0; |
289 for (var i = 0; i < codeCount; i++) { | 565 for (var i = 0; i < codeCount; i++) { |
290 var codeIndex = _trieData[_trieDataCursor++]; | 566 var codeIndex = _trieData[_trieDataCursor++]; |
291 var code = codes[codeIndex]; | 567 var code = codes[codeIndex]; |
292 var codeTicks = _trieData[_trieDataCursor++]; | 568 var codeTicks = _trieData[_trieDataCursor++]; |
293 totalCodeTicks += codeTicks; | 569 totalCodeTicks += codeTicks; |
294 var nodeCode = new FunctionTrieNodeCode(code, codeTicks); | 570 var nodeCode = new FunctionCallTreeNodeCode(code, codeTicks); |
295 node.codes.add(nodeCode); | 571 node.codes.add(nodeCode); |
| 572 node.setCodeAttributes(); |
296 } | 573 } |
297 node._totalCodeTicks = totalCodeTicks; | 574 node._totalCodeTicks = totalCodeTicks; |
298 // Number of children. | 575 // Number of children. |
299 var children = _trieData[_trieDataCursor++]; | 576 var children = _trieData[_trieDataCursor++]; |
300 // Recursively read child nodes. | 577 // Recursively read child nodes. |
301 for (var i = 0; i < children; i++) { | 578 for (var i = 0; i < children; i++) { |
302 var child = _readFunctionTrieNode(); | 579 var child = _readFunctionTrieNode(); |
303 node.children.add(child); | 580 node.children.add(child); |
304 } | 581 } |
305 return node; | 582 return node; |
306 } | 583 } |
307 | 584 |
| 585 int approximateMillisecondsForCount(count) { |
| 586 var MICROSECONDS_PER_MILLISECOND = 1000.0; |
| 587 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND; |
| 588 } |
| 589 |
308 double approximateSecondsForCount(count) { | 590 double approximateSecondsForCount(count) { |
309 var MICROSECONDS_PER_SECOND = 1000000.0; | 591 var MICROSECONDS_PER_SECOND = 1000000.0; |
310 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; | 592 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; |
311 } | 593 } |
312 } | 594 } |
OLD | NEW |