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

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

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