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

Side by Side Diff: runtime/observatory/lib/src/elements/cpu_profile_table.dart

Issue 2204563003: Converted Observatory cpu-profile element (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Removed tmp files 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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 library cpu_profile_element; 5 library cpu_profile_table_element;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:html'; 8 import 'dart:html';
9 import 'observatory_element.dart'; 9 import 'observatory_element.dart';
10 import 'package:observatory/models.dart' as M; 10 import 'sample_buffer_control.dart';
11 import 'stack_trace_tree_config.dart';
12 import 'cpu_profile/virtual_tree.dart';
11 import 'package:observatory/service.dart'; 13 import 'package:observatory/service.dart';
12 import 'package:observatory/app.dart'; 14 import 'package:observatory/app.dart';
13 import 'package:observatory/cpu_profile.dart'; 15 import 'package:observatory/cpu_profile.dart';
14 import 'package:observatory/elements.dart'; 16 import 'package:observatory/elements.dart';
17 import 'package:observatory/models.dart' as M;
18 import 'package:observatory/repositories.dart';
15 import 'package:polymer/polymer.dart'; 19 import 'package:polymer/polymer.dart';
16 20
17 List<String> sorted(Set<String> attributes) { 21 List<String> sorted(Set<String> attributes) {
18 var list = attributes.toList(); 22 var list = attributes.toList();
19 list.sort(); 23 list.sort();
20 return list; 24 return list;
21 } 25 }
22 26
23 abstract class ProfileTreeRow<T> extends TableTreeRow { 27 abstract class ProfileTreeRow<T> extends TableTreeRow {
24 final CpuProfile profile; 28 final CpuProfile profile;
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 methodColumn.children.add(infoButton); 432 methodColumn.children.add(infoButton);
429 433
430 // Fill in self column. 434 // Fill in self column.
431 var selfColumn = flexColumns[1]; 435 var selfColumn = flexColumns[1];
432 selfColumn.style.position = 'relative'; 436 selfColumn.style.position = 'relative';
433 selfColumn.style.alignItems = 'center'; 437 selfColumn.style.alignItems = 'center';
434 selfColumn.text = selfPercent; 438 selfColumn.text = selfPercent;
435 } 439 }
436 } 440 }
437 441
438 @CustomTag('sample-buffer-control')
439 class SampleBufferControlElement extends ObservatoryElement {
440 SampleBufferControlElement.created() : super.created() {
441 _stopWatch.start();
442 }
443
444 Future<CpuProfile> reload(Isolate isolate) async {
445 profile.clear();
446 if (isolate == null) {
447 _update(profile);
448 // Notify listener.
449 onSampleBufferUpdate(profile);
450 return profile;
451 }
452 profileVM = isolate.vm.profileVM;
453 if (tagSelector == null) {
454 // Set default value.
455 tagSelector = profileVM ? 'UserVM' : 'None';
456 }
457 await _changeState(kFetchingState);
458 try {
459 var response;
460 if (allocationProfileClass != null) {
461 response =
462 await allocationProfileClass.getAllocationSamples(tagSelector);
463 } else {
464 var params = { 'tags': tagSelector };
465 response = await isolate.invokeRpc('_getCpuProfile', params);
466 }
467 await _changeState(kLoadingState);
468 profile.load(isolate, response);
469 profile.buildFunctionCallerAndCallees();
470 _update(profile);
471 await _changeState(kLoadedState);
472 // Notify listener.
473 onSampleBufferUpdate(profile);
474 return profile;
475 } catch (e, st) {
476 if (e is ServerRpcException) {
477 ServerRpcException se = e;
478 if (se.code == ServerRpcException.kFeatureDisabled) {
479 await _changeState(kDisabledState);
480 return profile;
481 }
482 }
483 await _changeState(kExceptionState, e, st);
484 rethrow;
485 }
486 }
487
488 Future _changeState(String newState, [exception, stackTrace]) {
489 if ((newState == kDisabledState) ||
490 (newState == kFetchingState) ||
491 (newState == kExceptionState)) {
492 loadTime = '';
493 fetchTime = '';
494 } else if (newState == kLoadingState) {
495 fetchTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds);
496 loadTime = '';
497 } else if (newState == kLoadedState) {
498 loadTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds);
499 }
500 state = newState;
501 this.exception = exception;
502 this.stackTrace = stackTrace;
503 _stopWatch.reset();
504 return window.animationFrame;
505 }
506
507 _update(CpuProfile sampleBuffer) {
508 sampleCount = profile.sampleCount.toString();
509 refreshTime = new DateTime.now().toString();
510 stackDepth = profile.stackDepth.toString();
511 sampleRate = profile.sampleRate.toStringAsFixed(0);
512 if (profile.sampleCount == 0) {
513 timeSpan = '0s';
514 } else {
515 timeSpan = formatTime(profile.timeSpan);
516 }
517 }
518
519 void tagSelectorChanged(oldValue) {
520 reload(profile.isolate);
521 }
522
523 Function onSampleBufferUpdate;
524 @observable bool showTagSelector = true;
525 @observable bool profileVM = false;
526 @observable String sampleCount = '';
527 @observable String refreshTime = '';
528 @observable String sampleRate = '';
529 @observable String stackDepth = '';
530 @observable String timeSpan = '';
531 @observable String fetchTime = '';
532 @observable String loadTime = '';
533 @observable String tagSelector;
534 @observable String state = kFetchingState;
535 @observable var exception;
536 @observable var stackTrace;
537
538 static const kDisabledState = 'kDisabled';
539 static const kExceptionState = 'Exception';
540 static const kFetchingState = 'kFetching';
541 static const kLoadedState = 'kLoaded';
542 static const kLoadingState = 'kLoading';
543 static const kNotLoadedState = 'kNotLoaded';
544
545 Isolate isolate;
546 Class allocationProfileClass;
547
548 final CpuProfile profile = new CpuProfile();
549 final Stopwatch _stopWatch = new Stopwatch();
550 }
551
552 @CustomTag('stack-trace-tree-config')
553 class StackTraceTreeConfigElement extends ObservatoryElement {
554 StackTraceTreeConfigElement.created() : super.created();
555
556 attached() {
557 super.attached();
558 var filterElement = shadowRoot.querySelector('#filterInput');
559 keyDownSubscription = filterElement.onKeyDown.listen(_onKeyDown);
560 blurSubscription = filterElement.onBlur.listen(_onBlur);
561 }
562
563 detached() {
564 super.detached();
565 keyDownSubscription?.cancel();
566 blurSubscription?.cancel();
567 }
568
569 void _onKeyDown(KeyboardEvent keyEvent) {
570 if (keyEvent.keyCode == 13) {
571 // On enter, update the filter string.
572 filterString =
573 (shadowRoot.querySelector('#filterInput') as InputElement).value;
574 if (onTreeConfigChange == null) {
575 return;
576 }
577 onTreeConfigChange(modeSelector, directionSelector, filterString);
578 }
579 }
580
581 void _onBlur(Event event) {
582 // Input box has lost focus, update the display to match the active
583 // filter string.
584 (shadowRoot.querySelector('#filterInput') as InputElement).value =
585 filterString;
586 }
587
588 void modeSelectorChanged(oldValue) {
589 if (onTreeConfigChange == null) {
590 return;
591 }
592 onTreeConfigChange(modeSelector, directionSelector, filterString);
593 }
594
595 void directionSelectorChanged(oldValue) {
596 if (onTreeConfigChange == null) {
597 return;
598 }
599 onTreeConfigChange(modeSelector, directionSelector, filterString);
600 }
601
602 Function onTreeConfigChange;
603 StreamSubscription keyDownSubscription;
604 StreamSubscription blurSubscription;
605 @observable bool show = true;
606 @observable bool showModeSelector = true;
607 @observable bool showDirectionSelector = true;
608 @observable bool showFilter = true;
609 @observable String modeSelector = 'Function';
610 @observable String directionSelector = 'Up';
611 @observable String filterString;
612 }
613
614 class FunctionCallTreeNodeRow extends VirtualTreeRow {
615 final CpuProfile profile;
616 final FunctionCallTreeNode node;
617 String selfPercent;
618 String totalPercent;
619 String percent;
620
621 static const kHotThreshold = 0.05; // 5%.
622 static const kMediumThreshold = 0.02; // 2%.
623
624 double _percent(bool self) {
625 if (self) {
626 return node.profileFunction.normalizedExclusiveTicks;
627 } else {
628 return node.profileFunction.normalizedInclusiveTicks;
629 }
630 }
631
632 bool isHot(bool self) => _percent(self) > kHotThreshold;
633 bool isMedium(bool self) => _percent(self) > kMediumThreshold;
634
635 String rowClass(bool self) {
636 if (isHot(self)) {
637 return 'hotProfile';
638 } else if (isMedium(self)) {
639 return 'mediumProfile';
640 } else {
641 return 'coldProfile';
642 }
643 }
644
645 FunctionCallTreeNodeRow(VirtualTree tree,
646 int depth,
647 this.profile,
648 FunctionCallTreeNode node)
649 : node = node,
650 super(tree, depth) {
651 if ((node.profileFunction.function.kind == M.FunctionKind.tag) &&
652 (node.profileFunction.normalizedExclusiveTicks == 0) &&
653 (node.profileFunction.normalizedInclusiveTicks == 0)) {
654 selfPercent = '';
655 totalPercent = '';
656 } else {
657 selfPercent = Utils.formatPercentNormalized(
658 node.profileFunction.normalizedExclusiveTicks);
659 totalPercent = Utils.formatPercentNormalized(
660 node.profileFunction.normalizedInclusiveTicks);
661 }
662 percent = Utils.formatPercentNormalized(node.percentage);
663 }
664
665 void onRender(DivElement rowDiv) {
666 rowDiv.children.add(makeGap(ems:0.1));
667 rowDiv.children.add(
668 makeText(totalPercent,
669 toolTip: 'global % on stack'));
670 rowDiv.children.add(makeGap());
671 rowDiv.children.add(
672 makeText(selfPercent,
673 toolTip: 'global % executing'));
674 rowDiv.children.add(makeGap());
675 rowDiv.children.add(makeIndenter(depth, colored: false));
676 rowDiv.children.add(makeColorBar(depth));
677 rowDiv.children.add(makeGap(ems: 1.0));
678 rowDiv.children.add(makeExpander());
679 rowDiv.children.add(
680 makeText(percent, toolTip: 'tree node %', flexBasis: null));
681 rowDiv.children.add(makeGap(ems: 0.5));
682 functionRef.ref = node.profileFunction.function;
683 rowDiv.children.add(functionRef);
684 }
685
686 var functionRef = new Element.tag('function-ref');
687
688 int get childCount => node.children.length;
689
690 void onShow() {
691 if (children.length > 0) {
692 return;
693 }
694 for (var childNode in node.children) {
695 var row = new FunctionCallTreeNodeRow(tree, depth + 1, profile, childNode) ;
696 children.add(row);
697 }
698 }
699 }
700
701
702 class CodeCallTreeNodeRow extends VirtualTreeRow {
703 final CpuProfile profile;
704 final CodeCallTreeNode node;
705 String selfPercent;
706 String totalPercent;
707 String percent;
708
709 static const kHotThreshold = 0.05; // 5%.
710 static const kMediumThreshold = 0.02; // 2%.
711
712 double _percent(bool self) {
713 if (self) {
714 return node.profileCode.normalizedExclusiveTicks;
715 } else {
716 return node.profileCode.normalizedInclusiveTicks;
717 }
718 }
719
720 bool isHot(bool self) => _percent(self) > kHotThreshold;
721 bool isMedium(bool self) => _percent(self) > kMediumThreshold;
722
723 String rowClass(bool self) {
724 if (isHot(self)) {
725 return 'hotProfile';
726 } else if (isMedium(self)) {
727 return 'mediumProfile';
728 } else {
729 return 'coldProfile';
730 }
731 }
732
733 CodeCallTreeNodeRow(VirtualTree tree,
734 int depth,
735 this.profile,
736 CodeCallTreeNode node)
737 : node = node,
738 super(tree, depth) {
739 if ((node.profileCode.code.kind == M.CodeKind.tag) &&
740 (node.profileCode.normalizedExclusiveTicks == 0) &&
741 (node.profileCode.normalizedInclusiveTicks == 0)) {
742 selfPercent = '';
743 totalPercent = '';
744 } else {
745 selfPercent = Utils.formatPercentNormalized(
746 node.profileCode.normalizedExclusiveTicks);
747 totalPercent = Utils.formatPercentNormalized(
748 node.profileCode.normalizedInclusiveTicks);
749 }
750 percent = Utils.formatPercentNormalized(node.percentage);
751 }
752
753 void onRender(DivElement rowDiv) {
754 rowDiv.children.add(makeGap(ems:0.1));
755 rowDiv.children.add(
756 makeText(totalPercent,
757 toolTip: 'global % on stack'));
758 rowDiv.children.add(makeGap());
759 rowDiv.children.add(
760 makeText(selfPercent,
761 toolTip: 'global % executing'));
762 rowDiv.children.add(makeGap());
763 rowDiv.children.add(makeIndenter(depth, colored: false));
764 rowDiv.children.add(makeColorBar(depth));
765 rowDiv.children.add(makeGap(ems: 1.0));
766 rowDiv.children.add(makeExpander());
767 rowDiv.children.add(
768 makeText(percent, toolTip: 'tree node %', flexBasis: null));
769 rowDiv.children.add(makeGap(ems: 0.5));
770 codeRef.ref = node.profileCode.code;
771 rowDiv.children.add(codeRef);
772 }
773
774 var codeRef = new Element.tag('code-ref');
775
776 int get childCount => node.children.length;
777
778 void onShow() {
779 if (children.length > 0) {
780 return;
781 }
782 for (var childNode in node.children) {
783 var row = new CodeCallTreeNodeRow(tree, depth + 1, profile, childNode);
784 children.add(row);
785 }
786 }
787 }
788
789 /// Displays a CpuProfile
790 @CustomTag('cpu-profile')
791 class CpuProfileElement extends ObservatoryElement {
792 CpuProfileElement.created() : super.created() {
793 _updateTask = new Task(update);
794 _renderTask = new Task(render);
795 }
796
797 attached() {
798 super.attached();
799 sampleBufferControlElement =
800 shadowRoot.querySelector('#sampleBufferControl');
801 assert(sampleBufferControlElement != null);
802 sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange;
803 stackTraceTreeConfigElement =
804 shadowRoot.querySelector('#stackTraceTreeConfig');
805 assert(stackTraceTreeConfigElement != null);
806 stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
807 cpuProfileVirtualTreeElement = shadowRoot.querySelector('#cpuProfileVirtualT ree');
808 assert(cpuProfileVirtualTreeElement != null);
809 cpuProfileVirtualTreeElement.profile = sampleBufferControlElement.profile;
810 _resizeSubscription = window.onResize.listen((_) => _updateSize());
811 _updateTask.queue();
812 _updateSize();
813 }
814
815 detached() {
816 super.detached();
817 if (_resizeSubscription != null) {
818 _resizeSubscription.cancel();
819 }
820 }
821
822 _updateSize() {
823 var applySize = (e) {
824 Rectangle rect = e.getBoundingClientRect();
825 final totalHeight = window.innerHeight;
826 final bottomMargin = 200;
827 final mainHeight = totalHeight - bottomMargin;
828 e.style.setProperty('height', '${mainHeight}px');
829 };
830 HtmlElement e2 = $['cpuProfileVirtualTree'];
831 applySize(e2);
832 }
833
834 isolateChanged(oldValue) {
835 _updateTask.queue();
836 }
837
838 update() {
839 if (sampleBufferControlElement != null) {
840 sampleBufferControlElement.reload(isolate);
841 }
842 }
843
844 onSampleBufferChange(CpuProfile sampleBuffer) {
845 _renderTask.queue();
846 }
847
848 onTreeConfigChange(String modeSelector,
849 String directionSelector,
850 String filterString) {
851 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
852 if (directionSelector != 'Up') {
853 direction = ProfileTreeDirection.Inclusive;
854 }
855 ProfileTreeMode mode = ProfileTreeMode.Function;
856 if (modeSelector == 'Code') {
857 mode = ProfileTreeMode.Code;
858 }
859 // Clear the filter.
860 cpuProfileVirtualTreeElement.filter = null;
861 if (filterString != null) {
862 filterString = filterString.trim();
863 if (filterString.isNotEmpty) {
864 cpuProfileVirtualTreeElement.filter = (CallTreeNode node) {
865 return node.name.contains(filterString);
866 };
867 }
868 }
869 cpuProfileVirtualTreeElement.direction = direction;
870 cpuProfileVirtualTreeElement.mode = mode;
871 _renderTask.queue();
872 }
873
874 Future clearCpuProfile() async {
875 await isolate.invokeRpc('_clearCpuProfile', { });
876 _updateTask.queue();
877 return new Future.value(null);
878 }
879
880 Future refresh() {
881 _updateTask.queue();
882 return new Future.value(null);
883 }
884
885 render() {
886 cpuProfileVirtualTreeElement.render();
887 }
888
889 @published Isolate isolate;
890
891 StreamSubscription _resizeSubscription;
892 Task _updateTask;
893 Task _renderTask;
894 SampleBufferControlElement sampleBufferControlElement;
895 StackTraceTreeConfigElement stackTraceTreeConfigElement;
896 CpuProfileVirtualTreeElement cpuProfileVirtualTreeElement;
897 }
898
899 class NameSortedTable extends SortedTable { 442 class NameSortedTable extends SortedTable {
900 NameSortedTable(columns) : super(columns); 443 NameSortedTable(columns) : super(columns);
901 @override 444 @override
902 dynamic getSortKeyFor(int row, int col) { 445 dynamic getSortKeyFor(int row, int col) {
903 if (col == FUNCTION_COLUMN) { 446 if (col == FUNCTION_COLUMN) {
904 // Use name as sort key. 447 // Use name as sort key.
905 return rows[row].values[col].name; 448 return rows[row].values[col].name;
906 } 449 }
907 return super.getSortKeyFor(row, col); 450 return super.getSortKeyFor(row, col);
908 } 451 }
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
999 for (var i = 0; i < sortedRows.length; i++) { 542 for (var i = 0; i < sortedRows.length; i++) {
1000 var rowIndex = sortedRows[i]; 543 var rowIndex = sortedRows[i];
1001 var tr = table.children[i]; 544 var tr = table.children[i];
1002 _updateRow(tr, rowIndex, spacerColumns, refColumn); 545 _updateRow(tr, rowIndex, spacerColumns, refColumn);
1003 } 546 }
1004 } 547 }
1005 } 548 }
1006 549
1007 @CustomTag('cpu-profile-table') 550 @CustomTag('cpu-profile-table')
1008 class CpuProfileTableElement extends ObservatoryElement { 551 class CpuProfileTableElement extends ObservatoryElement {
552
553
1009 CpuProfileTableElement.created() : super.created() { 554 CpuProfileTableElement.created() : super.created() {
1010 _updateTask = new Task(update); 555 _updateTask = new Task(update);
1011 _renderTask = new Task(render); 556 _renderTask = new Task(render);
1012 var columns = [ 557 var columns = [
1013 new SortedTableColumn.withFormatter('Executing (%)', 558 new SortedTableColumn.withFormatter('Executing (%)',
1014 Utils.formatPercentNormalized), 559 Utils.formatPercentNormalized),
1015 new SortedTableColumn.withFormatter('In stack (%)', 560 new SortedTableColumn.withFormatter('In stack (%)',
1016 Utils.formatPercentNormalized), 561 Utils.formatPercentNormalized),
1017 new SortedTableColumn('Method'), 562 new SortedTableColumn('Method'),
1018 ]; 563 ];
(...skipping 12 matching lines...) Expand all
1031 new SortedTableColumn.withFormatter('Callers (%)', 576 new SortedTableColumn.withFormatter('Callers (%)',
1032 Utils.formatPercentNormalized), 577 Utils.formatPercentNormalized),
1033 new SortedTableColumn('Method') 578 new SortedTableColumn('Method')
1034 ]; 579 ];
1035 profileCallersTable = new NameSortedTable(columns); 580 profileCallersTable = new NameSortedTable(columns);
1036 profileCallersTable.sortColumnIndex = 0; 581 profileCallersTable.sortColumnIndex = 0;
1037 } 582 }
1038 583
1039 attached() { 584 attached() {
1040 super.attached(); 585 super.attached();
1041 sampleBufferControlElement =
1042 shadowRoot.querySelector('#sampleBufferControl');
1043 assert(sampleBufferControlElement != null);
1044 sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange;
1045 // Disable the tag selector- we always want no tags.
1046 sampleBufferControlElement.tagSelector = 'None';
1047 sampleBufferControlElement.showTagSelector = false;
1048 stackTraceTreeConfigElement =
1049 shadowRoot.querySelector('#stackTraceTreeConfig');
1050 assert(stackTraceTreeConfigElement != null);
1051 stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
1052 stackTraceTreeConfigElement.modeSelector = 'Function';
1053 stackTraceTreeConfigElement.showModeSelector = false;
1054 stackTraceTreeConfigElement.directionSelector = 'Down';
1055 stackTraceTreeConfigElement.showDirectionSelector = false;
1056 cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
1057 assert(cpuProfileTreeElement != null);
1058 cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
1059 _updateTask.queue(); 586 _updateTask.queue();
1060 _resizeSubscription = window.onResize.listen((_) => _updateSize()); 587 _resizeSubscription = window.onResize.listen((_) => _updateSize());
1061 _updateSize(); 588 _updateSize();
1062 } 589 }
1063 590
1064 detached() { 591 detached() {
1065 super.detached(); 592 super.detached();
1066 if (_resizeSubscription != null) { 593 if (_resizeSubscription != null) {
1067 _resizeSubscription.cancel(); 594 _resizeSubscription.cancel();
1068 } 595 }
1069 } 596 }
1070 597
1071 _updateSize() { 598 _updateSize() {
1072 HtmlElement e = $['main']; 599 HtmlElement e = $['main'];
1073 final totalHeight = window.innerHeight; 600 final totalHeight = window.innerHeight;
1074 final top = e.offset.top; 601 final top = e.offset.top;
1075 final bottomMargin = 32; 602 final bottomMargin = 32;
1076 final mainHeight = totalHeight - top - bottomMargin; 603 final mainHeight = totalHeight - top - bottomMargin;
1077 e.style.setProperty('height', '${mainHeight}px'); 604 e.style.setProperty('height', '${mainHeight}px');
1078 } 605 }
1079 606
1080 isolateChanged(oldValue) { 607 isolateChanged(oldValue) {
1081 _updateTask.queue(); 608 _updateTask.queue();
1082 } 609 }
1083 610
1084 update() { 611 update() async {
1085 _clearView(); 612 _clearView();
1086 if (sampleBufferControlElement != null) { 613 if (isolate == null) {
1087 sampleBufferControlElement.reload(isolate).whenComplete(checkParameters); 614 return;
1088 } 615 }
1089 } 616 final progress = _repository.get(isolate, M.SampleProfileTag.None);
1090 617 shadowRoot.querySelector('#sampleBufferControl').children = [
1091 onSampleBufferChange(CpuProfile sampleBuffer) { 618 sampleBufferControlElement =
619 new SampleBufferControlElement(progress, showTag: false,
620 selectedTag: M.SampleProfileTag.None, queue: app.queue)
621 ];
622 await progress.onProgress.last;
623 if (progress.status == M.SampleProfileLoadingStatus.Loaded) {
624 _profile = progress.profile;
625 shadowRoot.querySelector('#stackTraceTreeConfig').children = [
626 stackTraceTreeConfigElement =
627 new StackTraceTreeConfigElement(showMode: false, showDirection: fals e,
Cutch 2016/08/02 15:52:20 fix long lines
cbernaschina 2016/08/02 17:40:24 Done.
628 mode: ProfileTreeMode.Function,
629 direction: ProfileTreeDirection.Exclusive, queue: app.queue)
630 ..onModeChange.listen((e) {
631 cpuProfileTreeElement.mode = e.element.mode; _renderTask.queue() ;
632 })
633 ..onDirectionChange.listen((e) {
634 cpuProfileTreeElement.mode = e.element.mode; _renderTask.queue() ;
635 })
636 ..onFilterChange.listen((e) =>_renderTask.queue())
637 ];
638 shadowRoot.querySelector('#cpuProfileTree').children = [
639 cpuProfileTreeElement =
640 new CpuProfileVirtualTreeElement(isolate, _profile,
641 queue: app.queue)
642 ];
643 }
1092 _renderTask.queue(); 644 _renderTask.queue();
1093 } 645 }
1094 646
1095 onTreeConfigChange(String modeSelector,
1096 String directionSelector,
1097 String filterString) {
1098 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
1099 if (directionSelector != 'Up') {
1100 direction = ProfileTreeDirection.Inclusive;
1101 }
1102 ProfileTreeMode mode = ProfileTreeMode.Function;
1103 if (modeSelector == 'Code') {
1104 mode = ProfileTreeMode.Code;
1105 }
1106 cpuProfileTreeElement.direction = direction;
1107 cpuProfileTreeElement.mode = mode;
1108 _renderTask.queue();
1109 }
1110
1111 Future clearCpuProfile() async { 647 Future clearCpuProfile() async {
1112 await isolate.invokeRpc('_clearCpuProfile', { }); 648 await isolate.invokeRpc('_clearCpuProfile', { });
1113 _updateTask.queue(); 649 _updateTask.queue();
1114 return new Future.value(null); 650 return new Future.value(null);
1115 } 651 }
1116 652
1117 Future refresh() { 653 Future refresh() {
1118 _updateTask.queue(); 654 _updateTask.queue();
1119 return new Future.value(null); 655 return new Future.value(null);
1120 } 656 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1183 TableSectionElement tableBody = $['profile-table']; 719 TableSectionElement tableBody = $['profile-table'];
1184 // Clear current focus. 720 // Clear current focus.
1185 if (focusedRow != null) { 721 if (focusedRow != null) {
1186 tableBody.children[focusedRow].classes.remove('focused'); 722 tableBody.children[focusedRow].classes.remove('focused');
1187 } 723 }
1188 focusedRow = null; 724 focusedRow = null;
1189 focusedFunction = null; 725 focusedFunction = null;
1190 } 726 }
1191 727
1192 ServiceFunction _findFunction(String functionName) { 728 ServiceFunction _findFunction(String functionName) {
1193 for (var func in profile.functions) { 729 for (var func in _profile.functions) {
1194 if (func.function.name == functionName) { 730 if (func.function.name == functionName) {
1195 return func.function; 731 return func.function;
1196 } 732 }
1197 } 733 }
1198 return null; 734 return null;
1199 } 735 }
1200 736
1201 _focusOnFunction(ServiceFunction function) { 737 _focusOnFunction(ServiceFunction function) {
1202 if (focusedFunction == function) { 738 if (focusedFunction == function) {
1203 // Do nothing. 739 // Do nothing.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1243 779
1244 _renderTable() { 780 _renderTable() {
1245 profileTable._updateTableView($['profile-table'], 781 profileTable._updateTableView($['profile-table'],
1246 profileTable._makeFunctionRow, 782 profileTable._makeFunctionRow,
1247 _onRowClick, 783 _onRowClick,
1248 NameSortedTable.FUNCTION_SPACER_COLUMNS, 784 NameSortedTable.FUNCTION_SPACER_COLUMNS,
1249 NameSortedTable.FUNCTION_COLUMN); 785 NameSortedTable.FUNCTION_COLUMN);
1250 } 786 }
1251 787
1252 _buildFunctionTable() { 788 _buildFunctionTable() {
1253 for (var func in profile.functions) { 789 for (var func in _profile.functions) {
1254 if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) { 790 if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) {
1255 // Skip. 791 // Skip.
1256 continue; 792 continue;
1257 } 793 }
1258 var row = [ 794 var row = [
1259 func.normalizedExclusiveTicks, 795 func.normalizedExclusiveTicks,
1260 func.normalizedInclusiveTicks, 796 func.normalizedInclusiveTicks,
1261 func.function, 797 func.function,
1262 ]; 798 ];
1263 profileTable.addRow(new SortedTableRow(row)); 799 profileTable.addRow(new SortedTableRow(row));
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 _changeSort(target, profileCalleesTable); 888 _changeSort(target, profileCalleesTable);
1353 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick); 889 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick);
1354 } 890 }
1355 891
1356 ////// 892 //////
1357 /// 893 ///
1358 /// Function tree. 894 /// Function tree.
1359 /// 895 ///
1360 TableTree functionTree; 896 TableTree functionTree;
1361 _updateFunctionTreeView() { 897 _updateFunctionTreeView() {
898 if (cpuProfileTreeElement == null) { return; }
1362 cpuProfileTreeElement.filter = (FunctionCallTreeNode node) { 899 cpuProfileTreeElement.filter = (FunctionCallTreeNode node) {
1363 return node.profileFunction.function == focusedFunction; 900 return node.profileFunction.function == focusedFunction;
1364 }; 901 };
1365 cpuProfileTreeElement.render();
1366 } 902 }
1367 903
1368 @published Isolate isolate; 904 @published Isolate isolate;
1369 @observable NameSortedTable profileTable; 905 @observable NameSortedTable profileTable;
1370 @observable NameSortedTable profileCallersTable; 906 @observable NameSortedTable profileCallersTable;
1371 @observable NameSortedTable profileCalleesTable; 907 @observable NameSortedTable profileCalleesTable;
1372 @observable ServiceFunction focusedFunction; 908 @observable ServiceFunction focusedFunction;
1373 @observable int focusedRow; 909 @observable int focusedRow;
1374 910
1375 911
1376 StreamSubscription _resizeSubscription; 912 StreamSubscription _resizeSubscription;
1377 Task _updateTask; 913 Task _updateTask;
1378 Task _renderTask; 914 Task _renderTask;
1379 915
1380 CpuProfile get profile => sampleBufferControlElement.profile; 916 IsolateSampleProfileRepository _repository =
917 new IsolateSampleProfileRepository();
918 CpuProfile _profile;
1381 SampleBufferControlElement sampleBufferControlElement; 919 SampleBufferControlElement sampleBufferControlElement;
1382 StackTraceTreeConfigElement stackTraceTreeConfigElement; 920 StackTraceTreeConfigElement stackTraceTreeConfigElement;
1383 CpuProfileVirtualTreeElement cpuProfileTreeElement; 921 CpuProfileVirtualTreeElement cpuProfileTreeElement;
1384 } 922 }
1385
1386 enum ProfileTreeDirection {
1387 Exclusive,
1388 Inclusive
1389 }
1390
1391 enum ProfileTreeMode {
1392 Code,
1393 Function,
1394 }
1395
1396 @CustomTag('cpu-profile-virtual-tree')
1397 class CpuProfileVirtualTreeElement extends ObservatoryElement {
1398 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
1399 ProfileTreeMode mode = ProfileTreeMode.Function;
1400 CpuProfile profile;
1401 VirtualTree virtualTree;
1402 CallTreeNodeFilter filter;
1403 StreamSubscription _resizeSubscription;
1404 @observable bool show = true;
1405
1406 CpuProfileVirtualTreeElement.created() : super.created();
1407
1408 attached() {
1409 super.attached();
1410 _resizeSubscription = window.onResize.listen((_) => _updateSize());
1411 }
1412
1413 detached() {
1414 super.detached();
1415 _resizeSubscription?.cancel();
1416 }
1417
1418 void render() {
1419 _updateView();
1420 }
1421
1422 showChanged(oldValue) {
1423 if (show) {
1424 virtualTree?.root?.style?.display = 'block';
1425 } else {
1426 virtualTree?.root?.style?.display = 'none';
1427 }
1428 }
1429
1430 void _updateView() {
1431 _updateSize();
1432 virtualTree?.clear();
1433 virtualTree?.uninstall();
1434 virtualTree = null;
1435 bool exclusive = direction == ProfileTreeDirection.Exclusive;
1436 if (mode == ProfileTreeMode.Code) {
1437 _buildCodeTree(exclusive);
1438 } else {
1439 assert(mode == ProfileTreeMode.Function);
1440 _buildFunctionTree(exclusive);
1441 }
1442 virtualTree?.refresh();
1443 }
1444
1445 void _updateSize() {
1446 var treeBody = shadowRoot.querySelector('#tree');
1447 assert(treeBody != null);
1448 int windowHeight = window.innerHeight - 32;
1449 treeBody.style.height = '${windowHeight}px';
1450 }
1451
1452 void _buildFunctionTree(bool exclusive) {
1453 var treeBody = shadowRoot.querySelector('#tree');
1454 assert(treeBody != null);
1455 virtualTree = new VirtualTree(32, treeBody);
1456 if (profile == null) {
1457 return;
1458 }
1459 var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
1460 if (tree == null) {
1461 return;
1462 }
1463 if (filter != null) {
1464 tree = tree.filtered(filter);
1465 }
1466 for (var child in tree.root.children) {
1467 virtualTree.rows.add(
1468 new FunctionCallTreeNodeRow(virtualTree, 0, profile, child));
1469 }
1470 if (virtualTree.rows.length == 1) {
1471 virtualTree.rows[0].expanded = true;
1472 }
1473 }
1474
1475 void _buildCodeTree(bool exclusive) {
1476 var treeBody = shadowRoot.querySelector('#tree');
1477 assert(treeBody != null);
1478 virtualTree = new VirtualTree(32, treeBody);
1479 if (profile == null) {
1480 return;
1481 }
1482 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive');
1483 if (tree == null) {
1484 return;
1485 }
1486 if (filter != null) {
1487 tree = tree.filtered(filter);
1488 }
1489 for (var child in tree.root.children) {
1490 virtualTree.rows.add(
1491 new CodeCallTreeNodeRow(virtualTree, 0, profile, child));
1492 }
1493 if (virtualTree.rows.length == 1) {
1494 virtualTree.rows[0].expanded = true;
1495 }
1496 }
1497 }
1498
1499 @CustomTag('cpu-profile-tree')
1500 class CpuProfileTreeElement extends ObservatoryElement {
1501 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
1502 ProfileTreeMode mode = ProfileTreeMode.Function;
1503 CpuProfile profile;
1504 TableTree codeTree;
1505 TableTree functionTree;
1506 CallTreeNodeFilter functionFilter;
1507 @observable bool show = true;
1508
1509 CpuProfileTreeElement.created() : super.created();
1510
1511 void render() {
1512 _updateView();
1513 }
1514
1515 showChanged(oldValue) {
1516 var treeTable = shadowRoot.querySelector('#treeTable');
1517 assert(treeTable != null);
1518 treeTable.style.display = show ? 'table' : 'none';
1519 }
1520
1521 void _updateView() {
1522 if (functionTree != null) {
1523 functionTree.clear();
1524 functionTree = null;
1525 }
1526 if (codeTree != null) {
1527 codeTree.clear();
1528 codeTree = null;
1529 }
1530 bool exclusive = direction == ProfileTreeDirection.Exclusive;
1531 if (mode == ProfileTreeMode.Code) {
1532 _buildCodeTree(exclusive);
1533 } else {
1534 assert(mode == ProfileTreeMode.Function);
1535 _buildFunctionTree(exclusive);
1536 }
1537 }
1538
1539 void _buildFunctionTree(bool exclusive) {
1540 if (functionTree == null) {
1541 var tableBody = shadowRoot.querySelector('#treeBody');
1542 assert(tableBody != null);
1543 functionTree = new TableTree(tableBody, 2);
1544 }
1545 if (profile == null) {
1546 return;
1547 }
1548 var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
1549 if (tree == null) {
1550 return;
1551 }
1552 if (functionFilter != null) {
1553 tree = tree.filtered(functionFilter);
1554 }
1555 var rootRow =
1556 new FunctionProfileTreeRow(functionTree, null, profile, tree.root);
1557 functionTree.initialize(rootRow);
1558 }
1559
1560 void _buildCodeTree(bool exclusive) {
1561 if (codeTree == null) {
1562 var tableBody = shadowRoot.querySelector('#treeBody');
1563 assert(tableBody != null);
1564 codeTree = new TableTree(tableBody, 2);
1565 }
1566 if (profile == null) {
1567 return;
1568 }
1569 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive');
1570 if (tree == null) {
1571 return;
1572 }
1573 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root);
1574 codeTree.initialize(rootRow);
1575 }
1576 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698