Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: runtime/observatory/lib/src/cpu_profile/cpu_profile.dart

Issue 1013563002: CPU profile displayed in three tables with a tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 class CodeCallTreeNode {
8 final ProfileCode profileCode; 8 final ProfileCode profileCode;
9 final int count; 9 final int count;
10 double get percentage => _percentage; 10 double get percentage => _percentage;
(...skipping 23 matching lines...) Expand all
34 } 34 }
35 if (inclusive) { 35 if (inclusive) {
36 node._percentage = parentPercentage * (node.count / parentCount); 36 node._percentage = parentPercentage * (node.count / parentCount);
37 } else { 37 } else {
38 node._percentage = (node.count / parentCount); 38 node._percentage = (node.count / parentCount);
39 } 39 }
40 for (var child in node.children) { 40 for (var child in node.children) {
41 _setCodePercentage(node, child); 41 _setCodePercentage(node, child);
42 } 42 }
43 } 43 }
44
45 _markCodeCallsInner(CodeCallTreeNode caller,
46 CodeCallTreeNode callee) {
47 if (caller != null) {
48 caller.profileCode._noteCallee(callee.profileCode, callee.count);
49 callee.profileCode._noteCaller(caller.profileCode, callee.count);
50 }
51
52 for (var child in callee.children) {
53 _markCodeCallsInner(callee, child);
54 }
55 }
56
57 _markCodeCalls() {
turnidge 2015/04/07 21:24:31 What does "marking" mean here? Is there another n
Cutch 2015/04/14 21:45:15 Went with _recordCallerAndCallees. The class is n
58 for (var child in root.children) {
59 _markCodeCallsInner(null, child);
60 }
61 }
44 } 62 }
45 63
46 class FunctionCallTreeNodeCode { 64 class FunctionCallTreeNodeCode {
47 final ProfileCode code; 65 final ProfileCode code;
48 final int ticks; 66 final int ticks;
49 FunctionCallTreeNodeCode(this.code, this.ticks); 67 FunctionCallTreeNodeCode(this.code, this.ticks);
50 } 68 }
51 69
52 class FunctionCallTreeNode { 70 class FunctionCallTreeNode {
53 final ProfileFunction profileFunction; 71 final ProfileFunction profileFunction;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 } 140 }
123 if (hasUnoptimizedCode()) { 141 if (hasUnoptimizedCode()) {
124 attributes.add('unoptimized'); 142 attributes.add('unoptimized');
125 } 143 }
126 if (isInlined()) { 144 if (isInlined()) {
127 attributes.add('inlined'); 145 attributes.add('inlined');
128 } 146 }
129 } 147 }
130 } 148 }
131 149
150 typedef bool FunctionCallTreeNodeFilter(FunctionCallTreeNode node);
151
152 class _FilteredTreeBuilder {
turnidge 2015/04/07 21:24:31 Can you make some of the functions in this class p
Cutch 2015/04/14 21:45:15 Done.
153 final FunctionCallTreeNodeFilter filter;
154 final FunctionCallTree tree;
155 final FunctionCallTree filtered;
156 final List currentPath = [];
157
158 _FilteredTreeBuilder(this.filter, FunctionCallTree tree)
159 : tree = tree,
160 filtered =
161 new FunctionCallTree(
162 tree.inclusive,
163 new FunctionCallTreeNode(
164 tree.root.profileFunction,
165 tree.root.count));
166
167 FunctionCallTreeNode findFunctionInChildren(FunctionCallTreeNode current,
168 FunctionCallTreeNode needle) {
169 for (var child in current.children) {
170 if (child.profileFunction == needle.profileFunction) {
171 return child;
172 }
173 }
174 return null;
175 }
176
177 FunctionCallTreeNode addCurrentPath() {
178 FunctionCallTreeNode current = filtered.root;
179 // Tree root is always the first element of the current path.
180 assert(tree.root == currentPath[0]);
181 // Assert that tree and filtered are different.
182 assert(tree.root != current);
183 for (var i = 1; i < currentPath.length; i++) {
184 var toAdd = currentPath[i];
185 var child = findFunctionInChildren(current, toAdd);
186 if (child == null) {
187 child = new FunctionCallTreeNode(toAdd.profileFunction, toAdd.count);
188 current.children.add(child);
189 }
190 current = child;
191 assert(current.count == toAdd.count);
192 }
193 return current;
194 }
195
196 appendTree(FunctionCallTreeNode current, FunctionCallTreeNode next) {
197 if (next == null) {
198 return;
199 }
200 var child = findFunctionInChildren(current, next);
201 if (child == null) {
202 child = new FunctionCallTreeNode(next.profileFunction, next.count);
203 current.children.add(child);
204 }
205 current = child;
206 for (var nextChild in next.children) {
207 appendTree(current, nextChild);
208 }
209 }
210
211 addTree(FunctionCallTreeNode child) {
212 var current = addCurrentPath();
213 appendTree(current, child);
214 }
215
216 descend(FunctionCallTreeNode current) {
217 if (current == null) {
218 return;
219 }
220 currentPath.add(current);
221
222 if (filter(current)) {
223 // Filter matched.
224 if (current.children.length == 0) {
225 // Have no children. Add this path.
226 addTree(null);
227 } else {
228 // Add all child trees.
229 for (var child in current.children) {
230 addTree(child);
231 }
232 }
233 } else {
234 // Did not match, descend to each child.
235 for (var child in current.children) {
236 descend(child);
237 }
238 }
239
240 var last = currentPath.removeLast();
241 assert(current == last);
242 }
243
244 build() {
245 assert(filtered != null);
246 assert(filter != null);
247 assert(tree != null);
248 descend(tree.root);
249 }
250 }
251
132 class FunctionCallTree { 252 class FunctionCallTree {
133 final bool inclusive; 253 final bool inclusive;
134 final FunctionCallTreeNode root; 254 final FunctionCallTreeNode root;
135 FunctionCallTree(this.inclusive, this.root) { 255 FunctionCallTree(this.inclusive, this.root) {
136 _setFunctionPercentage(null, root); 256 _setFunctionPercentage(null, root);
137 } 257 }
138 258
259 FunctionCallTree filtered(FunctionCallTreeNodeFilter filter) {
260 var treeFilter = new _FilteredTreeBuilder(filter, this);
261 treeFilter.build();
262 _setFunctionPercentage(null, treeFilter.filtered.root);
263 return treeFilter.filtered;
264 }
265
139 void _setFunctionPercentage(FunctionCallTreeNode parent, 266 void _setFunctionPercentage(FunctionCallTreeNode parent,
140 FunctionCallTreeNode node) { 267 FunctionCallTreeNode node) {
141 assert(node != null); 268 assert(node != null);
142 var parentPercentage = 1.0; 269 var parentPercentage = 1.0;
143 var parentCount = node.count; 270 var parentCount = node.count;
144 if (parent != null) { 271 if (parent != null) {
145 parentPercentage = parent._percentage; 272 parentPercentage = parent._percentage;
146 parentCount = parent.count; 273 parentCount = parent.count;
147 } 274 }
148 if (inclusive) { 275 if (inclusive) {
149 node._percentage = parentPercentage * (node.count / parentCount); 276 node._percentage = parentPercentage * (node.count / parentCount);
150 } else { 277 } else {
151 node._percentage = (node.count / parentCount); 278 node._percentage = (node.count / parentCount);
152 } 279 }
153 for (var child in node.children) { 280 for (var child in node.children) {
154 _setFunctionPercentage(node, child); 281 _setFunctionPercentage(node, child);
155 } 282 }
156 } 283 }
284
285 _markFunctionCallsInner(FunctionCallTreeNode caller,
286 FunctionCallTreeNode callee) {
287 if (caller != null) {
288 caller.profileFunction._noteCallee(callee.profileFunction, callee.count);
289 callee.profileFunction._noteCaller(caller.profileFunction, callee.count);
290 }
291 for (var child in callee.children) {
292 _markFunctionCallsInner(callee, child);
293 }
294 }
295
296 _markFunctionCalls() {
297 for (var child in root.children) {
298 _markFunctionCallsInner(null, child);
299 }
300 }
157 } 301 }
158 302
159 class CodeTick { 303 class CodeTick {
160 final int exclusiveTicks; 304 final int exclusiveTicks;
161 final int inclusiveTicks; 305 final int inclusiveTicks;
162 CodeTick(this.exclusiveTicks, this.inclusiveTicks); 306 CodeTick(this.exclusiveTicks, this.inclusiveTicks);
163 } 307 }
164 308
165 class InlineIntervalTick { 309 class InlineIntervalTick {
166 final int startAddress; 310 final int startAddress;
(...skipping 12 matching lines...) Expand all
179 double normalizedExclusiveTicks = 0.0; 323 double normalizedExclusiveTicks = 0.0;
180 double normalizedInclusiveTicks = 0.0; 324 double normalizedInclusiveTicks = 0.0;
181 final addressTicks = new Map<int, CodeTick>(); 325 final addressTicks = new Map<int, CodeTick>();
182 final intervalTicks = new Map<int, InlineIntervalTick>(); 326 final intervalTicks = new Map<int, InlineIntervalTick>();
183 String formattedInclusiveTicks = ''; 327 String formattedInclusiveTicks = '';
184 String formattedExclusiveTicks = ''; 328 String formattedExclusiveTicks = '';
185 String formattedExclusivePercent = ''; 329 String formattedExclusivePercent = '';
186 String formattedCpuTime = ''; 330 String formattedCpuTime = '';
187 String formattedOnStackTime = ''; 331 String formattedOnStackTime = '';
188 final Set<String> attributes = new Set<String>(); 332 final Set<String> attributes = new Set<String>();
333 final Map<ProfileCode, int> callers = new Map<ProfileCode, int>();
334 final Map<ProfileCode, int> callees = new Map<ProfileCode, int>();
189 335
190 void _processTicks(List<String> profileTicks) { 336 void _processTicks(List<String> profileTicks) {
191 assert(profileTicks != null); 337 assert(profileTicks != null);
192 assert((profileTicks.length % 3) == 0); 338 assert((profileTicks.length % 3) == 0);
193 for (var i = 0; i < profileTicks.length; i += 3) { 339 for (var i = 0; i < profileTicks.length; i += 3) {
194 var address = int.parse(profileTicks[i], radix:16); 340 var address = int.parse(profileTicks[i], radix:16);
195 var exclusive = int.parse(profileTicks[i + 1]); 341 var exclusive = int.parse(profileTicks[i + 1]);
196 var inclusive = int.parse(profileTicks[i + 2]); 342 var inclusive = int.parse(profileTicks[i + 2]);
197 var tick = new CodeTick(exclusive, inclusive); 343 var tick = new CodeTick(exclusive, inclusive);
198 addressTicks[address] = tick; 344 addressTicks[address] = tick;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 profile.approximateMillisecondsForCount(inclusiveTicks)); 401 profile.approximateMillisecondsForCount(inclusiveTicks));
256 402
257 formattedInclusiveTicks = 403 formattedInclusiveTicks =
258 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} ' 404 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
259 '($inclusiveTicks)'; 405 '($inclusiveTicks)';
260 406
261 formattedExclusiveTicks = 407 formattedExclusiveTicks =
262 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} ' 408 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
263 '($exclusiveTicks)'; 409 '($exclusiveTicks)';
264 } 410 }
411
412 _noteCaller(ProfileCode caller, int count) {
turnidge 2015/04/07 21:24:31 Maybe _addCaller and _addCallee?
Cutch 2015/04/14 21:45:15 Done.
413 var r = callers[caller];
414 if (r == null) {
415 r = 0;
416 }
417 callers[caller] = r + count;
418 }
419
420 _noteCallee(ProfileCode callee, int count) {
421 var r = callees[callee];
422 if (r == null) {
423 r = 0;
424 }
425 callees[callee] = r + count;
426 }
265 } 427 }
266 428
267 class ProfileFunction { 429 class ProfileFunction {
268 final CpuProfile profile; 430 final CpuProfile profile;
269 final ServiceFunction function; 431 final ServiceFunction function;
270 // List of compiled code objects containing this function. 432 // List of compiled code objects containing this function.
271 final List<ProfileCode> profileCodes = new List<ProfileCode>(); 433 final List<ProfileCode> profileCodes = new List<ProfileCode>();
434 final Map<ProfileFunction, int> callers = new Map<ProfileFunction, int>();
435 final Map<ProfileFunction, int> callees = new Map<ProfileFunction, int>();
436
272 // Absolute ticks: 437 // Absolute ticks:
273 int exclusiveTicks = 0; 438 int exclusiveTicks = 0;
274 int inclusiveTicks = 0; 439 int inclusiveTicks = 0;
275 440
276 // Global percentages: 441 // Global percentages:
277 double normalizedExclusiveTicks = 0.0; 442 double normalizedExclusiveTicks = 0.0;
278 double normalizedInclusiveTicks = 0.0; 443 double normalizedInclusiveTicks = 0.0;
279 444
280 String formattedInclusiveTicks = ''; 445 String formattedInclusiveTicks = '';
281 String formattedExclusiveTicks = ''; 446 String formattedExclusiveTicks = '';
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 } else if (function.kind == FunctionKind.kNative) { 514 } else if (function.kind == FunctionKind.kNative) {
350 attribs.add('native'); 515 attribs.add('native');
351 } else if (function.kind.isSynthetic()) { 516 } else if (function.kind.isSynthetic()) {
352 attribs.add('synthetic'); 517 attribs.add('synthetic');
353 } else { 518 } else {
354 attribs.add('dart'); 519 attribs.add('dart');
355 } 520 }
356 } 521 }
357 522
358 ProfileFunction.fromMap(this.profile, this.function, Map data) { 523 ProfileFunction.fromMap(this.profile, this.function, Map data) {
524 function.profile = this;
359 for (var codeIndex in data['codes']) { 525 for (var codeIndex in data['codes']) {
360 var profileCode = profile.codes[codeIndex]; 526 var profileCode = profile.codes[codeIndex];
361 profileCodes.add(profileCode); 527 profileCodes.add(profileCode);
362 } 528 }
363 profileCodes.sort(_sortCodes); 529 profileCodes.sort(_sortCodes);
364 530
365 if (hasOptimizedCode()) { 531 if (hasOptimizedCode()) {
366 attributes.add('optimized'); 532 attributes.add('optimized');
367 } 533 }
368 if (hasUnoptimizedCode()) { 534 if (hasUnoptimizedCode()) {
(...skipping 21 matching lines...) Expand all
390 profile.approximateMillisecondsForCount(inclusiveTicks)); 556 profile.approximateMillisecondsForCount(inclusiveTicks));
391 557
392 formattedInclusiveTicks = 558 formattedInclusiveTicks =
393 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} ' 559 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
394 '($inclusiveTicks)'; 560 '($inclusiveTicks)';
395 561
396 formattedExclusiveTicks = 562 formattedExclusiveTicks =
397 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} ' 563 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
398 '($exclusiveTicks)'; 564 '($exclusiveTicks)';
399 } 565 }
566
567 _noteCaller(ProfileFunction caller, int count) {
568 var r = callers[caller];
569 if (r == null) {
570 r = 0;
571 }
572 callers[caller] = r + count;
573 }
574
575 _noteCallee(ProfileFunction callee, int count) {
576 var r = callees[callee];
577 if (r == null) {
578 r = 0;
579 }
580 callees[callee] = r + count;
581 }
400 } 582 }
401 583
402 584
403 class CpuProfile { 585 class CpuProfile {
404 final double MICROSECONDS_PER_SECOND = 1000000.0; 586 final double MICROSECONDS_PER_SECOND = 1000000.0;
405 final double displayThreshold = 0.0002; // 0.02%. 587 final double displayThreshold = 0.0002; // 0.02%.
406 588
407 Isolate isolate; 589 Isolate isolate;
408 590
409 int sampleCount = 0; 591 int sampleCount = 0;
410 int samplePeriod = 0; 592 int samplePeriod = 0;
411 double sampleRate = 0.0; 593 double sampleRate = 0.0;
412 594
413 int stackDepth = 0; 595 int stackDepth = 0;
414 596
415 double timeSpan = 0.0; 597 double timeSpan = 0.0;
416 598
417 final Map<String, List> tries = <String, List>{}; 599 final Map<String, List> tries = <String, List>{};
418 final List<ProfileCode> codes = new List<ProfileCode>(); 600 final List<ProfileCode> codes = new List<ProfileCode>();
601 bool _markedCodeCalls = false;
419 final List<ProfileFunction> functions = new List<ProfileFunction>(); 602 final List<ProfileFunction> functions = new List<ProfileFunction>();
603 bool _markedFunctionCalls = false;
420 604
421 CodeCallTree loadCodeTree(String name) { 605 CodeCallTree loadCodeTree(String name) {
422 if (name == 'inclusive') { 606 if (name == 'inclusive') {
423 return _loadCodeTree(true, tries['inclusiveCodeTrie']); 607 return _loadCodeTree(true, tries['inclusiveCodeTrie']);
424 } else { 608 } else {
425 return _loadCodeTree(false, tries['exclusiveCodeTrie']); 609 return _loadCodeTree(false, tries['exclusiveCodeTrie']);
426 } 610 }
427 } 611 }
428 612
429 FunctionCallTree loadFunctionTree(String name) { 613 FunctionCallTree loadFunctionTree(String name) {
430 if (name == 'inclusive') { 614 if (name == 'inclusive') {
431 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']); 615 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']);
432 } else { 616 } else {
433 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']); 617 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']);
434 } 618 }
435 } 619 }
436 620
437 void clear() { 621 markCodeCalls() {
622 if (_markedCodeCalls) {
623 return;
624 }
625 _markedCodeCalls = true;
626 var tree = loadCodeTree('inclusive');
627 tree._markCodeCalls();
628 }
629
630 markFunctionCalls() {
631 if (_markedFunctionCalls) {
632 return;
633 }
634 _markedFunctionCalls = true;
635 var tree = loadFunctionTree('inclusive');
636 tree._markFunctionCalls();
637 }
638
639 clear() {
438 sampleCount = 0; 640 sampleCount = 0;
439 samplePeriod = 0; 641 samplePeriod = 0;
440 sampleRate = 0.0; 642 sampleRate = 0.0;
441 stackDepth = 0; 643 stackDepth = 0;
442 timeSpan = 0.0; 644 timeSpan = 0.0;
443 codes.clear(); 645 codes.clear();
444 functions.clear(); 646 functions.clear();
445 tries.clear(); 647 tries.clear();
648 _markedCodeCalls = false;
649 _markedFunctionCalls = false;
446 } 650 }
447 651
448 void load(Isolate isolate, ServiceMap profile) { 652 load(Isolate isolate, ServiceMap profile) {
449 clear(); 653 clear();
450 if ((isolate == null) || (profile == null)) { 654 if ((isolate == null) || (profile == null)) {
451 return; 655 return;
452 } 656 }
453 657
454 this.isolate = isolate; 658 this.isolate = isolate;
455 isolate.resetCachedProfileData(); 659 isolate.resetCachedProfileData();
456 660
457 sampleCount = profile['sampleCount']; 661 sampleCount = profile['sampleCount'];
458 samplePeriod = profile['samplePeriod']; 662 samplePeriod = profile['samplePeriod'];
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 int approximateMillisecondsForCount(count) { 861 int approximateMillisecondsForCount(count) {
658 var MICROSECONDS_PER_MILLISECOND = 1000.0; 862 var MICROSECONDS_PER_MILLISECOND = 1000.0;
659 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND; 863 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND;
660 } 864 }
661 865
662 double approximateSecondsForCount(count) { 866 double approximateSecondsForCount(count) {
663 var MICROSECONDS_PER_SECOND = 1000000.0; 867 var MICROSECONDS_PER_SECOND = 1000000.0;
664 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; 868 return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
665 } 869 }
666 } 870 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698