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

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

Issue 2204563003: Converted Observatory cpu-profile element (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Added lifecycle tests Created 4 years, 4 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
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 abstract class CallTreeNode { 7 abstract class CallTreeNode<NodeT extends M.CallTreeNode>
8 final List<CallTreeNode> children; 8 implements M.CallTreeNode {
9 final List<NodeT> children;
9 final int count; 10 final int count;
10 double get percentage => _percentage; 11 double get percentage => _percentage;
11 double _percentage = 0.0; 12 double _percentage = 0.0;
12 final Set<String> attributes = new Set<String>(); 13 final Set<String> attributes = new Set<String>();
13 14
14 // Either a ProfileCode or a ProfileFunction. 15 // Either a ProfileCode or a ProfileFunction.
15 Object get profileData; 16 Object get profileData;
16 String get name; 17 String get name;
17 18
18 CallTreeNode(this.children, this.count); 19 CallTreeNode(this.children, this.count);
19 } 20 }
20 21
21 class CodeCallTreeNode extends CallTreeNode { 22 class CodeCallTreeNode extends CallTreeNode<CodeCallTreeNode>
23 implements M.CodeCallTreeNode {
22 final ProfileCode profileCode; 24 final ProfileCode profileCode;
23 25
24 Object get profileData => profileCode; 26 Object get profileData => profileCode;
25 27
26 String get name => profileCode.code.name; 28 String get name => profileCode.code.name;
27 29
28 final Set<String> attributes = new Set<String>(); 30 final Set<String> attributes = new Set<String>();
29 CodeCallTreeNode(this.profileCode, int count) 31 CodeCallTreeNode(this.profileCode, int count)
30 : super(new List<CodeCallTreeNode>(), count) { 32 : super(new List<CodeCallTreeNode>(), count) {
31 attributes.addAll(profileCode.attributes); 33 attributes.addAll(profileCode.attributes);
32 } 34 }
33 } 35 }
34 36
35 class CallTree { 37 class CallTree<NodeT extends CallTreeNode> {
36 final bool inclusive; 38 final bool inclusive;
37 final CallTreeNode root; 39 final NodeT root;
38 40
39 CallTree(this.inclusive, this.root); 41 CallTree(this.inclusive, this.root);
40 } 42 }
41 43
42 class CodeCallTree extends CallTree { 44 class CodeCallTree extends CallTree<CodeCallTreeNode>
45 implements M.CodeCallTree {
43 CodeCallTree(bool inclusive, CodeCallTreeNode root) 46 CodeCallTree(bool inclusive, CodeCallTreeNode root)
44 : super(inclusive, root) { 47 : super(inclusive, root) {
45 _setCodePercentage(null, root); 48 _setCodePercentage(null, root);
46 } 49 }
47 50
48 CodeCallTree filtered(CallTreeNodeFilter filter) { 51 CodeCallTree filtered(CallTreeNodeFilter filter) {
49 var treeFilter = new _FilteredCodeCallTreeBuilder(filter, this); 52 var treeFilter = new _FilteredCodeCallTreeBuilder(filter, this);
50 treeFilter.build(); 53 treeFilter.build();
51 _setCodePercentage(null, treeFilter.filtered.root); 54 _setCodePercentage(null, treeFilter.filtered.root);
52 return treeFilter.filtered; 55 return treeFilter.filtered;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 : super(filter, tree, 301 : super(filter, tree,
299 new CodeCallTree(tree.inclusive, 302 new CodeCallTree(tree.inclusive,
300 new CodeCallTreeNode(tree.root.profileData, 303 new CodeCallTreeNode(tree.root.profileData,
301 tree.root.count))); 304 tree.root.count)));
302 305
303 _copyNode(CodeCallTreeNode node) { 306 _copyNode(CodeCallTreeNode node) {
304 return new CodeCallTreeNode(node.profileData, node.count); 307 return new CodeCallTreeNode(node.profileData, node.count);
305 } 308 }
306 } 309 }
307 310
308 class FunctionCallTree extends CallTree { 311 class FunctionCallTree extends CallTree implements M.FunctionCallTree {
309 FunctionCallTree(bool inclusive, FunctionCallTreeNode root) 312 FunctionCallTree(bool inclusive, FunctionCallTreeNode root)
310 : super(inclusive, root) { 313 : super(inclusive, root) {
311 _setFunctionPercentage(null, root); 314 _setFunctionPercentage(null, root);
312 } 315 }
313 316
314 FunctionCallTree filtered(CallTreeNodeFilter filter) { 317 FunctionCallTree filtered(CallTreeNodeFilter filter) {
315 var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this); 318 var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this);
316 treeFilter.build(); 319 treeFilter.build();
317 _setFunctionPercentage(null, treeFilter.filtered.root); 320 _setFunctionPercentage(null, treeFilter.filtered.root);
318 return treeFilter.filtered; 321 return treeFilter.filtered;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 366
364 class InlineIntervalTick { 367 class InlineIntervalTick {
365 final int startAddress; 368 final int startAddress;
366 int _inclusiveTicks = 0; 369 int _inclusiveTicks = 0;
367 int get inclusiveTicks => _inclusiveTicks; 370 int get inclusiveTicks => _inclusiveTicks;
368 int _exclusiveTicks = 0; 371 int _exclusiveTicks = 0;
369 int get exclusiveTicks => _exclusiveTicks; 372 int get exclusiveTicks => _exclusiveTicks;
370 InlineIntervalTick(this.startAddress); 373 InlineIntervalTick(this.startAddress);
371 } 374 }
372 375
373 class ProfileCode { 376 class ProfileCode implements M.ProfileCode {
374 final CpuProfile profile; 377 final CpuProfile profile;
375 final Code code; 378 final Code code;
376 int exclusiveTicks; 379 int exclusiveTicks;
377 int inclusiveTicks; 380 int inclusiveTicks;
378 double normalizedExclusiveTicks = 0.0; 381 double normalizedExclusiveTicks = 0.0;
379 double normalizedInclusiveTicks = 0.0; 382 double normalizedInclusiveTicks = 0.0;
380 final addressTicks = new Map<int, CodeTick>(); 383 final addressTicks = new Map<int, CodeTick>();
381 final intervalTicks = new Map<int, InlineIntervalTick>(); 384 final intervalTicks = new Map<int, InlineIntervalTick>();
382 String formattedInclusiveTicks = ''; 385 String formattedInclusiveTicks = '';
383 String formattedExclusiveTicks = ''; 386 String formattedExclusiveTicks = '';
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 484
482 _recordCallee(ProfileCode callee, int count) { 485 _recordCallee(ProfileCode callee, int count) {
483 var r = callees[callee]; 486 var r = callees[callee];
484 if (r == null) { 487 if (r == null) {
485 r = 0; 488 r = 0;
486 } 489 }
487 callees[callee] = r + count; 490 callees[callee] = r + count;
488 } 491 }
489 } 492 }
490 493
491 class ProfileFunction { 494 class ProfileFunction implements M.ProfileFunction {
492 final CpuProfile profile; 495 final CpuProfile profile;
493 final ServiceFunction function; 496 final ServiceFunction function;
494 // List of compiled code objects containing this function. 497 // List of compiled code objects containing this function.
495 final List<ProfileCode> profileCodes = new List<ProfileCode>(); 498 final List<ProfileCode> profileCodes = new List<ProfileCode>();
496 final Map<ProfileFunction, int> callers = new Map<ProfileFunction, int>(); 499 final Map<ProfileFunction, int> callers = new Map<ProfileFunction, int>();
497 final Map<ProfileFunction, int> callees = new Map<ProfileFunction, int>(); 500 final Map<ProfileFunction, int> callees = new Map<ProfileFunction, int>();
498 501
499 // Absolute ticks: 502 // Absolute ticks:
500 int exclusiveTicks = 0; 503 int exclusiveTicks = 0;
501 int inclusiveTicks = 0; 504 int inclusiveTicks = 0;
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 var r = callees[callee]; 636 var r = callees[callee];
634 if (r == null) { 637 if (r == null) {
635 r = 0; 638 r = 0;
636 } 639 }
637 callees[callee] = r + count; 640 callees[callee] = r + count;
638 } 641 }
639 } 642 }
640 643
641 644
642 // TODO(johnmccutchan): Rename to SampleProfile 645 // TODO(johnmccutchan): Rename to SampleProfile
643 class CpuProfile { 646 class CpuProfile extends M.SampleProfile {
644 final double MICROSECONDS_PER_SECOND = 1000000.0;
645 final double displayThreshold = 0.0002; // 0.02%.
646 647
647 Isolate isolate; 648 Isolate isolate;
648 649
649 int sampleCount = 0; 650 int sampleCount = 0;
650 int samplePeriod = 0; 651 int samplePeriod = 0;
651 double sampleRate = 0.0; 652 double sampleRate = 0.0;
652 653
653 int stackDepth = 0; 654 int stackDepth = 0;
654 655
655 double timeSpan = 0.0; 656 double timeSpan = 0.0;
656 657
657 final Map<String, List> tries = <String, List>{}; 658 final Map<String, List> tries = <String, List>{};
658 final List<ProfileCode> codes = new List<ProfileCode>(); 659 final List<ProfileCode> codes = new List<ProfileCode>();
659 bool _builtCodeCalls = false; 660 bool _builtCodeCalls = false;
660 final List<ProfileFunction> functions = new List<ProfileFunction>(); 661 final List<ProfileFunction> functions = new List<ProfileFunction>();
661 bool _builtFunctionCalls = false; 662 bool _builtFunctionCalls = false;
662 663
663 CodeCallTree loadCodeTree(String name) { 664 CodeCallTree loadCodeTree(M.ProfileTreeDirection direction) {
664 if (name == 'inclusive') { 665 switch (direction) {
665 return _loadCodeTree(true, tries['inclusiveCodeTrie']); 666 case M.ProfileTreeDirection.inclusive:
666 } else { 667 return _loadCodeTree(true, tries['inclusiveCodeTrie']);
667 return _loadCodeTree(false, tries['exclusiveCodeTrie']); 668 case M.ProfileTreeDirection.exclusive:
669 return _loadCodeTree(false, tries['exclusiveCodeTrie']);
668 } 670 }
671 throw new Exception('Unknown ProfileTreeDirection');
669 } 672 }
670 673
671 FunctionCallTree loadFunctionTree(String name) { 674 FunctionCallTree loadFunctionTree(M.ProfileTreeDirection direction) {
672 if (name == 'inclusive') { 675 switch (direction) {
673 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']); 676 case M.ProfileTreeDirection.inclusive:
674 } else { 677 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']);
675 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']); 678 case M.ProfileTreeDirection.exclusive:
679 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']);
676 } 680 }
681 throw new Exception('Unknown ProfileTreeDirection');
677 } 682 }
678 683
679 buildCodeCallerAndCallees() { 684 buildCodeCallerAndCallees() {
680 if (_builtCodeCalls) { 685 if (_builtCodeCalls) {
681 return; 686 return;
682 } 687 }
683 _builtCodeCalls = true; 688 _builtCodeCalls = true;
684 var tree = loadCodeTree('inclusive'); 689 var tree = loadCodeTree(M.ProfileTreeDirection.inclusive);
685 tree._recordCallerAndCallees(); 690 tree._recordCallerAndCallees();
686 } 691 }
687 692
688 buildFunctionCallerAndCallees() { 693 buildFunctionCallerAndCallees() {
689 if (_builtFunctionCalls) { 694 if (_builtFunctionCalls) {
690 return; 695 return;
691 } 696 }
692 _builtFunctionCalls = true; 697 _builtFunctionCalls = true;
693 var tree = loadFunctionTree('inclusive'); 698 var tree = loadFunctionTree(M.ProfileTreeDirection.inclusive);
694 tree._markFunctionCalls(); 699 tree._markFunctionCalls();
695 } 700 }
696 701
697 clear() { 702 clear() {
698 sampleCount = 0; 703 sampleCount = 0;
699 samplePeriod = 0; 704 samplePeriod = 0;
700 sampleRate = 0.0; 705 sampleRate = 0.0;
701 stackDepth = 0; 706 stackDepth = 0;
702 timeSpan = 0.0; 707 timeSpan = 0.0;
703 codes.clear(); 708 codes.clear();
704 functions.clear(); 709 functions.clear();
705 tries.clear(); 710 tries.clear();
706 _builtCodeCalls = false; 711 _builtCodeCalls = false;
707 _builtFunctionCalls = false; 712 _builtFunctionCalls = false;
708 } 713 }
709 714
710 load(Isolate isolate, ServiceMap profile) { 715 Future load(Isolate isolate, ServiceMap profile) async {
711 clear(); 716 await loadProgress(isolate, profile).last;
712 if ((isolate == null) || (profile == null)) { 717 }
713 return;
714 }
715 718
716 this.isolate = isolate; 719 static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
717 isolate.resetCachedProfileData(); 720 final Completer completer = new Completer();
721 new Timer(duration, () => completer.complete() );
722 return completer.future;
723 }
718 724
719 sampleCount = profile['sampleCount']; 725 Stream<double> loadProgress(Isolate isolate, ServiceMap profile) {
720 samplePeriod = profile['samplePeriod']; 726 var progress = new StreamController<double>.broadcast();
721 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
722 stackDepth = profile['stackDepth'];
723 timeSpan = profile['timeSpan'];
724 727
725 // Process code table. 728 (() async {
726 for (var codeRegion in profile['codes']) { 729 final Stopwatch watch = new Stopwatch();
727 Code code = codeRegion['code']; 730 watch.start();
728 assert(code != null); 731 int count = 0;
729 codes.add(new ProfileCode.fromMap(this, code, codeRegion)); 732 var needToUpdate = () {
730 } 733 count++;
734 if (count % 256 == 0 && watch.elapsedMilliseconds > 16) {
Cutch 2016/08/09 20:21:52 our style is this: if (((count % 256) == 0) && (w
cbernaschina 2016/08/09 20:29:39 Done.
735 watch.reset();
736 return true;
737 }
738 return false;
739 };
740 var signal = (double p) {
741 progress.add(p);
742 return sleep();
743 };
744 try {
745 clear();
746 progress.add(0.0);
747 if ((isolate == null) || (profile == null)) {
748 return;
749 }
731 750
732 // Process function table. 751 this.isolate = isolate;
733 for (var profileFunction in profile['functions']) { 752 isolate.resetCachedProfileData();
734 ServiceFunction function = profileFunction['function'];
735 assert(function != null);
736 functions.add(
737 new ProfileFunction.fromMap(this, function, profileFunction));
738 }
739 753
740 tries['exclusiveCodeTrie'] = 754 sampleCount = profile['sampleCount'];
741 new Uint32List.fromList(profile['exclusiveCodeTrie']); 755 samplePeriod = profile['samplePeriod'];
742 tries['inclusiveCodeTrie'] = 756 sampleRate = (Duration.MICROSECONDS_PER_SECOND / samplePeriod);
743 new Uint32List.fromList(profile['inclusiveCodeTrie']); 757 stackDepth = profile['stackDepth'];
744 tries['exclusiveFunctionTrie'] = 758 timeSpan = profile['timeSpan'];
745 new Uint32List.fromList(profile['exclusiveFunctionTrie']); 759
746 tries['inclusiveFunctionTrie'] = 760 num length = profile['codes'].length +
747 new Uint32List.fromList(profile['inclusiveFunctionTrie']); 761 profile['functions'].length;
762
763 // Process code table.
764 for (var codeRegion in profile['codes']) {
765 if (needToUpdate()) { await signal(count * 100.0 / length); }
766 Code code = codeRegion['code'];
767 assert(code != null);
768 codes.add(new ProfileCode.fromMap(this, code, codeRegion));
769 }
770 // Process function table.
771 for (var profileFunction in profile['functions']) {
772 if (needToUpdate()) { await signal(count * 100 / length); }
Cutch 2016/08/09 20:21:52 new line and indent
cbernaschina 2016/08/09 20:29:39 Done.
773 ServiceFunction function = profileFunction['function'];
774 assert(function != null);
775 functions.add(
776 new ProfileFunction.fromMap(this, function, profileFunction));
777 }
778
779 tries['exclusiveCodeTrie'] =
780 new Uint32List.fromList(profile['exclusiveCodeTrie']);
781 tries['inclusiveCodeTrie'] =
782 new Uint32List.fromList(profile['inclusiveCodeTrie']);
783 tries['exclusiveFunctionTrie'] =
784 new Uint32List.fromList(profile['exclusiveFunctionTrie']);
785 tries['inclusiveFunctionTrie'] =
786 new Uint32List.fromList(profile['inclusiveFunctionTrie']);
787 } finally {
788 progress.close();
789 }
790 }());
791 return progress.stream;
748 } 792 }
749 793
750 // Data shared across calls to _read*TrieNode. 794 // Data shared across calls to _read*TrieNode.
751 int _dataCursor = 0; 795 int _dataCursor = 0;
752 796
753 // The code trie is serialized as a list of integers. Each node 797 // The code trie is serialized as a list of integers. Each node
754 // is recreated by consuming some portion of the list. The format is as 798 // is recreated by consuming some portion of the list. The format is as
755 // follows: 799 // follows:
756 // [0] index into codeTable of code object. 800 // [0] index into codeTable of code object.
757 // [1] tick count (number of times this stack frame occured). 801 // [1] tick count (number of times this stack frame occured).
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
911 if (node.children.length > 0) { 955 if (node.children.length > 0) {
912 nodeStack.add(node); 956 nodeStack.add(node);
913 childIndexStack.add(0); 957 childIndexStack.add(0);
914 } 958 }
915 } 959 }
916 960
917 return root; 961 return root;
918 } 962 }
919 963
920 int approximateMillisecondsForCount(count) { 964 int approximateMillisecondsForCount(count) {
921 var MICROSECONDS_PER_MILLISECOND = 1000.0; 965 return (count * samplePeriod) ~/ Duration.MICROSECONDS_PER_MILLISECOND;
922 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND;
923 } 966 }
924 967
925 double approximateSecondsForCount(count) { 968 double approximateSecondsForCount(count) {
926 var MICROSECONDS_PER_SECOND = 1000000.0; 969 return (count * samplePeriod) / Duration.MICROSECONDS_PER_SECOND;
927 return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
928 } 970 }
929 } 971 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698