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

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

Powered by Google App Engine
This is Rietveld 408576698