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

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: Refactoring 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; 647 static const double MICROSECONDS_PER_SECOND = 1000000.0;
Cutch 2016/08/04 15:35:52 Please switch this to use the constants defined on
cbernaschina 2016/08/04 19:45:08 Done.
645 final double displayThreshold = 0.0002; // 0.02%. 648 static const double MICROSECONDS_PER_MILLISECOND = 1000.0;
649 static const double displayThreshold = 0.0002; // 0.02%.
Cutch 2016/08/04 15:35:52 please remove the displayThreshold (it's unnecessa
cbernaschina 2016/08/04 19:45:08 Done.
646 650
647 Isolate isolate; 651 Isolate isolate;
648 652
649 int sampleCount = 0; 653 int sampleCount = 0;
650 int samplePeriod = 0; 654 int samplePeriod = 0;
651 double sampleRate = 0.0; 655 double sampleRate = 0.0;
652 656
653 int stackDepth = 0; 657 int stackDepth = 0;
654 658
655 double timeSpan = 0.0; 659 double timeSpan = 0.0;
656 660
657 final Map<String, List> tries = <String, List>{}; 661 final Map<String, List> tries = <String, List>{};
658 final List<ProfileCode> codes = new List<ProfileCode>(); 662 final List<ProfileCode> codes = new List<ProfileCode>();
659 bool _builtCodeCalls = false; 663 bool _builtCodeCalls = false;
660 final List<ProfileFunction> functions = new List<ProfileFunction>(); 664 final List<ProfileFunction> functions = new List<ProfileFunction>();
661 bool _builtFunctionCalls = false; 665 bool _builtFunctionCalls = false;
662 666
663 CodeCallTree loadCodeTree(String name) { 667 CodeCallTree loadCodeTree(M.ProfileTreeDirection direction) {
664 if (name == 'inclusive') { 668 switch (direction) {
665 return _loadCodeTree(true, tries['inclusiveCodeTrie']); 669 case M.ProfileTreeDirection.inclusive:
666 } else { 670 return _loadCodeTree(true, tries['inclusiveCodeTrie']);
667 return _loadCodeTree(false, tries['exclusiveCodeTrie']); 671 case M.ProfileTreeDirection.exclusive:
672 return _loadCodeTree(false, tries['exclusiveCodeTrie']);
668 } 673 }
674 throw new Exception('Unknown ProfileTreeDirection');
669 } 675 }
670 676
671 FunctionCallTree loadFunctionTree(String name) { 677 FunctionCallTree loadFunctionTree(M.ProfileTreeDirection direction) {
672 if (name == 'inclusive') { 678 switch (direction) {
673 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']); 679 case M.ProfileTreeDirection.inclusive:
674 } else { 680 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']);
675 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']); 681 case M.ProfileTreeDirection.exclusive:
682 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']);
676 } 683 }
684 throw new Exception('Unknown ProfileTreeDirection');
677 } 685 }
678 686
679 buildCodeCallerAndCallees() { 687 buildCodeCallerAndCallees() {
680 if (_builtCodeCalls) { 688 if (_builtCodeCalls) {
681 return; 689 return;
682 } 690 }
683 _builtCodeCalls = true; 691 _builtCodeCalls = true;
684 var tree = loadCodeTree('inclusive'); 692 var tree = loadCodeTree(M.ProfileTreeDirection.inclusive);
685 tree._recordCallerAndCallees(); 693 tree._recordCallerAndCallees();
686 } 694 }
687 695
688 buildFunctionCallerAndCallees() { 696 buildFunctionCallerAndCallees() {
689 if (_builtFunctionCalls) { 697 if (_builtFunctionCalls) {
690 return; 698 return;
691 } 699 }
692 _builtFunctionCalls = true; 700 _builtFunctionCalls = true;
693 var tree = loadFunctionTree('inclusive'); 701 var tree = loadFunctionTree(M.ProfileTreeDirection.inclusive);
694 tree._markFunctionCalls(); 702 tree._markFunctionCalls();
695 } 703 }
696 704
697 clear() { 705 clear() {
698 sampleCount = 0; 706 sampleCount = 0;
699 samplePeriod = 0; 707 samplePeriod = 0;
700 sampleRate = 0.0; 708 sampleRate = 0.0;
701 stackDepth = 0; 709 stackDepth = 0;
702 timeSpan = 0.0; 710 timeSpan = 0.0;
703 codes.clear(); 711 codes.clear();
704 functions.clear(); 712 functions.clear();
705 tries.clear(); 713 tries.clear();
706 _builtCodeCalls = false; 714 _builtCodeCalls = false;
707 _builtFunctionCalls = false; 715 _builtFunctionCalls = false;
708 } 716 }
709 717
710 load(Isolate isolate, ServiceMap profile) { 718 Future load(Isolate isolate, ServiceMap profile) async {
711 clear(); 719 await loadProgress(isolate, profile).last;
712 if ((isolate == null) || (profile == null)) { 720 }
713 return;
714 }
715 721
716 this.isolate = isolate; 722 static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
717 isolate.resetCachedProfileData(); 723 final Completer completer = new Completer();
724 new Timer(duration, () => completer.complete() );
725 return completer.future;
726 }
718 727
719 sampleCount = profile['sampleCount']; 728 Stream<double> loadProgress(Isolate isolate, ServiceMap profile) {
720 samplePeriod = profile['samplePeriod']; 729 var progress = new StreamController<double>.broadcast();
721 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
722 stackDepth = profile['stackDepth'];
723 timeSpan = profile['timeSpan'];
724 730
725 // Process code table. 731 (() async {
726 for (var codeRegion in profile['codes']) { 732 final Stopwatch watch = new Stopwatch();
727 Code code = codeRegion['code']; 733 watch.start();
728 assert(code != null); 734 int count = 0;
729 codes.add(new ProfileCode.fromMap(this, code, codeRegion)); 735 var needToUpdate = () {
730 } 736 count++;
737 if (count % 256 == 0 && watch.elapsedMilliseconds > 16) {
738 watch.reset();
739 return true;
740 }
741 return false;
742 };
743 var signal = (double p) {
744 progress.add(p);
745 return sleep();
746 };
747 try {
748 clear();
749 progress.add(0.0);
750 if ((isolate == null) || (profile == null)) {
751 return;
752 }
731 753
732 // Process function table. 754 this.isolate = isolate;
733 for (var profileFunction in profile['functions']) { 755 isolate.resetCachedProfileData();
734 ServiceFunction function = profileFunction['function'];
735 assert(function != null);
736 functions.add(
737 new ProfileFunction.fromMap(this, function, profileFunction));
738 }
739 756
740 tries['exclusiveCodeTrie'] = 757 sampleCount = profile['sampleCount'];
741 new Uint32List.fromList(profile['exclusiveCodeTrie']); 758 samplePeriod = profile['samplePeriod'];
742 tries['inclusiveCodeTrie'] = 759 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
743 new Uint32List.fromList(profile['inclusiveCodeTrie']); 760 stackDepth = profile['stackDepth'];
744 tries['exclusiveFunctionTrie'] = 761 timeSpan = profile['timeSpan'];
745 new Uint32List.fromList(profile['exclusiveFunctionTrie']); 762
746 tries['inclusiveFunctionTrie'] = 763 num length = profile['codes'].length +
747 new Uint32List.fromList(profile['inclusiveFunctionTrie']); 764 profile['functions'].length;
765
766 // Process code table.
767 for (var codeRegion in profile['codes']) {
768 if (needToUpdate()) { await signal(count * 100.0 / length); }
769 Code code = codeRegion['code'];
770 assert(code != null);
771 codes.add(new ProfileCode.fromMap(this, code, codeRegion));
772 }
773 // Process function table.
774 for (var profileFunction in profile['functions']) {
775 if (needToUpdate()) { await signal(count * 100 / length); }
776 ServiceFunction function = profileFunction['function'];
777 assert(function != null);
778 functions.add(
779 new ProfileFunction.fromMap(this, function, profileFunction));
780 }
781
782 tries['exclusiveCodeTrie'] =
783 new Uint32List.fromList(profile['exclusiveCodeTrie']);
784 tries['inclusiveCodeTrie'] =
785 new Uint32List.fromList(profile['inclusiveCodeTrie']);
786 tries['exclusiveFunctionTrie'] =
787 new Uint32List.fromList(profile['exclusiveFunctionTrie']);
788 tries['inclusiveFunctionTrie'] =
789 new Uint32List.fromList(profile['inclusiveFunctionTrie']);
790 } finally {
791 progress.close();
792 }
793 }());
794 return progress.stream;
748 } 795 }
749 796
750 // Data shared across calls to _read*TrieNode. 797 // Data shared across calls to _read*TrieNode.
751 int _dataCursor = 0; 798 int _dataCursor = 0;
752 799
753 // The code trie is serialized as a list of integers. Each node 800 // 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 801 // is recreated by consuming some portion of the list. The format is as
755 // follows: 802 // follows:
756 // [0] index into codeTable of code object. 803 // [0] index into codeTable of code object.
757 // [1] tick count (number of times this stack frame occured). 804 // [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) { 958 if (node.children.length > 0) {
912 nodeStack.add(node); 959 nodeStack.add(node);
913 childIndexStack.add(0); 960 childIndexStack.add(0);
914 } 961 }
915 } 962 }
916 963
917 return root; 964 return root;
918 } 965 }
919 966
920 int approximateMillisecondsForCount(count) { 967 int approximateMillisecondsForCount(count) {
921 var MICROSECONDS_PER_MILLISECOND = 1000.0;
922 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND; 968 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND;
923 } 969 }
924 970
925 double approximateSecondsForCount(count) { 971 double approximateSecondsForCount(count) {
926 var MICROSECONDS_PER_SECOND = 1000000.0;
927 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; 972 return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
928 } 973 }
929 } 974 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698