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

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

Issue 1013563002: CPU profile displayed in three tables with a tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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 | Annotate | Revision Log
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_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 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 // Fill in method column. 217 // Fill in method column.
218 var methodColumn = flexColumns[0]; 218 var methodColumn = flexColumns[0];
219 methodColumn.style.justifyContent = 'flex-start'; 219 methodColumn.style.justifyContent = 'flex-start';
220 methodColumn.style.position = 'relative'; 220 methodColumn.style.position = 'relative';
221 221
222 // Percent. 222 // Percent.
223 var percentNode = new DivElement(); 223 var percentNode = new DivElement();
224 percentNode.text = percent; 224 percentNode.text = percent;
225 percentNode.style.minWidth = '5em'; 225 percentNode.style.minWidth = '5em';
226 percentNode.style.textAlign = 'right'; 226 percentNode.style.textAlign = 'right';
227 percentNode.title = 'Self: $selfPercent'; 227 percentNode.title = 'Executing: $selfPercent';
228 methodColumn.children.add(percentNode); 228 methodColumn.children.add(percentNode);
229 229
230 // Gap. 230 // Gap.
231 var gap = new SpanElement(); 231 var gap = new SpanElement();
232 gap.style.minWidth = '1em'; 232 gap.style.minWidth = '1em';
233 methodColumn.children.add(gap); 233 methodColumn.children.add(gap);
234 234
235 // Code link. 235 // Code link.
236 var codeRef = newCodeRef(node.profileCode); 236 var codeRef = newCodeRef(node.profileCode);
237 codeRef.style.alignSelf = 'center'; 237 codeRef.style.alignSelf = 'center';
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 functionRow.style.position = 'relative'; 312 functionRow.style.position = 'relative';
313 functionRow.style.justifyContent = 'flex-start'; 313 functionRow.style.justifyContent = 'flex-start';
314 codeAndFunctionColumn.children.add(functionRow); 314 codeAndFunctionColumn.children.add(functionRow);
315 315
316 // Insert the parent percentage 316 // Insert the parent percentage
317 var parentPercent = new SpanElement(); 317 var parentPercent = new SpanElement();
318 parentPercent.text = percent; 318 parentPercent.text = percent;
319 parentPercent.style.minWidth = '4em'; 319 parentPercent.style.minWidth = '4em';
320 parentPercent.style.alignSelf = 'center'; 320 parentPercent.style.alignSelf = 'center';
321 parentPercent.style.textAlign = 'right'; 321 parentPercent.style.textAlign = 'right';
322 parentPercent.title = 'Self: $selfPercent'; 322 parentPercent.title = 'Executing: $selfPercent';
323 functionRow.children.add(parentPercent); 323 functionRow.children.add(parentPercent);
324 324
325 // Gap. 325 // Gap.
326 var gap = new SpanElement(); 326 var gap = new SpanElement();
327 gap.style.minWidth = '1em'; 327 gap.style.minWidth = '1em';
328 gap.text = ' '; 328 gap.text = ' ';
329 functionRow.children.add(gap); 329 functionRow.children.add(gap);
330 330
331 var functionRef = new Element.tag('function-ref'); 331 var functionRef = new Element.tag('function-ref');
332 functionRef.ref = node.profileFunction.function; 332 functionRef.ref = node.profileFunction.function;
333 functionRef.style.alignSelf = 'center'; 333 functionRef.style.alignSelf = 'center';
334 functionRow.children.add(functionRef); 334 functionRow.children.add(functionRef);
335 335
336 gap = new SpanElement(); 336 gap = new SpanElement();
337 gap.style.minWidth = '1em'; 337 gap.style.minWidth = '1em';
338 gap.text = ' '; 338 gap.text = ' ';
339 functionRow.children.add(gap); 339 functionRow.children.add(gap);
340 340
341 for (var attribute in sorted(node.attributes)) { 341 for (var attribute in sorted(node.attributes)) {
342 functionRow.children.add(newAttributeBox(attribute)); 342 functionRow.children.add(newAttributeBox(attribute));
343 } 343 }
344 344
345 makeInfoBox(); 345 makeInfoBox();
346 functionRow.children.add(infoBox); 346 functionRow.children.add(infoBox);
347 347
348 if (node.profileFunction.function.kind.hasDartCode()) { 348 if (node.profileFunction.function.kind.hasDartCode()) {
349 infoBox.children.add(div('Hot code for current node')); 349 infoBox.children.add(div('Code for current node'));
350 infoBox.children.add(br()); 350 infoBox.children.add(br());
351 var totalTicks = node.totalCodesTicks; 351 var totalTicks = node.totalCodesTicks;
352 var numCodes = node.codes.length; 352 var numCodes = node.codes.length;
353 for (var i = 0; i < numCodes; i++) { 353 for (var i = 0; i < numCodes; i++) {
354 var codeRowSpan = new DivElement(); 354 var codeRowSpan = new DivElement();
355 codeRowSpan.style.paddingLeft = '1em'; 355 codeRowSpan.style.paddingLeft = '1em';
356 infoBox.children.add(codeRowSpan); 356 infoBox.children.add(codeRowSpan);
357 var nodeCode = node.codes[i]; 357 var nodeCode = node.codes[i];
358 var ticks = nodeCode.ticks; 358 var ticks = nodeCode.ticks;
359 var percentage = Utils.formatPercent(ticks, totalTicks); 359 var percentage = Utils.formatPercent(ticks, totalTicks);
(...skipping 25 matching lines...) Expand all
385 infoBox.children.add(memberList); 385 infoBox.children.add(memberList);
386 infoBox.children.add(br()); 386 infoBox.children.add(br());
387 ProfileTreeRow._addToMemberList(memberList, { 387 ProfileTreeRow._addToMemberList(memberList, {
388 'Exclusive ticks' : node.profileFunction.formattedExclusiveTicks, 388 'Exclusive ticks' : node.profileFunction.formattedExclusiveTicks,
389 'Cpu time' : node.profileFunction.formattedCpuTime, 389 'Cpu time' : node.profileFunction.formattedCpuTime,
390 'Inclusive ticks' : node.profileFunction.formattedInclusiveTicks, 390 'Inclusive ticks' : node.profileFunction.formattedInclusiveTicks,
391 'Call stack time' : node.profileFunction.formattedOnStackTime, 391 'Call stack time' : node.profileFunction.formattedOnStackTime,
392 }); 392 });
393 393
394 if (node.profileFunction.function.kind.hasDartCode()) { 394 if (node.profileFunction.function.kind.hasDartCode()) {
395 infoBox.children.add(div('Hot code containing function')); 395 infoBox.children.add(div('Code containing function'));
396 infoBox.children.add(br()); 396 infoBox.children.add(br());
397 var totalTicks = profile.sampleCount; 397 var totalTicks = profile.sampleCount;
398 var codes = node.profileFunction.profileCodes; 398 var codes = node.profileFunction.profileCodes;
399 var numCodes = codes.length; 399 var numCodes = codes.length;
400 for (var i = 0; i < numCodes; i++) { 400 for (var i = 0; i < numCodes; i++) {
401 var codeRowSpan = new DivElement(); 401 var codeRowSpan = new DivElement();
402 codeRowSpan.style.paddingLeft = '1em'; 402 codeRowSpan.style.paddingLeft = '1em';
403 infoBox.children.add(codeRowSpan); 403 infoBox.children.add(codeRowSpan);
404 var profileCode = codes[i]; 404 var profileCode = codes[i];
405 var code = profileCode.code; 405 var code = profileCode.code;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 _sw.reset(); 503 _sw.reset();
504 _sw.start(); 504 _sw.start();
505 state = 'Requested'; 505 state = 'Requested';
506 } 506 }
507 507
508 _onFetchFinished() { 508 _onFetchFinished() {
509 _sw.stop(); 509 _sw.stop();
510 fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds); 510 fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
511 } 511 }
512 512
513 _onLoadStarted() { 513 Future _onLoadStarted() {
514 _sw.reset(); 514 _sw.reset();
515 _sw.start(); 515 _sw.start();
516 state = 'Loading'; 516 state = 'Loading';
517 return window.animationFrame;
517 } 518 }
518 519
519 _onLoadFinished() { 520 _onLoadFinished() {
520 _sw.stop(); 521 _sw.stop();
521 loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds); 522 loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
522 state = 'Loaded'; 523 state = 'Loaded';
523 } 524 }
524 525
525 Future _getCpuProfile() { 526 Future _getCpuProfile() {
526 profile.clear(); 527 profile.clear();
527 if (functionTree != null) { 528 if (functionTree != null) {
528 functionTree.clear(); 529 functionTree.clear();
529 functionTree = null; 530 functionTree = null;
530 } 531 }
531 if (codeTree != null) { 532 if (codeTree != null) {
532 codeTree.clear(); 533 codeTree.clear();
533 codeTree = null; 534 codeTree = null;
534 } 535 }
535 if (isolate == null) { 536 if (isolate == null) {
536 return new Future.value(null); 537 return new Future.value(null);
537 } 538 }
538 _onFetchStarted(); 539 _onFetchStarted();
539 return isolate.invokeRpc('getCpuProfile', { 'tags': tagSelector }) 540 return isolate.invokeRpc('getCpuProfile', { 'tags': tagSelector })
540 .then((response) { 541 .then((response) async {
541 _onFetchFinished(); 542 _onFetchFinished();
542 _onLoadStarted(); 543 await _onLoadStarted();
543 try { 544 try {
544 profile.load(isolate, response); 545 profile.load(isolate, response);
545 _onLoadFinished(); 546 _onLoadFinished();
546 _updateView(); 547 _updateView();
547 } catch (e, st) { 548 } catch (e, st) {
548 state = 'Exception'; 549 state = 'Exception';
549 exception = e; 550 exception = e;
550 stackTrace = st; 551 stackTrace = st;
551 } 552 }
552 }).catchError((e, st) { 553 }).catchError((e, st) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 codeTree = new TableTree(tableBody, 2); 604 codeTree = new TableTree(tableBody, 2);
604 } 605 }
605 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); 606 var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive');
606 if (tree == null) { 607 if (tree == null) {
607 return; 608 return;
608 } 609 }
609 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root); 610 var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root);
610 codeTree.initialize(rootRow); 611 codeTree.initialize(rootRow);
611 } 612 }
612 } 613 }
614
615 class NameSortedTable extends SortedTable {
616 NameSortedTable(columns) : super(columns);
617 @override
618 dynamic getSortKeyFor(int row, int col) {
619 if (col == FUNCTION_COLUMN) {
620 // Use name as sort key.
621 return rows[row].values[col].name;
622 }
623 return super.getSortKeyFor(row, col);
624 }
625
626 SortedTableRow rowFromIndex(int tableIndex) {
627 final modelIndex = sortedRows[tableIndex];
628 return rows[modelIndex];
629 }
630
631 static const FUNCTION_SPACER_COLUMNS = const [];
632 static const FUNCTION_COLUMN = 2;
633 TableRowElement _makeFunctionRow() {
634 var tr = new TableRowElement();
635 var cell;
636
637 // Add percentage.
638 cell = tr.insertCell(-1);
639 cell = tr.insertCell(-1);
640
641 // Add function ref.
642 cell = tr.insertCell(-1);
643 var functionRef = new Element.tag('function-ref');
644 cell.children.add(functionRef);
645
646 return tr;
647 }
648
649 static const CALL_SPACER_COLUMNS = const [];
650 static const CALL_FUNCTION_COLUMN = 1;
651 TableRowElement _makeCallRow() {
652 var tr = new TableRowElement();
653 var cell;
654
655 // Add percentage.
656 cell = tr.insertCell(-1);
657 // Add function ref.
658 cell = tr.insertCell(-1);
659 var functionRef = new Element.tag('function-ref');
660 cell.children.add(functionRef);
661 return tr;
662 }
663
664 _updateRow(TableRowElement tr,
665 int rowIndex,
666 List spacerColumns,
667 int refColumn) {
668 var row = rows[rowIndex];
669 // Set reference
670 var ref = tr.children[refColumn].children[0];
671 ref.ref = row.values[refColumn];
672
673 for (var i = 0; i < row.values.length; i++) {
674 if (spacerColumns.contains(i) || (i == refColumn)) {
675 // Skip spacer columns.
676 continue;
677 }
678 var cell = tr.children[i];
679 cell.title = row.values[i].toString();
680 cell.text = getFormattedValue(rowIndex, i);
681 }
682 }
683
684 _updateTableView(HtmlElement table,
685 HtmlElement makeEmptyRow(),
686 void onRowClick(TableRowElement tr),
687 List spacerColumns,
688 int refColumn) {
689 assert(table != null);
690
691 // Resize DOM table.
692 if (table.children.length > sortedRows.length) {
693 // Shrink the table.
694 var deadRows = table.children.length - sortedRows.length;
695 for (var i = 0; i < deadRows; i++) {
696 table.children.removeLast();
697 }
698 } else if (table.children.length < sortedRows.length) {
699 // Grow table.
700 var newRows = sortedRows.length - table.children.length;
701 for (var i = 0; i < newRows; i++) {
702 var row = makeEmptyRow();
703 row.onClick.listen((e) {
704 e.stopPropagation();
705 e.preventDefault();
706 onRowClick(row);
707 });
708 table.children.add(row);
709 }
710 }
711
712 assert(table.children.length == sortedRows.length);
713
714 // Fill table.
715 for (var i = 0; i < sortedRows.length; i++) {
716 var rowIndex = sortedRows[i];
717 var tr = table.children[i];
718 _updateRow(tr, rowIndex, spacerColumns, refColumn);
719 }
720 }
721 }
722
723 @CustomTag('cpu-profile-table')
724 class CpuProfileTableElement extends ObservatoryElement {
725 final Stopwatch _sw = new Stopwatch();
726 final CpuProfile profile = new CpuProfile();
727 StreamSubscription _resizeSubscription;
728 @observable NameSortedTable profileTable;
729 @observable NameSortedTable profileCallersTable;
730 @observable NameSortedTable profileCalleesTable;
731 @observable ServiceFunction focusedFunction;
732 @observable int focusedRow;
733 @observable String fetchTime = '';
734 @observable String loadTime = '';
735 @observable String state = 'Requested';
736 @observable var exception;
737 @observable var stackTrace;
738 @observable Isolate isolate;
739 @observable String sampleCount = '';
740 @observable String refreshTime = '';
741 @observable String sampleRate = '';
742 @observable String stackDepth = '';
743 @observable String timeSpan = '';
744 @observable String directionSelector = 'Up';
745
746 CpuProfileTableElement.created() : super.created() {
747 var columns = [
748 new SortedTableColumn.withFormatter('Executing (%)',
749 Utils.formatPercentNormalized),
750 new SortedTableColumn.withFormatter('In stack (%)',
751 Utils.formatPercentNormalized),
752 new SortedTableColumn('Method'),
753 ];
754 profileTable = new NameSortedTable(columns);
755 profileTable.sortColumnIndex = 0;
756
757 columns = [
758 new SortedTableColumn.withFormatter('Callees (%)',
759 Utils.formatPercentNormalized),
760 new SortedTableColumn('Method')
761 ];
762 profileCalleesTable = new NameSortedTable(columns);
763 profileCalleesTable.sortColumnIndex = 0;
764
765 columns = [
766 new SortedTableColumn.withFormatter('Callers (%)',
767 Utils.formatPercentNormalized),
768 new SortedTableColumn('Method')
769 ];
770 profileCallersTable = new NameSortedTable(columns);
771 profileCallersTable.sortColumnIndex = 0;
772 }
773
774 attached() {
775 super.attached();
776 _resizeSubscription = window.onResize.listen((_) => _updateSize());
777 _updateSize();
778 }
779
780 detached() {
781 super.detached();
782 if (_resizeSubscription != null) {
783 _resizeSubscription.cancel();
784 }
785 }
786
787 _updateSize() {
788 HtmlElement e = $['main'];
789 final totalHeight = window.innerHeight;
790 final top = e.offset.top;
791 final bottomMargin = 32;
792 final mainHeight = totalHeight - top - bottomMargin;
793 e.style.setProperty('height', '${mainHeight}px');
794 }
795
796 isolateChanged() {
797 _getCpuProfile().whenComplete(checkParameters);
798 }
799
800 checkParameters() {
801 var functionId = app.locationManager.uri.queryParameters['functionId'];
802 if (functionId == null) {
803 _focusOnFunction(null);
804 return;
805 }
806 if (isolate == null) {
807 return;
808 }
809 isolate.getObject(functionId).then((func) => _focusOnFunction(func));
810 }
811
812 void directionSelectorChanged(oldValue) {
813 _updateFunctionTreeView();
814 }
815
816 void refresh(var done) {
817 _getCpuProfile().whenComplete(done);
818 }
819
820 void clear(var done) {
821 _clearCpuProfile().whenComplete(done);
822 }
823
824 _onFetchStarted() {
825 _sw.reset();
826 _sw.start();
827 state = 'Requested';
828 }
829
830 _onFetchFinished() {
831 _sw.stop();
832 fetchTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
833 }
834
835 _onLoadStarted() {
836 _sw.reset();
837 _sw.start();
838 state = 'Loading';
839 }
840
841 _onLoadFinished() {
842 _sw.stop();
843 loadTime = formatTimeMilliseconds(_sw.elapsedMilliseconds);
844 state = 'Loaded';
845 }
846
847 Future _clearCpuProfile() {
848 profile.clear();
849 _clearView();
850 if (isolate == null) {
851 return new Future.value(null);
852 }
853 return isolate.invokeRpc('clearCpuProfile', { })
854 .then((ServiceMap response) {
855 _updateView();
856 });
857 }
858
859 Future _getCpuProfile() {
860 profile.clear();
861 _clearView();
862 if (isolate == null) {
863 return new Future.value(null);
864 }
865 _onFetchStarted();
866 return isolate.invokeRpc('getCpuProfile', { 'tags': 'None' })
867 .then((response) {
868 _onFetchFinished();
869 _onLoadStarted();
870 try {
871 profile.load(isolate, response);
872 profile.buildFunctionCallerAndCallees();
873 _onLoadFinished();
874 _updateView();
875 } catch (e, st) {
876 state = 'Exception';
877 exception = e;
878 stackTrace = st;
879 }
880 }).catchError((e, st) {
881 state = 'Exception';
882 exception = e;
883 stackTrace = st;
884 });
885 }
886
887 _clearView() {
888 profileTable.clearRows();
889 _renderTable();
890 }
891
892 _updateView() {
893 sampleCount = profile.sampleCount.toString();
894 refreshTime = new DateTime.now().toString();
895 stackDepth = profile.stackDepth.toString();
896 sampleRate = profile.sampleRate.toStringAsFixed(0);
897 timeSpan = formatTime(profile.timeSpan);
898 _buildFunctionTable();
899 _renderTable();
900 _updateFunctionTreeView();
901 }
902
903 int _findFunctionRow(ServiceFunction function) {
904 for (var i = 0; i < profileTable.sortedRows.length; i++) {
905 var rowIndex = profileTable.sortedRows[i];
906 var row = profileTable.rows[rowIndex];
907 if (row.values[NameSortedTable.FUNCTION_COLUMN] == function) {
908 return i;
909 }
910 }
911 return -1;
912 }
913
914 _scrollToFunction(ServiceFunction function) {
915 TableSectionElement tableBody = $['profile-table'];
916 var row = _findFunctionRow(function);
917 if (row == -1) {
918 return;
919 }
920 tableBody.children[row].classes.remove('shake');
921 // trigger reflow.
922 tableBody.children[row].offsetHeight;
923 tableBody.children[row].scrollIntoView(ScrollAlignment.CENTER);
924 tableBody.children[row].classes.add('shake');
925 }
926
927 _clearFocusedFunction() {
928 TableSectionElement tableBody = $['profile-table'];
929 // Clear current focus.
930 if (focusedRow != null) {
931 tableBody.children[focusedRow].classes.remove('focused');
932 }
933 focusedRow = null;
934 focusedFunction = null;
935 }
936
937 _focusOnFunction(ServiceFunction function) {
938 if (focusedFunction == function) {
939 return;
940 }
941
942 _clearFocusedFunction();
943
944 if (function == null) {
945 _updateFunctionTreeView();
946 return;
947 }
948
949 var row = _findFunctionRow(function);
950 if (row == -1) {
951 _updateFunctionTreeView();
952 return;
953 }
954
955 focusedRow = row;
956 focusedFunction = function;
957
958 app.locationManager.goParameter(
959 {
960 'functionId': focusedFunction.id
961 }
962 );
963
964 TableSectionElement tableBody = $['profile-table'];
965 tableBody.children[focusedRow].classes.add('focused');
966 _updateFunctionTreeView();
967 }
968
969 _onRowClick(TableRowElement tr) {
970 var tableBody = $['profile-table'];
971 var row = profileTable.rowFromIndex(tableBody.children.indexOf(tr));
972 var function = row.values[NameSortedTable.FUNCTION_COLUMN];
973 _focusOnFunction(function);
974 _buildCallersTable(function);
975 _buildCalleesTable(function);
976 }
977
978 _renderTable() {
979 profileTable._updateTableView($['profile-table'],
980 profileTable._makeFunctionRow,
981 _onRowClick,
982 NameSortedTable.FUNCTION_SPACER_COLUMNS,
983 NameSortedTable.FUNCTION_COLUMN);
984 }
985
986 _buildFunctionTable() {
987 for (var func in profile.functions) {
988 if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) {
989 // Skip.
990 continue;
991 }
992 var row = [
993 func.normalizedExclusiveTicks,
994 func.normalizedInclusiveTicks,
995 func.function,
996 ];
997 profileTable.addRow(new SortedTableRow(row));
998 }
999 profileTable.sort();
1000 }
1001
1002 _renderCallTable(TableSectionElement view,
1003 NameSortedTable model,
1004 void onRowClick(TableRowElement tr)) {
1005 model._updateTableView(view,
1006 model._makeCallRow,
1007 onRowClick,
1008 NameSortedTable.CALL_SPACER_COLUMNS,
1009 NameSortedTable.CALL_FUNCTION_COLUMN);
1010 }
1011
1012 _buildCallTable(Map<ProfileFunction, int> calls,
1013 NameSortedTable model) {
1014 model.clearRows();
1015 var sum = 0;
1016 calls.values.forEach((i) => sum += i);
1017 calls.forEach((func, count) {
1018 var row = [
1019 count / sum,
1020 func.function,
1021 ];
1022 model.addRow(new SortedTableRow(row));
1023 });
1024 model.sort();
1025 }
1026
1027 _onCallersClick(TableRowElement tr) {
1028 var table = $['callers-table'];
1029 final row = profileCallersTable.rowFromIndex(table.children.indexOf(tr));
1030 var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
1031 _scrollToFunction(function);
1032 }
1033
1034 _buildCallersTable(ServiceFunction function) {
1035 var profileFunction = function.profile;
1036 var calls = profileFunction.callers;
1037 var table = $['callers-table'];
1038 _buildCallTable(calls, profileCallersTable);
1039 _renderCallTable(table, profileCallersTable, _onCallersClick);
1040 }
1041
1042 _onCalleesClick(TableRowElement tr) {
1043 var table = $['callees-table'];
1044 final row = profileCalleesTable.rowFromIndex(table.children.indexOf(tr));
1045 var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
1046 _scrollToFunction(function);
1047 }
1048
1049 _buildCalleesTable(ServiceFunction function) {
1050 var profileFunction = function.profile;
1051 var calls = profileFunction.callees;
1052 var table = $['callees-table'];
1053 _buildCallTable(calls, profileCalleesTable);
1054 _renderCallTable(table, profileCalleesTable, _onCalleesClick);
1055 }
1056
1057 _changeSort(Element target, NameSortedTable table) {
1058 if (target is TableCellElement) {
1059 if (table.sortColumnIndex != target.cellIndex) {
1060 table.sortColumnIndex = target.cellIndex;
1061 table.sortDescending = true;
1062 } else {
1063 table.sortDescending = !profileTable.sortDescending;
1064 }
1065 table.sort();
1066 }
1067 }
1068
1069 changeSortProfile(Event e, var detail, Element target) {
1070 _changeSort(target, profileTable);
1071 _renderTable();
1072 }
1073
1074 changeSortCallers(Event e, var detail, Element target) {
1075 _changeSort(target, profileCallersTable);
1076 _renderCallTable($['callers-table'], profileCallersTable, _onCallersClick);
1077 }
1078
1079 changeSortCallees(Event e, var detail, Element target) {
1080 _changeSort(target, profileCalleesTable);
1081 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick);
1082 }
1083
1084 //////
1085 ///
1086 /// Function tree.
1087 ///
1088 TableTree functionTree;
1089 _updateFunctionTreeView() {
1090 if (functionTree != null) {
1091 functionTree.clear();
1092 functionTree = null;
1093 }
1094 _buildFunctionTree();
1095 }
1096
1097 void _buildFunctionTree() {
1098 if (functionTree == null) {
1099 var tableBody = shadowRoot.querySelector('#treeBody');
1100 assert(tableBody != null);
1101 functionTree = new TableTree(tableBody, 2);
1102 }
1103 if (focusedFunction == null) {
1104 return;
1105 }
1106 bool exclusive = directionSelector == 'Up';
1107 var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
1108 if (tree == null) {
1109 return;
1110 }
1111 var filter = (FunctionCallTreeNode node) {
1112 return node.profileFunction.function == focusedFunction;
1113 };
1114 tree = tree.filtered(filter);
1115 var rootRow =
1116 new FunctionProfileTreeRow(functionTree, null, profile, tree.root);
1117 functionTree.initialize(rootRow);
1118 }
1119 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698