| OLD | NEW |
| 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_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/service.dart'; | 10 import 'package:observatory/service.dart'; |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 } | 562 } |
| 563 | 563 |
| 564 Function onTreeConfigChange; | 564 Function onTreeConfigChange; |
| 565 @observable bool show = true; | 565 @observable bool show = true; |
| 566 @observable bool showModeSelector = true; | 566 @observable bool showModeSelector = true; |
| 567 @observable bool showDirectionSelector = true; | 567 @observable bool showDirectionSelector = true; |
| 568 @observable String modeSelector = 'Function'; | 568 @observable String modeSelector = 'Function'; |
| 569 @observable String directionSelector = 'Up'; | 569 @observable String directionSelector = 'Up'; |
| 570 } | 570 } |
| 571 | 571 |
| 572 class FunctionCallTreeNodeRow extends VirtualTreeRow { |
| 573 final CpuProfile profile; |
| 574 final FunctionCallTreeNode node; |
| 575 final String selfPercent; |
| 576 final String totalPercent; |
| 577 final String percent; |
| 578 |
| 579 FunctionCallTreeNodeRow(VirtualTree tree, |
| 580 int depth, |
| 581 this.profile, |
| 582 FunctionCallTreeNode node) |
| 583 : node = node, |
| 584 selfPercent = Utils.formatPercentNormalized(node.profileFunction.normali
zedExclusiveTicks), |
| 585 totalPercent = Utils.formatPercentNormalized(node.profileFunction.normal
izedInclusiveTicks), |
| 586 percent = Utils.formatPercentNormalized(node.percentage), |
| 587 super(tree, depth) { |
| 588 } |
| 589 |
| 590 void onRender(DivElement rowDiv) { |
| 591 rowDiv.children.add( |
| 592 makeText(totalPercent, toolTip: 'global % on stack')); |
| 593 rowDiv.children.add(makeGap()); |
| 594 rowDiv.children.add( |
| 595 makeText(selfPercent, toolTip: 'global % executing')); |
| 596 rowDiv.children.add(makeGap()); |
| 597 rowDiv.children.add(makeIndenter(colored: false)); |
| 598 rowDiv.children.add(makeColorBar()); |
| 599 rowDiv.children.add(makeGap(ems: 1.0)); |
| 600 rowDiv.children.add(makeExpander()); |
| 601 rowDiv.children.add( |
| 602 makeText(percent, toolTip: 'tree node %', flexBasis: null)); |
| 603 rowDiv.children.add(makeGap(ems: 0.5)); |
| 604 functionRef.ref = node.profileFunction.function; |
| 605 rowDiv.children.add(functionRef); |
| 606 } |
| 607 |
| 608 var functionRef = new Element.tag('function-ref'); |
| 609 |
| 610 int get childCount => node.children.length; |
| 611 |
| 612 void onShow() { |
| 613 if (children.length > 0) { |
| 614 return; |
| 615 } |
| 616 for (var childNode in node.children) { |
| 617 var row = new FunctionCallTreeNodeRow(tree, depth + 1, profile, childNode)
; |
| 618 children.add(row); |
| 619 } |
| 620 } |
| 621 } |
| 622 |
| 623 |
| 624 class CodeCallTreeNodeRow extends VirtualTreeRow { |
| 625 final CpuProfile profile; |
| 626 final CodeCallTreeNode node; |
| 627 final String selfPercent; |
| 628 final String totalPercent; |
| 629 final String percent; |
| 630 |
| 631 CodeCallTreeNodeRow(VirtualTree tree, |
| 632 int depth, |
| 633 this.profile, |
| 634 CodeCallTreeNode node) |
| 635 : node = node, |
| 636 selfPercent = Utils.formatPercentNormalized(node.profileCode.normalizedE
xclusiveTicks), |
| 637 totalPercent = Utils.formatPercentNormalized(node.profileCode.normalized
InclusiveTicks), |
| 638 percent = Utils.formatPercentNormalized(node.percentage), |
| 639 super(tree, depth) { |
| 640 } |
| 641 |
| 642 void onRender(DivElement rowDiv) { |
| 643 rowDiv.children.add( |
| 644 makeText(totalPercent, toolTip: 'global % on stack')); |
| 645 rowDiv.children.add(makeGap()); |
| 646 rowDiv.children.add( |
| 647 makeText(selfPercent, toolTip: 'global % executing')); |
| 648 rowDiv.children.add(makeGap()); |
| 649 rowDiv.children.add(makeIndenter(colored: false)); |
| 650 rowDiv.children.add(makeColorBar()); |
| 651 rowDiv.children.add(makeGap(ems: 1.0)); |
| 652 rowDiv.children.add(makeExpander()); |
| 653 rowDiv.children.add( |
| 654 makeText(percent, toolTip: 'tree node %', flexBasis: null)); |
| 655 rowDiv.children.add(makeGap(ems: 0.5)); |
| 656 codeRef.ref = node.profileCode.code; |
| 657 rowDiv.children.add(codeRef); |
| 658 } |
| 659 |
| 660 var codeRef = new Element.tag('code-ref'); |
| 661 |
| 662 int get childCount => node.children.length; |
| 663 |
| 664 void onShow() { |
| 665 if (children.length > 0) { |
| 666 return; |
| 667 } |
| 668 for (var childNode in node.children) { |
| 669 var row = new CodeCallTreeNodeRow(tree, depth + 1, profile, childNode); |
| 670 children.add(row); |
| 671 } |
| 672 } |
| 673 } |
| 674 |
| 572 /// Displays a CpuProfile | 675 /// Displays a CpuProfile |
| 573 @CustomTag('cpu-profile') | 676 @CustomTag('cpu-profile') |
| 574 class CpuProfileElement extends ObservatoryElement { | 677 class CpuProfileElement extends ObservatoryElement { |
| 575 CpuProfileElement.created() : super.created() { | 678 CpuProfileElement.created() : super.created() { |
| 576 _updateTask = new Task(update); | 679 _updateTask = new Task(update); |
| 577 _renderTask = new Task(render); | 680 _renderTask = new Task(render); |
| 578 } | 681 } |
| 579 | 682 |
| 580 attached() { | 683 attached() { |
| 581 super.attached(); | 684 super.attached(); |
| 582 sampleBufferControlElement = | 685 sampleBufferControlElement = |
| 583 shadowRoot.querySelector('#sampleBufferControl'); | 686 shadowRoot.querySelector('#sampleBufferControl'); |
| 584 assert(sampleBufferControlElement != null); | 687 assert(sampleBufferControlElement != null); |
| 585 sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange; | 688 sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange; |
| 586 stackTraceTreeConfigElement = | 689 stackTraceTreeConfigElement = |
| 587 shadowRoot.querySelector('#stackTraceTreeConfig'); | 690 shadowRoot.querySelector('#stackTraceTreeConfig'); |
| 588 assert(stackTraceTreeConfigElement != null); | 691 assert(stackTraceTreeConfigElement != null); |
| 589 stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange; | 692 stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange; |
| 590 cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree'); | 693 cpuProfileVirtualTreeElement = shadowRoot.querySelector('#cpuProfileVirtualT
ree'); |
| 591 assert(cpuProfileTreeElement != null); | 694 assert(cpuProfileVirtualTreeElement != null); |
| 592 cpuProfileTreeElement.profile = sampleBufferControlElement.profile; | 695 cpuProfileVirtualTreeElement.profile = sampleBufferControlElement.profile; |
| 696 _resizeSubscription = window.onResize.listen((_) => _updateSize()); |
| 593 _updateTask.queue(); | 697 _updateTask.queue(); |
| 698 _updateSize(); |
| 699 } |
| 700 |
| 701 detached() { |
| 702 super.detached(); |
| 703 if (_resizeSubscription != null) { |
| 704 _resizeSubscription.cancel(); |
| 705 } |
| 706 } |
| 707 |
| 708 _updateSize() { |
| 709 var applySize = (e) { |
| 710 Rectangle rect = e.getBoundingClientRect(); |
| 711 final totalHeight = window.innerHeight; |
| 712 final top = rect.top; |
| 713 final bottomMargin = 200; |
| 714 final mainHeight = totalHeight - top - bottomMargin; |
| 715 e.style.setProperty('height', '${mainHeight}px'); |
| 716 }; |
| 717 HtmlElement e2 = $['cpuProfileVirtualTree']; |
| 718 applySize(e2); |
| 594 } | 719 } |
| 595 | 720 |
| 596 isolateChanged(oldValue) { | 721 isolateChanged(oldValue) { |
| 597 _updateTask.queue(); | 722 _updateTask.queue(); |
| 598 } | 723 } |
| 599 | 724 |
| 600 update() { | 725 update() { |
| 601 if (sampleBufferControlElement != null) { | 726 if (sampleBufferControlElement != null) { |
| 602 sampleBufferControlElement.reload(isolate); | 727 sampleBufferControlElement.reload(isolate); |
| 603 } | 728 } |
| 604 } | 729 } |
| 605 | 730 |
| 606 onSampleBufferChange(CpuProfile sampleBuffer) { | 731 onSampleBufferChange(CpuProfile sampleBuffer) { |
| 607 _renderTask.queue(); | 732 _renderTask.queue(); |
| 608 } | 733 } |
| 609 | 734 |
| 610 onTreeConfigChange(String modeSelector, String directionSelector) { | 735 onTreeConfigChange(String modeSelector, String directionSelector) { |
| 611 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; | 736 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; |
| 612 if (directionSelector != 'Up') { | 737 if (directionSelector != 'Up') { |
| 613 direction = ProfileTreeDirection.Inclusive; | 738 direction = ProfileTreeDirection.Inclusive; |
| 614 } | 739 } |
| 615 ProfileTreeMode mode = ProfileTreeMode.Function; | 740 ProfileTreeMode mode = ProfileTreeMode.Function; |
| 616 if (modeSelector == 'Code') { | 741 if (modeSelector == 'Code') { |
| 617 mode = ProfileTreeMode.Code; | 742 mode = ProfileTreeMode.Code; |
| 618 } | 743 } |
| 619 cpuProfileTreeElement.direction = direction; | 744 cpuProfileVirtualTreeElement.direction = direction; |
| 620 cpuProfileTreeElement.mode = mode; | 745 cpuProfileVirtualTreeElement.mode = mode; |
| 621 _renderTask.queue(); | 746 _renderTask.queue(); |
| 622 } | 747 } |
| 623 | 748 |
| 624 Future clearCpuProfile() async { | 749 Future clearCpuProfile() async { |
| 625 await isolate.invokeRpc('_clearCpuProfile', { }); | 750 await isolate.invokeRpc('_clearCpuProfile', { }); |
| 626 _updateTask.queue(); | 751 _updateTask.queue(); |
| 627 return new Future.value(null); | 752 return new Future.value(null); |
| 628 } | 753 } |
| 629 | 754 |
| 630 Future refresh() { | 755 Future refresh() { |
| 631 _updateTask.queue(); | 756 _updateTask.queue(); |
| 632 return new Future.value(null); | 757 return new Future.value(null); |
| 633 } | 758 } |
| 634 | 759 |
| 635 render() { | 760 render() { |
| 636 cpuProfileTreeElement.render(); | 761 cpuProfileVirtualTreeElement.render(); |
| 637 } | 762 } |
| 638 | 763 |
| 639 @published Isolate isolate; | 764 @published Isolate isolate; |
| 640 | 765 |
| 766 StreamSubscription _resizeSubscription; |
| 641 Task _updateTask; | 767 Task _updateTask; |
| 642 Task _renderTask; | 768 Task _renderTask; |
| 643 SampleBufferControlElement sampleBufferControlElement; | 769 SampleBufferControlElement sampleBufferControlElement; |
| 644 StackTraceTreeConfigElement stackTraceTreeConfigElement; | 770 StackTraceTreeConfigElement stackTraceTreeConfigElement; |
| 645 CpuProfileTreeElement cpuProfileTreeElement; | 771 CpuProfileVirtualTreeElement cpuProfileVirtualTreeElement; |
| 646 } | 772 } |
| 647 | 773 |
| 648 class NameSortedTable extends SortedTable { | 774 class NameSortedTable extends SortedTable { |
| 649 NameSortedTable(columns) : super(columns); | 775 NameSortedTable(columns) : super(columns); |
| 650 @override | 776 @override |
| 651 dynamic getSortKeyFor(int row, int col) { | 777 dynamic getSortKeyFor(int row, int col) { |
| 652 if (col == FUNCTION_COLUMN) { | 778 if (col == FUNCTION_COLUMN) { |
| 653 // Use name as sort key. | 779 // Use name as sort key. |
| 654 return rows[row].values[col].name; | 780 return rows[row].values[col].name; |
| 655 } | 781 } |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1133 enum ProfileTreeDirection { | 1259 enum ProfileTreeDirection { |
| 1134 Exclusive, | 1260 Exclusive, |
| 1135 Inclusive | 1261 Inclusive |
| 1136 } | 1262 } |
| 1137 | 1263 |
| 1138 enum ProfileTreeMode { | 1264 enum ProfileTreeMode { |
| 1139 Code, | 1265 Code, |
| 1140 Function, | 1266 Function, |
| 1141 } | 1267 } |
| 1142 | 1268 |
| 1269 @CustomTag('cpu-profile-virtual-tree') |
| 1270 class CpuProfileVirtualTreeElement extends ObservatoryElement { |
| 1271 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; |
| 1272 ProfileTreeMode mode = ProfileTreeMode.Function; |
| 1273 CpuProfile profile; |
| 1274 VirtualTree virtualTree; |
| 1275 FunctionCallTreeNodeFilter functionFilter; |
| 1276 @observable bool show = true; |
| 1277 |
| 1278 CpuProfileVirtualTreeElement.created() : super.created(); |
| 1279 |
| 1280 void render() { |
| 1281 _updateView(); |
| 1282 } |
| 1283 |
| 1284 showChanged(oldValue) { |
| 1285 var treeTable = shadowRoot.querySelector('#treeTable'); |
| 1286 assert(treeTable != null); |
| 1287 treeTable.style.display = show ? 'table' : 'none'; |
| 1288 } |
| 1289 |
| 1290 void _updateView() { |
| 1291 virtualTree?.clear(); |
| 1292 virtualTree?.uninstall(); |
| 1293 virtualTree = null; |
| 1294 bool exclusive = direction == ProfileTreeDirection.Exclusive; |
| 1295 if (mode == ProfileTreeMode.Code) { |
| 1296 _buildCodeTree(exclusive); |
| 1297 } else { |
| 1298 assert(mode == ProfileTreeMode.Function); |
| 1299 _buildFunctionTree(exclusive); |
| 1300 } |
| 1301 virtualTree?.refresh(); |
| 1302 } |
| 1303 |
| 1304 void _buildFunctionTree(bool exclusive) { |
| 1305 var treeBody = shadowRoot.querySelector('#tree'); |
| 1306 assert(treeBody != null); |
| 1307 virtualTree = new VirtualTree(32, treeBody); |
| 1308 if (profile == null) { |
| 1309 return; |
| 1310 } |
| 1311 var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive'); |
| 1312 if (tree == null) { |
| 1313 return; |
| 1314 } |
| 1315 if (functionFilter != null) { |
| 1316 tree = tree.filtered(functionFilter); |
| 1317 } |
| 1318 for (var child in tree.root.children) { |
| 1319 virtualTree.rows.add( |
| 1320 new FunctionCallTreeNodeRow(virtualTree, 0, profile, child)); |
| 1321 } |
| 1322 if (virtualTree.rows.length == 1) { |
| 1323 virtualTree.rows[0].expanded = true; |
| 1324 } |
| 1325 } |
| 1326 |
| 1327 void _buildCodeTree(bool exclusive) { |
| 1328 var treeBody = shadowRoot.querySelector('#tree'); |
| 1329 assert(treeBody != null); |
| 1330 virtualTree = new VirtualTree(32, treeBody); |
| 1331 if (profile == null) { |
| 1332 return; |
| 1333 } |
| 1334 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); |
| 1335 if (tree == null) { |
| 1336 return; |
| 1337 } |
| 1338 for (var child in tree.root.children) { |
| 1339 virtualTree.rows.add( |
| 1340 new CodeCallTreeNodeRow(virtualTree, 0, profile, child)); |
| 1341 } |
| 1342 if (virtualTree.rows.length == 1) { |
| 1343 virtualTree.rows[0].expanded = true; |
| 1344 } |
| 1345 } |
| 1346 } |
| 1347 |
| 1143 @CustomTag('cpu-profile-tree') | 1348 @CustomTag('cpu-profile-tree') |
| 1144 class CpuProfileTreeElement extends ObservatoryElement { | 1349 class CpuProfileTreeElement extends ObservatoryElement { |
| 1145 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; | 1350 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; |
| 1146 ProfileTreeMode mode = ProfileTreeMode.Function; | 1351 ProfileTreeMode mode = ProfileTreeMode.Function; |
| 1147 CpuProfile profile; | 1352 CpuProfile profile; |
| 1148 TableTree codeTree; | 1353 TableTree codeTree; |
| 1149 TableTree functionTree; | 1354 TableTree functionTree; |
| 1150 FunctionCallTreeNodeFilter functionFilter; | 1355 FunctionCallTreeNodeFilter functionFilter; |
| 1151 @observable bool show = true; | 1356 @observable bool show = true; |
| 1152 | 1357 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 return; | 1416 return; |
| 1212 } | 1417 } |
| 1213 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); | 1418 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); |
| 1214 if (tree == null) { | 1419 if (tree == null) { |
| 1215 return; | 1420 return; |
| 1216 } | 1421 } |
| 1217 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); | 1422 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); |
| 1218 codeTree.initialize(rootRow); | 1423 codeTree.initialize(rootRow); |
| 1219 } | 1424 } |
| 1220 } | 1425 } |
| OLD | NEW |