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

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 // Do nothing.
940 return;
941 }
942
943 _clearFocusedFunction();
944
945 if (function == null) {
946 _updateFunctionTreeView();
947 _clearCallTables();
948 return;
949 }
950
951 var row = _findFunctionRow(function);
952 if (row == -1) {
953 _updateFunctionTreeView();
954 _clearCallTables();
955 return;
956 }
957
958 focusedRow = row;
959 focusedFunction = function;
960
961 TableSectionElement tableBody = $['profile-table'];
962 tableBody.children[focusedRow].classes.add('focused');
963 _updateFunctionTreeView();
964 _buildCallersTable(focusedFunction);
965 _buildCalleesTable(focusedFunction);
966 }
967
968 _onRowClick(TableRowElement tr) {
969 var tableBody = $['profile-table'];
970 var row = profileTable.rowFromIndex(tableBody.children.indexOf(tr));
971 var function = row.values[NameSortedTable.FUNCTION_COLUMN];
972 app.locationManager.goParameter(
973 {
974 'functionId': function.id
975 }
976 );
977 }
978
979 _renderTable() {
980 profileTable._updateTableView($['profile-table'],
981 profileTable._makeFunctionRow,
982 _onRowClick,
983 NameSortedTable.FUNCTION_SPACER_COLUMNS,
984 NameSortedTable.FUNCTION_COLUMN);
985 }
986
987 _buildFunctionTable() {
988 for (var func in profile.functions) {
989 if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) {
990 // Skip.
991 continue;
992 }
993 var row = [
994 func.normalizedExclusiveTicks,
995 func.normalizedInclusiveTicks,
996 func.function,
997 ];
998 profileTable.addRow(new SortedTableRow(row));
999 }
1000 profileTable.sort();
1001 }
1002
1003 _renderCallTable(TableSectionElement view,
1004 NameSortedTable model,
1005 void onRowClick(TableRowElement tr)) {
1006 model._updateTableView(view,
1007 model._makeCallRow,
1008 onRowClick,
1009 NameSortedTable.CALL_SPACER_COLUMNS,
1010 NameSortedTable.CALL_FUNCTION_COLUMN);
1011 }
1012
1013 _buildCallTable(Map<ProfileFunction, int> calls,
1014 NameSortedTable model) {
1015 model.clearRows();
1016 if (calls == null) {
1017 return;
1018 }
1019 var sum = 0;
1020 calls.values.forEach((i) => sum += i);
1021 calls.forEach((func, count) {
1022 var row = [
1023 count / sum,
1024 func.function,
1025 ];
1026 model.addRow(new SortedTableRow(row));
1027 });
1028 model.sort();
1029 }
1030
1031 _clearCallTables() {
1032 _buildCallersTable(null);
1033 _buildCalleesTable(null);
1034 }
1035
1036 _onCallersClick(TableRowElement tr) {
1037 var table = $['callers-table'];
1038 final row = profileCallersTable.rowFromIndex(table.children.indexOf(tr));
1039 var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
1040 _scrollToFunction(function);
1041 }
1042
1043 _buildCallersTable(ServiceFunction function) {
1044 var calls = (function != null) ? function.profile.callers : null;
1045 var table = $['callers-table'];
1046 _buildCallTable(calls, profileCallersTable);
1047 _renderCallTable(table, profileCallersTable, _onCallersClick);
1048 }
1049
1050 _onCalleesClick(TableRowElement tr) {
1051 var table = $['callees-table'];
1052 final row = profileCalleesTable.rowFromIndex(table.children.indexOf(tr));
1053 var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
1054 _scrollToFunction(function);
1055 }
1056
1057 _buildCalleesTable(ServiceFunction function) {
1058 var calls = (function != null) ? function.profile.callees : null;
1059 var table = $['callees-table'];
1060 _buildCallTable(calls, profileCalleesTable);
1061 _renderCallTable(table, profileCalleesTable, _onCalleesClick);
1062 }
1063
1064 _changeSort(Element target, NameSortedTable table) {
1065 if (target is TableCellElement) {
1066 if (table.sortColumnIndex != target.cellIndex) {
1067 table.sortColumnIndex = target.cellIndex;
1068 table.sortDescending = true;
1069 } else {
1070 table.sortDescending = !profileTable.sortDescending;
1071 }
1072 table.sort();
1073 }
1074 }
1075
1076 changeSortProfile(Event e, var detail, Element target) {
1077 _changeSort(target, profileTable);
1078 _renderTable();
1079 }
1080
1081 changeSortCallers(Event e, var detail, Element target) {
1082 _changeSort(target, profileCallersTable);
1083 _renderCallTable($['callers-table'], profileCallersTable, _onCallersClick);
1084 }
1085
1086 changeSortCallees(Event e, var detail, Element target) {
1087 _changeSort(target, profileCalleesTable);
1088 _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick);
1089 }
1090
1091 //////
1092 ///
1093 /// Function tree.
1094 ///
1095 TableTree functionTree;
1096 _updateFunctionTreeView() {
1097 if (functionTree != null) {
1098 functionTree.clear();
1099 functionTree = null;
1100 }
1101 _buildFunctionTree();
1102 }
1103
1104 void _buildFunctionTree() {
1105 if (functionTree == null) {
1106 var tableBody = shadowRoot.querySelector('#treeBody');
1107 assert(tableBody != null);
1108 functionTree = new TableTree(tableBody, 2);
1109 }
1110 if (focusedFunction == null) {
1111 return;
1112 }
1113 bool exclusive = directionSelector == 'Up';
1114 var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
1115 if (tree == null) {
1116 return;
1117 }
1118 var filter = (FunctionCallTreeNode node) {
1119 return node.profileFunction.function == focusedFunction;
1120 };
1121 tree = tree.filtered(filter);
1122 var rootRow =
1123 new FunctionProfileTreeRow(functionTree, null, profile, tree.root);
1124 functionTree.initialize(rootRow);
1125 }
1126 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/context_view.html ('k') | runtime/observatory/lib/src/elements/cpu_profile.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698