| 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 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 methodColumn.children.add(infoButton); | 425 methodColumn.children.add(infoButton); |
| 426 | 426 |
| 427 // Fill in self column. | 427 // Fill in self column. |
| 428 var selfColumn = flexColumns[1]; | 428 var selfColumn = flexColumns[1]; |
| 429 selfColumn.style.position = 'relative'; | 429 selfColumn.style.position = 'relative'; |
| 430 selfColumn.style.alignItems = 'center'; | 430 selfColumn.style.alignItems = 'center'; |
| 431 selfColumn.text = selfPercent; | 431 selfColumn.text = selfPercent; |
| 432 } | 432 } |
| 433 } | 433 } |
| 434 | 434 |
| 435 /// Displays a CpuProfile | 435 @CustomTag('sample-buffer-control') |
| 436 @CustomTag('cpu-profile') | 436 class SampleBufferControlElement extends ObservatoryElement { |
| 437 class CpuProfileElement extends ObservatoryElement { | 437 SampleBufferControlElement.created() : super.created() { |
| 438 static const MICROSECONDS_PER_SECOND = 1000000.0; | 438 _stopWatch.start(); |
| 439 } |
| 439 | 440 |
| 440 @published Isolate isolate; | 441 Future<CpuProfile> reload(Isolate isolate) async { |
| 442 profile.clear(); |
| 443 if (isolate == null) { |
| 444 _update(profile); |
| 445 // Notify listener. |
| 446 onSampleBufferUpdate(profile); |
| 447 return profile; |
| 448 } |
| 449 await _changeState(kFetchingState); |
| 450 try { |
| 451 var params = { 'tags': tagSelector }; |
| 452 var response = await isolate.invokeRpc('_getCpuProfile', params); |
| 453 await _changeState(kLoadingState); |
| 454 profile.load(isolate, response); |
| 455 _update(profile); |
| 456 await _changeState(kLoadedState); |
| 457 // Notify listener. |
| 458 onSampleBufferUpdate(profile); |
| 459 return profile; |
| 460 } catch (e, st) { |
| 461 if (e is ServerRpcException) { |
| 462 ServerRpcException se = e; |
| 463 if (se.code == ServerRpcException.kFeatureDisabled) { |
| 464 await _changeState(kDisabledState); |
| 465 return profile; |
| 466 } |
| 467 } |
| 468 await _changeState(kExceptionState, e, st); |
| 469 rethrow; |
| 470 } |
| 471 } |
| 472 |
| 473 Future _changeState(String newState, [exception, stackTrace]) { |
| 474 if ((newState == kDisabledState) || |
| 475 (newState == kFetchingState) || |
| 476 (newState == kExceptionState)) { |
| 477 loadTime = ''; |
| 478 fetchTime = ''; |
| 479 } else if (newState == kLoadingState) { |
| 480 fetchTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds); |
| 481 loadTime = ''; |
| 482 } else if (newState == kLoadedState) { |
| 483 loadTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds); |
| 484 } |
| 485 state = newState; |
| 486 this.exception = exception; |
| 487 this.stackTrace = stackTrace; |
| 488 _stopWatch.reset(); |
| 489 return window.animationFrame; |
| 490 } |
| 491 |
| 492 _update(CpuProfile sampleBuffer) { |
| 493 sampleCount = profile.sampleCount.toString(); |
| 494 refreshTime = new DateTime.now().toString(); |
| 495 stackDepth = profile.stackDepth.toString(); |
| 496 sampleRate = profile.sampleRate.toStringAsFixed(0); |
| 497 timeSpan = formatTime(profile.timeSpan); |
| 498 } |
| 499 |
| 500 void tagSelectorChanged(oldValue) { |
| 501 reload(profile.isolate); |
| 502 } |
| 503 |
| 504 Function onSampleBufferUpdate; |
| 505 @observable bool showTagSelector = true; |
| 506 |
| 441 @observable String sampleCount = ''; | 507 @observable String sampleCount = ''; |
| 442 @observable String refreshTime = ''; | 508 @observable String refreshTime = ''; |
| 443 @observable String sampleRate = ''; | 509 @observable String sampleRate = ''; |
| 444 @observable String stackDepth = ''; | 510 @observable String stackDepth = ''; |
| 445 @observable String timeSpan = ''; | 511 @observable String timeSpan = ''; |
| 446 @observable String fetchTime = ''; | 512 @observable String fetchTime = ''; |
| 447 @observable String loadTime = ''; | 513 @observable String loadTime = ''; |
| 448 @observable String tagSelector = 'UserVM'; | 514 @observable String tagSelector = 'UserVM'; |
| 449 @observable String modeSelector = 'Function'; | 515 @observable String state = 'kFetching'; |
| 450 @observable String directionSelector = 'Up'; | |
| 451 | |
| 452 @observable String state = 'Requested'; | |
| 453 @observable var exception; | 516 @observable var exception; |
| 454 @observable var stackTrace; | 517 @observable var stackTrace; |
| 455 | 518 |
| 456 final Stopwatch _sw = new Stopwatch(); | 519 static const kDisabledState = 'kDisabled'; |
| 520 static const kExceptionState = 'Exception'; |
| 521 static const kFetchingState = 'kFetching'; |
| 522 static const kLoadedState = 'kLoaded'; |
| 523 static const kLoadingState = 'kLoading'; |
| 524 |
| 525 Isolate isolate; |
| 457 | 526 |
| 458 final CpuProfile profile = new CpuProfile(); | 527 final CpuProfile profile = new CpuProfile(); |
| 528 final Stopwatch _stopWatch = new Stopwatch(); |
| 529 } |
| 459 | 530 |
| 460 CpuProfileElement.created() : super.created(); | 531 @CustomTag('stack-trace-tree-config') |
| 461 | 532 class StackTraceTreeConfigElement extends ObservatoryElement { |
| 462 @override | 533 StackTraceTreeConfigElement.created() : super.created(); |
| 463 void attached() { | |
| 464 super.attached(); | |
| 465 } | |
| 466 | |
| 467 void isolateChanged(oldValue) { | |
| 468 _getCpuProfile().catchError(app.handleException); | |
| 469 } | |
| 470 | |
| 471 void tagSelectorChanged(oldValue) { | |
| 472 _getCpuProfile().catchError(app.handleException); | |
| 473 } | |
| 474 | 534 |
| 475 void modeSelectorChanged(oldValue) { | 535 void modeSelectorChanged(oldValue) { |
| 476 _updateView(); | 536 if (onTreeConfigChange == null) { |
| 537 return; |
| 538 } |
| 539 onTreeConfigChange(modeSelector, directionSelector); |
| 477 } | 540 } |
| 478 | 541 |
| 479 void directionSelectorChanged(oldValue) { | 542 void directionSelectorChanged(oldValue) { |
| 480 _updateView(); | 543 if (onTreeConfigChange == null) { |
| 544 return; |
| 545 } |
| 546 onTreeConfigChange(modeSelector, directionSelector); |
| 481 } | 547 } |
| 482 | 548 |
| 483 Future clearCpuProfile() { | 549 Function onTreeConfigChange; |
| 484 profile.clear(); | 550 @observable bool showModeSelector = true; |
| 485 if (isolate == null) { | 551 @observable bool showDirectionSelector = true; |
| 486 return new Future.value(null); | 552 @observable String modeSelector = 'Function'; |
| 487 } | 553 @observable String directionSelector = 'Up'; |
| 488 return isolate.invokeRpc('_clearCpuProfile', { }) | 554 } |
| 489 .then((ServiceMap response) { | 555 |
| 490 _updateView(); | 556 /// Displays a CpuProfile |
| 491 }); | 557 @CustomTag('cpu-profile') |
| 558 class CpuProfileElement extends ObservatoryElement { |
| 559 CpuProfileElement.created() : super.created() { |
| 560 _updateTask = new Task(update); |
| 561 _renderTask = new Task(render); |
| 492 } | 562 } |
| 493 | 563 |
| 494 Future refresh() { | 564 attached() { |
| 495 return _getCpuProfile(); | 565 super.attached(); |
| 566 sampleBufferControlElement = shadowRoot.query('#sampleBufferControl'); |
| 567 assert(sampleBufferControlElement != null); |
| 568 sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange; |
| 569 stackTraceTreeConfigElement = shadowRoot.query('#stackTraceTreeConfig'); |
| 570 assert(stackTraceTreeConfigElement != null); |
| 571 stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange; |
| 572 cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree'); |
| 573 assert(cpuProfileTreeElement != null); |
| 574 cpuProfileTreeElement.profile = sampleBufferControlElement.profile; |
| 575 _updateTask.queue(); |
| 496 } | 576 } |
| 497 | 577 |
| 498 _onFetchStarted() { | 578 isolateChanged(oldValue) { |
| 499 _sw.reset(); | 579 _updateTask.queue(); |
| 500 _sw.start(); | |
| 501 state = 'Requested'; | |
| 502 } | 580 } |
| 503 | 581 |
| 504 _onFetchFinished() { | 582 update() { |
| 505 _sw.stop(); | 583 if (sampleBufferControlElement != null) { |
| 506 fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds); | 584 sampleBufferControlElement.reload(isolate); |
| 507 } | |
| 508 | |
| 509 Future _onLoadStarted() { | |
| 510 _sw.reset(); | |
| 511 _sw.start(); | |
| 512 state = 'Loading'; | |
| 513 return window.animationFrame; | |
| 514 } | |
| 515 | |
| 516 _onLoadFinished() { | |
| 517 _sw.stop(); | |
| 518 loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds); | |
| 519 state = 'Loaded'; | |
| 520 } | |
| 521 | |
| 522 Future _getCpuProfile() async { | |
| 523 profile.clear(); | |
| 524 if (isolate == null) { | |
| 525 return new Future.value(null); | |
| 526 } | |
| 527 _onFetchStarted(); | |
| 528 try { | |
| 529 var params = { 'tags': tagSelector }; | |
| 530 var response = await isolate.invokeRpc('_getCpuProfile', params); | |
| 531 _onFetchFinished(); | |
| 532 await _onLoadStarted(); | |
| 533 profile.load(isolate, response); | |
| 534 _onLoadFinished(); | |
| 535 _updateView(); | |
| 536 } catch (e, st) { | |
| 537 bool handled = false; | |
| 538 if (e is ServerRpcException) { | |
| 539 ServerRpcException se = e; | |
| 540 if (se.code == ServerRpcException.kFeatureDisabled) { | |
| 541 state = 'Disabled'; | |
| 542 handled = true; | |
| 543 } | |
| 544 } | |
| 545 if (!handled) { | |
| 546 state = 'Exception'; | |
| 547 exception = e; | |
| 548 stackTrace = st; | |
| 549 rethrow; | |
| 550 } | |
| 551 } | 585 } |
| 552 } | 586 } |
| 553 | 587 |
| 554 void _updateView() { | 588 onSampleBufferChange(CpuProfile sampleBuffer) { |
| 555 sampleCount = profile.sampleCount.toString(); | 589 _renderTask.queue(); |
| 556 refreshTime = new DateTime.now().toString(); | 590 } |
| 557 stackDepth = profile.stackDepth.toString(); | 591 |
| 558 sampleRate = profile.sampleRate.toStringAsFixed(0); | 592 onTreeConfigChange(String modeSelector, String directionSelector) { |
| 559 timeSpan = formatTime(profile.timeSpan); | |
| 560 CpuProfileTreeElement cpuProfileTreeElement = | |
| 561 shadowRoot.querySelector('#cpuProfileTree'); | |
| 562 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; | 593 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; |
| 563 if (directionSelector != 'Up') { | 594 if (directionSelector != 'Up') { |
| 564 direction = ProfileTreeDirection.Inclusive; | 595 direction = ProfileTreeDirection.Inclusive; |
| 565 } | 596 } |
| 566 ProfileTreeMode mode = ProfileTreeMode.Function; | 597 ProfileTreeMode mode = ProfileTreeMode.Function; |
| 567 if (modeSelector == 'Code') { | 598 if (modeSelector == 'Code') { |
| 568 mode = ProfileTreeMode.Code; | 599 mode = ProfileTreeMode.Code; |
| 569 } | 600 } |
| 570 cpuProfileTreeElement.profile = profile; | |
| 571 cpuProfileTreeElement.direction = direction; | 601 cpuProfileTreeElement.direction = direction; |
| 572 cpuProfileTreeElement.mode = mode; | 602 cpuProfileTreeElement.mode = mode; |
| 603 _renderTask.queue(); |
| 604 } |
| 605 |
| 606 Future clearCpuProfile() async { |
| 607 await isolate.invokeRpc('_clearCpuProfile', { }); |
| 608 _updateTask.queue(); |
| 609 return new Future.value(null); |
| 610 } |
| 611 |
| 612 Future refresh() { |
| 613 _updateTask.queue(); |
| 614 return new Future.value(null); |
| 615 } |
| 616 |
| 617 render() { |
| 573 cpuProfileTreeElement.render(); | 618 cpuProfileTreeElement.render(); |
| 574 } | 619 } |
| 620 |
| 621 @published Isolate isolate; |
| 622 |
| 623 Task _updateTask; |
| 624 Task _renderTask; |
| 625 SampleBufferControlElement sampleBufferControlElement; |
| 626 StackTraceTreeConfigElement stackTraceTreeConfigElement; |
| 627 CpuProfileTreeElement cpuProfileTreeElement; |
| 575 } | 628 } |
| 576 | 629 |
| 577 class NameSortedTable extends SortedTable { | 630 class NameSortedTable extends SortedTable { |
| 578 NameSortedTable(columns) : super(columns); | 631 NameSortedTable(columns) : super(columns); |
| 579 @override | 632 @override |
| 580 dynamic getSortKeyFor(int row, int col) { | 633 dynamic getSortKeyFor(int row, int col) { |
| 581 if (col == FUNCTION_COLUMN) { | 634 if (col == FUNCTION_COLUMN) { |
| 582 // Use name as sort key. | 635 // Use name as sort key. |
| 583 return rows[row].values[col].name; | 636 return rows[row].values[col].name; |
| 584 } | 637 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 for (var i = 0; i < sortedRows.length; i++) { | 730 for (var i = 0; i < sortedRows.length; i++) { |
| 678 var rowIndex = sortedRows[i]; | 731 var rowIndex = sortedRows[i]; |
| 679 var tr = table.children[i]; | 732 var tr = table.children[i]; |
| 680 _updateRow(tr, rowIndex, spacerColumns, refColumn); | 733 _updateRow(tr, rowIndex, spacerColumns, refColumn); |
| 681 } | 734 } |
| 682 } | 735 } |
| 683 } | 736 } |
| 684 | 737 |
| 685 @CustomTag('cpu-profile-table') | 738 @CustomTag('cpu-profile-table') |
| 686 class CpuProfileTableElement extends ObservatoryElement { | 739 class CpuProfileTableElement extends ObservatoryElement { |
| 687 final Stopwatch _sw = new Stopwatch(); | |
| 688 final CpuProfile profile = new CpuProfile(); | |
| 689 StreamSubscription _resizeSubscription; | |
| 690 @observable NameSortedTable profileTable; | |
| 691 @observable NameSortedTable profileCallersTable; | |
| 692 @observable NameSortedTable profileCalleesTable; | |
| 693 @observable ServiceFunction focusedFunction; | |
| 694 @observable int focusedRow; | |
| 695 @observable String fetchTime = ''; | |
| 696 @observable String loadTime = ''; | |
| 697 @observable String state = 'Requested'; | |
| 698 @observable var exception; | |
| 699 @observable var stackTrace; | |
| 700 @observable Isolate isolate; | |
| 701 @observable String sampleCount = ''; | |
| 702 @observable String refreshTime = ''; | |
| 703 @observable String sampleRate = ''; | |
| 704 @observable String stackDepth = ''; | |
| 705 @observable String timeSpan = ''; | |
| 706 @observable String directionSelector = 'Up'; | |
| 707 | |
| 708 CpuProfileTableElement.created() : super.created() { | 740 CpuProfileTableElement.created() : super.created() { |
| 741 _updateTask = new Task(update); |
| 742 _renderTask = new Task(render); |
| 709 var columns = [ | 743 var columns = [ |
| 710 new SortedTableColumn.withFormatter('Executing (%)', | 744 new SortedTableColumn.withFormatter('Executing (%)', |
| 711 Utils.formatPercentNormalized), | 745 Utils.formatPercentNormalized), |
| 712 new SortedTableColumn.withFormatter('In stack (%)', | 746 new SortedTableColumn.withFormatter('In stack (%)', |
| 713 Utils.formatPercentNormalized), | 747 Utils.formatPercentNormalized), |
| 714 new SortedTableColumn('Method'), | 748 new SortedTableColumn('Method'), |
| 715 ]; | 749 ]; |
| 716 profileTable = new NameSortedTable(columns); | 750 profileTable = new NameSortedTable(columns); |
| 717 profileTable.sortColumnIndex = 0; | 751 profileTable.sortColumnIndex = 0; |
| 718 | 752 |
| 719 columns = [ | 753 columns = [ |
| 720 new SortedTableColumn.withFormatter('Callees (%)', | 754 new SortedTableColumn.withFormatter('Callees (%)', |
| 721 Utils.formatPercentNormalized), | 755 Utils.formatPercentNormalized), |
| 722 new SortedTableColumn('Method') | 756 new SortedTableColumn('Method') |
| 723 ]; | 757 ]; |
| 724 profileCalleesTable = new NameSortedTable(columns); | 758 profileCalleesTable = new NameSortedTable(columns); |
| 725 profileCalleesTable.sortColumnIndex = 0; | 759 profileCalleesTable.sortColumnIndex = 0; |
| 726 | 760 |
| 727 columns = [ | 761 columns = [ |
| 728 new SortedTableColumn.withFormatter('Callers (%)', | 762 new SortedTableColumn.withFormatter('Callers (%)', |
| 729 Utils.formatPercentNormalized), | 763 Utils.formatPercentNormalized), |
| 730 new SortedTableColumn('Method') | 764 new SortedTableColumn('Method') |
| 731 ]; | 765 ]; |
| 732 profileCallersTable = new NameSortedTable(columns); | 766 profileCallersTable = new NameSortedTable(columns); |
| 733 profileCallersTable.sortColumnIndex = 0; | 767 profileCallersTable.sortColumnIndex = 0; |
| 734 } | 768 } |
| 735 | 769 |
| 736 attached() { | 770 attached() { |
| 737 super.attached(); | 771 super.attached(); |
| 772 sampleBufferControlElement = shadowRoot.query('#sampleBufferControl'); |
| 773 assert(sampleBufferControlElement != null); |
| 774 sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange; |
| 775 // Disable the tag selector- we always want no tags. |
| 776 sampleBufferControlElement.tagSelector = 'None'; |
| 777 sampleBufferControlElement.showTagSelector = false; |
| 778 stackTraceTreeConfigElement = shadowRoot.query('#stackTraceTreeConfig'); |
| 779 assert(stackTraceTreeConfigElement != null); |
| 780 stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange; |
| 781 stackTraceTreeConfigElement.modeSelector = 'Function'; |
| 782 stackTraceTreeConfigElement.showModeSelector = false; |
| 783 stackTraceTreeConfigElement.directionSelector = 'Down'; |
| 784 stackTraceTreeConfigElement.showDirectionSelector = false; |
| 785 cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree'); |
| 786 assert(cpuProfileTreeElement != null); |
| 787 cpuProfileTreeElement.profile = sampleBufferControlElement.profile; |
| 788 _updateTask.queue(); |
| 738 _resizeSubscription = window.onResize.listen((_) => _updateSize()); | 789 _resizeSubscription = window.onResize.listen((_) => _updateSize()); |
| 739 _updateSize(); | 790 _updateSize(); |
| 740 } | 791 } |
| 741 | 792 |
| 742 detached() { | 793 detached() { |
| 743 super.detached(); | 794 super.detached(); |
| 744 if (_resizeSubscription != null) { | 795 if (_resizeSubscription != null) { |
| 745 _resizeSubscription.cancel(); | 796 _resizeSubscription.cancel(); |
| 746 } | 797 } |
| 747 } | 798 } |
| 748 | 799 |
| 749 _updateSize() { | 800 _updateSize() { |
| 750 HtmlElement e = $['main']; | 801 HtmlElement e = $['main']; |
| 751 final totalHeight = window.innerHeight; | 802 final totalHeight = window.innerHeight; |
| 752 final top = e.offset.top; | 803 final top = e.offset.top; |
| 753 final bottomMargin = 32; | 804 final bottomMargin = 32; |
| 754 final mainHeight = totalHeight - top - bottomMargin; | 805 final mainHeight = totalHeight - top - bottomMargin; |
| 755 e.style.setProperty('height', '${mainHeight}px'); | 806 e.style.setProperty('height', '${mainHeight}px'); |
| 756 } | 807 } |
| 757 | 808 |
| 758 isolateChanged() { | 809 isolateChanged(oldValue) { |
| 759 _getCpuProfile() | 810 _updateTask.queue(); |
| 760 .catchError(app.handleException) | 811 } |
| 761 .whenComplete(checkParameters); | 812 |
| 813 update() { |
| 814 _clearView(); |
| 815 if (sampleBufferControlElement != null) { |
| 816 sampleBufferControlElement.reload(isolate).whenComplete(checkParameters); |
| 817 } |
| 818 } |
| 819 |
| 820 onSampleBufferChange(CpuProfile sampleBuffer) { |
| 821 _renderTask.queue(); |
| 822 } |
| 823 |
| 824 onTreeConfigChange(String modeSelector, String directionSelector) { |
| 825 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; |
| 826 if (directionSelector != 'Up') { |
| 827 direction = ProfileTreeDirection.Inclusive; |
| 828 } |
| 829 ProfileTreeMode mode = ProfileTreeMode.Function; |
| 830 if (modeSelector == 'Code') { |
| 831 mode = ProfileTreeMode.Code; |
| 832 } |
| 833 cpuProfileTreeElement.direction = direction; |
| 834 cpuProfileTreeElement.mode = mode; |
| 835 _renderTask.queue(); |
| 836 } |
| 837 |
| 838 Future clearCpuProfile() async { |
| 839 await isolate.invokeRpc('_clearCpuProfile', { }); |
| 840 _updateTask.queue(); |
| 841 return new Future.value(null); |
| 842 } |
| 843 |
| 844 Future refresh() { |
| 845 _updateTask.queue(); |
| 846 return new Future.value(null); |
| 847 } |
| 848 |
| 849 render() { |
| 850 _updateView(); |
| 762 } | 851 } |
| 763 | 852 |
| 764 checkParameters() { | 853 checkParameters() { |
| 765 var functionId = app.locationManager.uri.queryParameters['functionId']; | 854 var functionId = app.locationManager.uri.queryParameters['functionId']; |
| 766 if (functionId == null) { | 855 if (functionId == null) { |
| 767 _focusOnFunction(null); | 856 _focusOnFunction(null); |
| 768 return; | 857 return; |
| 769 } | 858 } |
| 770 if (isolate == null) { | 859 if (isolate == null) { |
| 771 return; | 860 return; |
| 772 } | 861 } |
| 773 isolate.getObject(functionId).then((func) => _focusOnFunction(func)); | 862 isolate.getObject(functionId).then((func) => _focusOnFunction(func)); |
| 774 } | 863 } |
| 775 | 864 |
| 776 void directionSelectorChanged(oldValue) { | |
| 777 _updateFunctionTreeView(); | |
| 778 } | |
| 779 | |
| 780 Future refresh() { | |
| 781 return _getCpuProfile(); | |
| 782 } | |
| 783 | |
| 784 _onFetchStarted() { | |
| 785 _sw.reset(); | |
| 786 _sw.start(); | |
| 787 state = 'Requested'; | |
| 788 } | |
| 789 | |
| 790 _onFetchFinished() { | |
| 791 _sw.stop(); | |
| 792 fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds); | |
| 793 } | |
| 794 | |
| 795 _onLoadStarted() { | |
| 796 _sw.reset(); | |
| 797 _sw.start(); | |
| 798 state = 'Loading'; | |
| 799 } | |
| 800 | |
| 801 _onLoadFinished() { | |
| 802 _sw.stop(); | |
| 803 loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds); | |
| 804 state = 'Loaded'; | |
| 805 } | |
| 806 | |
| 807 Future clearCpuProfile() { | |
| 808 profile.clear(); | |
| 809 _clearView(); | |
| 810 if (isolate == null) { | |
| 811 return new Future.value(null); | |
| 812 } | |
| 813 return isolate.invokeRpc('_clearCpuProfile', { }) | |
| 814 .then((ServiceMap response) { | |
| 815 _updateView(); | |
| 816 }); | |
| 817 } | |
| 818 | |
| 819 Future _getCpuProfile() async { | |
| 820 profile.clear(); | |
| 821 _clearView(); | |
| 822 if (isolate == null) { | |
| 823 return new Future.value(null); | |
| 824 } | |
| 825 _onFetchStarted(); | |
| 826 try { | |
| 827 var params = { 'tags': 'None' }; | |
| 828 var response = await isolate.invokeRpc('_getCpuProfile', params); | |
| 829 _onFetchFinished(); | |
| 830 _onLoadStarted(); | |
| 831 profile.load(isolate, response); | |
| 832 profile.buildFunctionCallerAndCallees(); | |
| 833 _onLoadFinished(); | |
| 834 _updateView(); | |
| 835 } catch (e, st) { | |
| 836 bool handled = false; | |
| 837 if (e is ServerRpcException) { | |
| 838 ServerRpcException se = e; | |
| 839 if (se.code == ServerRpcException.kFeatureDisabled) { | |
| 840 state = 'Disabled'; | |
| 841 handled = true; | |
| 842 } | |
| 843 } | |
| 844 if (!handled) { | |
| 845 state = 'Exception'; | |
| 846 exception = e; | |
| 847 stackTrace = st; | |
| 848 rethrow; | |
| 849 } | |
| 850 } | |
| 851 } | |
| 852 | |
| 853 _clearView() { | 865 _clearView() { |
| 854 profileTable.clearRows(); | 866 profileTable.clearRows(); |
| 855 _renderTable(); | 867 _renderTable(); |
| 856 } | 868 } |
| 857 | 869 |
| 858 _updateView() { | 870 _updateView() { |
| 859 sampleCount = profile.sampleCount.toString(); | |
| 860 refreshTime = new DateTime.now().toString(); | |
| 861 stackDepth = profile.stackDepth.toString(); | |
| 862 sampleRate = profile.sampleRate.toStringAsFixed(0); | |
| 863 timeSpan = formatTime(profile.timeSpan); | |
| 864 _buildFunctionTable(); | 871 _buildFunctionTable(); |
| 865 _renderTable(); | 872 _renderTable(); |
| 866 _updateFunctionTreeView(); | 873 _updateFunctionTreeView(); |
| 867 } | 874 } |
| 868 | 875 |
| 869 int _findFunctionRow(ServiceFunction function) { | 876 int _findFunctionRow(ServiceFunction function) { |
| 870 for (var i = 0; i < profileTable.sortedRows.length; i++) { | 877 for (var i = 0; i < profileTable.sortedRows.length; i++) { |
| 871 var rowIndex = profileTable.sortedRows[i]; | 878 var rowIndex = profileTable.sortedRows[i]; |
| 872 var row = profileTable.rows[rowIndex]; | 879 var row = profileTable.rows[rowIndex]; |
| 873 if (row.values[NameSortedTable.FUNCTION_COLUMN] == function) { | 880 if (row.values[NameSortedTable.FUNCTION_COLUMN] == function) { |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 _changeSort(target, profileCalleesTable); | 1060 _changeSort(target, profileCalleesTable); |
| 1054 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick); | 1061 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick); |
| 1055 } | 1062 } |
| 1056 | 1063 |
| 1057 ////// | 1064 ////// |
| 1058 /// | 1065 /// |
| 1059 /// Function tree. | 1066 /// Function tree. |
| 1060 /// | 1067 /// |
| 1061 TableTree functionTree; | 1068 TableTree functionTree; |
| 1062 _updateFunctionTreeView() { | 1069 _updateFunctionTreeView() { |
| 1063 CpuProfileTreeElement cpuProfileTreeElement = | |
| 1064 shadowRoot.querySelector('#cpuProfileTree'); | |
| 1065 ProfileTreeDirection direction = ProfileTreeDirection.Exclusive; | |
| 1066 if (directionSelector != 'Up') { | |
| 1067 direction = ProfileTreeDirection.Inclusive; | |
| 1068 } | |
| 1069 ProfileTreeMode mode = ProfileTreeMode.Function; | |
| 1070 cpuProfileTreeElement.profile = profile; | |
| 1071 cpuProfileTreeElement.direction = direction; | |
| 1072 cpuProfileTreeElement.mode = mode; | |
| 1073 cpuProfileTreeElement.functionFilter = (FunctionCallTreeNode node) { | 1070 cpuProfileTreeElement.functionFilter = (FunctionCallTreeNode node) { |
| 1074 return node.profileFunction.function == focusedFunction; | 1071 return node.profileFunction.function == focusedFunction; |
| 1075 }; | 1072 }; |
| 1076 cpuProfileTreeElement.render(); | 1073 cpuProfileTreeElement.render(); |
| 1077 } | 1074 } |
| 1075 |
| 1076 @published Isolate isolate; |
| 1077 @observable NameSortedTable profileTable; |
| 1078 @observable NameSortedTable profileCallersTable; |
| 1079 @observable NameSortedTable profileCalleesTable; |
| 1080 @observable ServiceFunction focusedFunction; |
| 1081 @observable int focusedRow; |
| 1082 |
| 1083 |
| 1084 StreamSubscription _resizeSubscription; |
| 1085 Task _updateTask; |
| 1086 Task _renderTask; |
| 1087 |
| 1088 CpuProfile get profile => sampleBufferControlElement.profile; |
| 1089 SampleBufferControlElement sampleBufferControlElement; |
| 1090 StackTraceTreeConfigElement stackTraceTreeConfigElement; |
| 1091 CpuProfileTreeElement cpuProfileTreeElement; |
| 1078 } | 1092 } |
| 1079 | 1093 |
| 1080 enum ProfileTreeDirection { | 1094 enum ProfileTreeDirection { |
| 1081 Exclusive, | 1095 Exclusive, |
| 1082 Inclusive | 1096 Inclusive |
| 1083 } | 1097 } |
| 1084 | 1098 |
| 1085 enum ProfileTreeMode { | 1099 enum ProfileTreeMode { |
| 1086 Code, | 1100 Code, |
| 1087 Function, | 1101 Function, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 return; | 1165 return; |
| 1152 } | 1166 } |
| 1153 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); | 1167 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); |
| 1154 if (tree == null) { | 1168 if (tree == null) { |
| 1155 return; | 1169 return; |
| 1156 } | 1170 } |
| 1157 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); | 1171 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); |
| 1158 codeTree.initialize(rootRow); | 1172 codeTree.initialize(rootRow); |
| 1159 } | 1173 } |
| 1160 } | 1174 } |
| OLD | NEW |