| 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 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 } | 441 } |
| 442 | 442 |
| 443 Future<CpuProfile> reload(Isolate isolate) async { | 443 Future<CpuProfile> reload(Isolate isolate) async { |
| 444 profile.clear(); | 444 profile.clear(); |
| 445 if (isolate == null) { | 445 if (isolate == null) { |
| 446 _update(profile); | 446 _update(profile); |
| 447 // Notify listener. | 447 // Notify listener. |
| 448 onSampleBufferUpdate(profile); | 448 onSampleBufferUpdate(profile); |
| 449 return profile; | 449 return profile; |
| 450 } | 450 } |
| 451 profileVM = isolate.vm.profileVM; |
| 452 if (tagSelector == null) { |
| 453 // Set default value. |
| 454 tagSelector = profileVM ? 'UserVM' : 'None'; |
| 455 } |
| 451 await _changeState(kFetchingState); | 456 await _changeState(kFetchingState); |
| 452 try { | 457 try { |
| 453 var response; | 458 var response; |
| 454 if (allocationProfileClass != null) { | 459 if (allocationProfileClass != null) { |
| 455 response = | 460 response = |
| 456 await allocationProfileClass.getAllocationSamples(tagSelector); | 461 await allocationProfileClass.getAllocationSamples(tagSelector); |
| 457 } else { | 462 } else { |
| 458 var params = { 'tags': tagSelector }; | 463 var params = { 'tags': tagSelector }; |
| 459 response = await isolate.invokeRpc('_getCpuProfile', params); | 464 response = await isolate.invokeRpc('_getCpuProfile', params); |
| 460 } | 465 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 timeSpan = formatTime(profile.timeSpan); | 514 timeSpan = formatTime(profile.timeSpan); |
| 510 } | 515 } |
| 511 } | 516 } |
| 512 | 517 |
| 513 void tagSelectorChanged(oldValue) { | 518 void tagSelectorChanged(oldValue) { |
| 514 reload(profile.isolate); | 519 reload(profile.isolate); |
| 515 } | 520 } |
| 516 | 521 |
| 517 Function onSampleBufferUpdate; | 522 Function onSampleBufferUpdate; |
| 518 @observable bool showTagSelector = true; | 523 @observable bool showTagSelector = true; |
| 519 | 524 @observable bool profileVM = false; |
| 520 @observable String sampleCount = ''; | 525 @observable String sampleCount = ''; |
| 521 @observable String refreshTime = ''; | 526 @observable String refreshTime = ''; |
| 522 @observable String sampleRate = ''; | 527 @observable String sampleRate = ''; |
| 523 @observable String stackDepth = ''; | 528 @observable String stackDepth = ''; |
| 524 @observable String timeSpan = ''; | 529 @observable String timeSpan = ''; |
| 525 @observable String fetchTime = ''; | 530 @observable String fetchTime = ''; |
| 526 @observable String loadTime = ''; | 531 @observable String loadTime = ''; |
| 527 @observable String tagSelector = 'UserVM'; | 532 @observable String tagSelector; |
| 528 @observable String state = kFetchingState; | 533 @observable String state = kFetchingState; |
| 529 @observable var exception; | 534 @observable var exception; |
| 530 @observable var stackTrace; | 535 @observable var stackTrace; |
| 531 | 536 |
| 532 static const kDisabledState = 'kDisabled'; | 537 static const kDisabledState = 'kDisabled'; |
| 533 static const kExceptionState = 'Exception'; | 538 static const kExceptionState = 'Exception'; |
| 534 static const kFetchingState = 'kFetching'; | 539 static const kFetchingState = 'kFetching'; |
| 535 static const kLoadedState = 'kLoaded'; | 540 static const kLoadedState = 'kLoaded'; |
| 536 static const kLoadingState = 'kLoading'; | 541 static const kLoadingState = 'kLoading'; |
| 537 static const kNotLoadedState = 'kNotLoaded'; | 542 static const kNotLoadedState = 'kNotLoaded'; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 @observable bool showDirectionSelector = true; | 606 @observable bool showDirectionSelector = true; |
| 602 @observable bool showFilter = true; | 607 @observable bool showFilter = true; |
| 603 @observable String modeSelector = 'Function'; | 608 @observable String modeSelector = 'Function'; |
| 604 @observable String directionSelector = 'Up'; | 609 @observable String directionSelector = 'Up'; |
| 605 @observable String filterString; | 610 @observable String filterString; |
| 606 } | 611 } |
| 607 | 612 |
| 608 class FunctionCallTreeNodeRow extends VirtualTreeRow { | 613 class FunctionCallTreeNodeRow extends VirtualTreeRow { |
| 609 final CpuProfile profile; | 614 final CpuProfile profile; |
| 610 final FunctionCallTreeNode node; | 615 final FunctionCallTreeNode node; |
| 611 final String selfPercent; | 616 String selfPercent; |
| 612 final String totalPercent; | 617 String totalPercent; |
| 613 final String percent; | 618 String percent; |
| 619 |
| 620 static const kHotThreshold = 0.05; // 5%. |
| 621 static const kMediumThreshold = 0.02; // 2%. |
| 622 |
| 623 double _percent(bool self) { |
| 624 if (self) { |
| 625 return node.profileFunction.normalizedExclusiveTicks; |
| 626 } else { |
| 627 return node.profileFunction.normalizedInclusiveTicks; |
| 628 } |
| 629 } |
| 630 |
| 631 bool isHot(bool self) => _percent(self) > kHotThreshold; |
| 632 bool isMedium(bool self) => _percent(self) > kMediumThreshold; |
| 633 |
| 634 String rowClass(bool self) { |
| 635 if (isHot(self)) { |
| 636 return 'hotProfile'; |
| 637 } else if (isMedium(self)) { |
| 638 return 'mediumProfile'; |
| 639 } else { |
| 640 return 'coldProfile'; |
| 641 } |
| 642 } |
| 614 | 643 |
| 615 FunctionCallTreeNodeRow(VirtualTree tree, | 644 FunctionCallTreeNodeRow(VirtualTree tree, |
| 616 int depth, | 645 int depth, |
| 617 this.profile, | 646 this.profile, |
| 618 FunctionCallTreeNode node) | 647 FunctionCallTreeNode node) |
| 619 : node = node, | 648 : node = node, |
| 620 selfPercent = Utils.formatPercentNormalized(node.profileFunction.normali
zedExclusiveTicks), | |
| 621 totalPercent = Utils.formatPercentNormalized(node.profileFunction.normal
izedInclusiveTicks), | |
| 622 percent = Utils.formatPercentNormalized(node.percentage), | |
| 623 super(tree, depth) { | 649 super(tree, depth) { |
| 650 if ((node.profileFunction.function.kind == FunctionKind.kTag) && |
| 651 (node.profileFunction.normalizedExclusiveTicks == 0) && |
| 652 (node.profileFunction.normalizedInclusiveTicks == 0)) { |
| 653 selfPercent = ''; |
| 654 totalPercent = ''; |
| 655 } else { |
| 656 selfPercent = Utils.formatPercentNormalized( |
| 657 node.profileFunction.normalizedExclusiveTicks); |
| 658 totalPercent = Utils.formatPercentNormalized( |
| 659 node.profileFunction.normalizedInclusiveTicks); |
| 660 } |
| 661 percent = Utils.formatPercentNormalized(node.percentage); |
| 624 } | 662 } |
| 625 | 663 |
| 626 void onRender(DivElement rowDiv) { | 664 void onRender(DivElement rowDiv) { |
| 627 rowDiv.children.add(makeGap(ems:0.1)); | 665 rowDiv.children.add(makeGap(ems:0.1)); |
| 628 rowDiv.children.add( | 666 rowDiv.children.add( |
| 629 makeText(totalPercent, toolTip: 'global % on stack')); | 667 makeText(totalPercent, |
| 668 toolTip: 'global % on stack')); |
| 630 rowDiv.children.add(makeGap()); | 669 rowDiv.children.add(makeGap()); |
| 631 rowDiv.children.add( | 670 rowDiv.children.add( |
| 632 makeText(selfPercent, toolTip: 'global % executing')); | 671 makeText(selfPercent, |
| 672 toolTip: 'global % executing')); |
| 633 rowDiv.children.add(makeGap()); | 673 rowDiv.children.add(makeGap()); |
| 634 rowDiv.children.add(makeIndenter(colored: false)); | 674 rowDiv.children.add(makeIndenter(depth, colored: false)); |
| 635 rowDiv.children.add(makeColorBar()); | 675 rowDiv.children.add(makeColorBar(depth)); |
| 636 rowDiv.children.add(makeGap(ems: 1.0)); | 676 rowDiv.children.add(makeGap(ems: 1.0)); |
| 637 rowDiv.children.add(makeExpander()); | 677 rowDiv.children.add(makeExpander()); |
| 638 rowDiv.children.add( | 678 rowDiv.children.add( |
| 639 makeText(percent, toolTip: 'tree node %', flexBasis: null)); | 679 makeText(percent, toolTip: 'tree node %', flexBasis: null)); |
| 640 rowDiv.children.add(makeGap(ems: 0.5)); | 680 rowDiv.children.add(makeGap(ems: 0.5)); |
| 641 functionRef.ref = node.profileFunction.function; | 681 functionRef.ref = node.profileFunction.function; |
| 642 rowDiv.children.add(functionRef); | 682 rowDiv.children.add(functionRef); |
| 643 } | 683 } |
| 644 | 684 |
| 645 var functionRef = new Element.tag('function-ref'); | 685 var functionRef = new Element.tag('function-ref'); |
| 646 | 686 |
| 647 int get childCount => node.children.length; | 687 int get childCount => node.children.length; |
| 648 | 688 |
| 649 void onShow() { | 689 void onShow() { |
| 650 if (children.length > 0) { | 690 if (children.length > 0) { |
| 651 return; | 691 return; |
| 652 } | 692 } |
| 653 for (var childNode in node.children) { | 693 for (var childNode in node.children) { |
| 654 var row = new FunctionCallTreeNodeRow(tree, depth + 1, profile, childNode)
; | 694 var row = new FunctionCallTreeNodeRow(tree, depth + 1, profile, childNode)
; |
| 655 children.add(row); | 695 children.add(row); |
| 656 } | 696 } |
| 657 } | 697 } |
| 658 } | 698 } |
| 659 | 699 |
| 660 | 700 |
| 661 class CodeCallTreeNodeRow extends VirtualTreeRow { | 701 class CodeCallTreeNodeRow extends VirtualTreeRow { |
| 662 final CpuProfile profile; | 702 final CpuProfile profile; |
| 663 final CodeCallTreeNode node; | 703 final CodeCallTreeNode node; |
| 664 final String selfPercent; | 704 String selfPercent; |
| 665 final String totalPercent; | 705 String totalPercent; |
| 666 final String percent; | 706 String percent; |
| 707 |
| 708 static const kHotThreshold = 0.05; // 5%. |
| 709 static const kMediumThreshold = 0.02; // 2%. |
| 710 |
| 711 double _percent(bool self) { |
| 712 if (self) { |
| 713 return node.profileCode.normalizedExclusiveTicks; |
| 714 } else { |
| 715 return node.profileCode.normalizedInclusiveTicks; |
| 716 } |
| 717 } |
| 718 |
| 719 bool isHot(bool self) => _percent(self) > kHotThreshold; |
| 720 bool isMedium(bool self) => _percent(self) > kMediumThreshold; |
| 721 |
| 722 String rowClass(bool self) { |
| 723 if (isHot(self)) { |
| 724 return 'hotProfile'; |
| 725 } else if (isMedium(self)) { |
| 726 return 'mediumProfile'; |
| 727 } else { |
| 728 return 'coldProfile'; |
| 729 } |
| 730 } |
| 667 | 731 |
| 668 CodeCallTreeNodeRow(VirtualTree tree, | 732 CodeCallTreeNodeRow(VirtualTree tree, |
| 669 int depth, | 733 int depth, |
| 670 this.profile, | 734 this.profile, |
| 671 CodeCallTreeNode node) | 735 CodeCallTreeNode node) |
| 672 : node = node, | 736 : node = node, |
| 673 selfPercent = Utils.formatPercentNormalized(node.profileCode.normalizedE
xclusiveTicks), | |
| 674 totalPercent = Utils.formatPercentNormalized(node.profileCode.normalized
InclusiveTicks), | |
| 675 percent = Utils.formatPercentNormalized(node.percentage), | |
| 676 super(tree, depth) { | 737 super(tree, depth) { |
| 738 if ((node.profileCode.code.kind == CodeKind.Tag) && |
| 739 (node.profileCode.normalizedExclusiveTicks == 0) && |
| 740 (node.profileCode.normalizedInclusiveTicks == 0)) { |
| 741 selfPercent = ''; |
| 742 totalPercent = ''; |
| 743 } else { |
| 744 selfPercent = Utils.formatPercentNormalized( |
| 745 node.profileCode.normalizedExclusiveTicks); |
| 746 totalPercent = Utils.formatPercentNormalized( |
| 747 node.profileCode.normalizedInclusiveTicks); |
| 748 } |
| 749 percent = Utils.formatPercentNormalized(node.percentage); |
| 677 } | 750 } |
| 678 | 751 |
| 679 void onRender(DivElement rowDiv) { | 752 void onRender(DivElement rowDiv) { |
| 680 rowDiv.children.add(makeGap(ems:0.1)); | 753 rowDiv.children.add(makeGap(ems:0.1)); |
| 681 rowDiv.children.add( | 754 rowDiv.children.add( |
| 682 makeText(totalPercent, toolTip: 'global % on stack')); | 755 makeText(totalPercent, |
| 756 toolTip: 'global % on stack')); |
| 683 rowDiv.children.add(makeGap()); | 757 rowDiv.children.add(makeGap()); |
| 684 rowDiv.children.add( | 758 rowDiv.children.add( |
| 685 makeText(selfPercent, toolTip: 'global % executing')); | 759 makeText(selfPercent, |
| 760 toolTip: 'global % executing')); |
| 686 rowDiv.children.add(makeGap()); | 761 rowDiv.children.add(makeGap()); |
| 687 rowDiv.children.add(makeIndenter(colored: false)); | 762 rowDiv.children.add(makeIndenter(depth, colored: false)); |
| 688 rowDiv.children.add(makeColorBar()); | 763 rowDiv.children.add(makeColorBar(depth)); |
| 689 rowDiv.children.add(makeGap(ems: 1.0)); | 764 rowDiv.children.add(makeGap(ems: 1.0)); |
| 690 rowDiv.children.add(makeExpander()); | 765 rowDiv.children.add(makeExpander()); |
| 691 rowDiv.children.add( | 766 rowDiv.children.add( |
| 692 makeText(percent, toolTip: 'tree node %', flexBasis: null)); | 767 makeText(percent, toolTip: 'tree node %', flexBasis: null)); |
| 693 rowDiv.children.add(makeGap(ems: 0.5)); | 768 rowDiv.children.add(makeGap(ems: 0.5)); |
| 694 codeRef.ref = node.profileCode.code; | 769 codeRef.ref = node.profileCode.code; |
| 695 rowDiv.children.add(codeRef); | 770 rowDiv.children.add(codeRef); |
| 696 } | 771 } |
| 697 | 772 |
| 698 var codeRef = new Element.tag('code-ref'); | 773 var codeRef = new Element.tag('code-ref'); |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1276 _changeSort(target, profileCalleesTable); | 1351 _changeSort(target, profileCalleesTable); |
| 1277 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick); | 1352 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick); |
| 1278 } | 1353 } |
| 1279 | 1354 |
| 1280 ////// | 1355 ////// |
| 1281 /// | 1356 /// |
| 1282 /// Function tree. | 1357 /// Function tree. |
| 1283 /// | 1358 /// |
| 1284 TableTree functionTree; | 1359 TableTree functionTree; |
| 1285 _updateFunctionTreeView() { | 1360 _updateFunctionTreeView() { |
| 1286 cpuProfileTreeElement.functionFilter = (FunctionCallTreeNode node) { | 1361 cpuProfileTreeElement.filter = (FunctionCallTreeNode node) { |
| 1287 return node.profileFunction.function == focusedFunction; | 1362 return node.profileFunction.function == focusedFunction; |
| 1288 }; | 1363 }; |
| 1289 cpuProfileTreeElement.render(); | 1364 cpuProfileTreeElement.render(); |
| 1290 } | 1365 } |
| 1291 | 1366 |
| 1292 @published Isolate isolate; | 1367 @published Isolate isolate; |
| 1293 @observable NameSortedTable profileTable; | 1368 @observable NameSortedTable profileTable; |
| 1294 @observable NameSortedTable profileCallersTable; | 1369 @observable NameSortedTable profileCallersTable; |
| 1295 @observable NameSortedTable profileCalleesTable; | 1370 @observable NameSortedTable profileCalleesTable; |
| 1296 @observable ServiceFunction focusedFunction; | 1371 @observable ServiceFunction focusedFunction; |
| 1297 @observable int focusedRow; | 1372 @observable int focusedRow; |
| 1298 | 1373 |
| 1299 | 1374 |
| 1300 StreamSubscription _resizeSubscription; | 1375 StreamSubscription _resizeSubscription; |
| 1301 Task _updateTask; | 1376 Task _updateTask; |
| 1302 Task _renderTask; | 1377 Task _renderTask; |
| 1303 | 1378 |
| 1304 CpuProfile get profile => sampleBufferControlElement.profile; | 1379 CpuProfile get profile => sampleBufferControlElement.profile; |
| 1305 SampleBufferControlElement sampleBufferControlElement; | 1380 SampleBufferControlElement sampleBufferControlElement; |
| 1306 StackTraceTreeConfigElement stackTraceTreeConfigElement; | 1381 StackTraceTreeConfigElement stackTraceTreeConfigElement; |
| 1307 CpuProfileTreeElement cpuProfileTreeElement; | 1382 CpuProfileVirtualTreeElement cpuProfileTreeElement; |
| 1308 } | 1383 } |
| 1309 | 1384 |
| 1310 enum ProfileTreeDirection { | 1385 enum ProfileTreeDirection { |
| 1311 Exclusive, | 1386 Exclusive, |
| 1312 Inclusive | 1387 Inclusive |
| 1313 } | 1388 } |
| 1314 | 1389 |
| 1315 enum ProfileTreeMode { | 1390 enum ProfileTreeMode { |
| 1316 Code, | 1391 Code, |
| 1317 Function, | 1392 Function, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1337 detached() { | 1412 detached() { |
| 1338 super.detached(); | 1413 super.detached(); |
| 1339 _resizeSubscription?.cancel(); | 1414 _resizeSubscription?.cancel(); |
| 1340 } | 1415 } |
| 1341 | 1416 |
| 1342 void render() { | 1417 void render() { |
| 1343 _updateView(); | 1418 _updateView(); |
| 1344 } | 1419 } |
| 1345 | 1420 |
| 1346 showChanged(oldValue) { | 1421 showChanged(oldValue) { |
| 1347 var treeTable = shadowRoot.querySelector('#treeTable'); | 1422 if (show) { |
| 1348 assert(treeTable != null); | 1423 virtualTree?.root?.style?.display = 'block'; |
| 1349 treeTable.style.display = show ? 'table' : 'none'; | 1424 } else { |
| 1425 virtualTree?.root?.style?.display = 'none'; |
| 1426 } |
| 1350 } | 1427 } |
| 1351 | 1428 |
| 1352 void _updateView() { | 1429 void _updateView() { |
| 1353 _updateSize(); | 1430 _updateSize(); |
| 1354 virtualTree?.clear(); | 1431 virtualTree?.clear(); |
| 1355 virtualTree?.uninstall(); | 1432 virtualTree?.uninstall(); |
| 1356 virtualTree = null; | 1433 virtualTree = null; |
| 1357 bool exclusive = direction == ProfileTreeDirection.Exclusive; | 1434 bool exclusive = direction == ProfileTreeDirection.Exclusive; |
| 1358 if (mode == ProfileTreeMode.Code) { | 1435 if (mode == ProfileTreeMode.Code) { |
| 1359 _buildCodeTree(exclusive); | 1436 _buildCodeTree(exclusive); |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1489 return; | 1566 return; |
| 1490 } | 1567 } |
| 1491 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); | 1568 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); |
| 1492 if (tree == null) { | 1569 if (tree == null) { |
| 1493 return; | 1570 return; |
| 1494 } | 1571 } |
| 1495 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); | 1572 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); |
| 1496 codeTree.initialize(rootRow); | 1573 codeTree.initialize(rootRow); |
| 1497 } | 1574 } |
| 1498 } | 1575 } |
| OLD | NEW |