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

Unified Diff: runtime/observatory/lib/src/elements/cpu_profile.dart

Issue 1833453004: Dramatically increase the performance of Observatory's profile UI (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: runtime/observatory/lib/src/elements/cpu_profile.dart
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index c026d7c04477718bebb916c27fc15fd32fbc110c..6f74bbc2db792e703bffe0a627fae71223911493 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -569,6 +569,109 @@ class StackTraceTreeConfigElement extends ObservatoryElement {
@observable String directionSelector = 'Up';
}
+class FunctionCallTreeNodeRow extends VirtualTreeRow {
+ final CpuProfile profile;
+ final FunctionCallTreeNode node;
+ final String selfPercent;
+ final String totalPercent;
+ final String percent;
+
+ FunctionCallTreeNodeRow(VirtualTree tree,
+ int depth,
+ this.profile,
+ FunctionCallTreeNode node)
+ : node = node,
+ selfPercent = Utils.formatPercentNormalized(node.profileFunction.normalizedExclusiveTicks),
+ totalPercent = Utils.formatPercentNormalized(node.profileFunction.normalizedInclusiveTicks),
+ percent = Utils.formatPercentNormalized(node.percentage),
+ super(tree, depth) {
+ }
+
+ void onRender(DivElement rowDiv) {
+ rowDiv.children.add(
+ makeText(totalPercent, toolTip: 'global % on stack'));
+ rowDiv.children.add(makeGap());
+ rowDiv.children.add(
+ makeText(selfPercent, toolTip: 'global % executing'));
+ rowDiv.children.add(makeGap());
+ rowDiv.children.add(makeIndenter(colored: false));
+ rowDiv.children.add(makeColorBar());
+ rowDiv.children.add(makeGap(ems: 1.0));
+ rowDiv.children.add(makeExpander());
+ rowDiv.children.add(
+ makeText(percent, toolTip: 'tree node %', flexBasis: null));
+ rowDiv.children.add(makeGap(ems: 0.5));
+ functionRef.ref = node.profileFunction.function;
+ rowDiv.children.add(functionRef);
+ }
+
+ var functionRef = new Element.tag('function-ref');
+
+ int get childCount => node.children.length;
+
+ void onShow() {
+ if (children.length > 0) {
+ return;
+ }
+ for (var childNode in node.children) {
+ var row = new FunctionCallTreeNodeRow(tree, depth + 1, profile, childNode);
+ children.add(row);
+ }
+ }
+}
+
+
+class CodeCallTreeNodeRow extends VirtualTreeRow {
+ final CpuProfile profile;
+ final CodeCallTreeNode node;
+ final String selfPercent;
+ final String totalPercent;
+ final String percent;
+
+ CodeCallTreeNodeRow(VirtualTree tree,
+ int depth,
+ this.profile,
+ CodeCallTreeNode node)
+ : node = node,
+ selfPercent = Utils.formatPercentNormalized(node.profileCode.normalizedExclusiveTicks),
+ totalPercent = Utils.formatPercentNormalized(node.profileCode.normalizedInclusiveTicks),
+ percent = Utils.formatPercentNormalized(node.percentage),
+ super(tree, depth) {
+ }
+
+ void onRender(DivElement rowDiv) {
+ rowDiv.children.add(
+ makeText(totalPercent, toolTip: 'global % on stack'));
+ rowDiv.children.add(makeGap());
+ rowDiv.children.add(
+ makeText(selfPercent, toolTip: 'global % executing'));
+ rowDiv.children.add(makeGap());
+ rowDiv.children.add(makeIndenter(colored: false));
+ rowDiv.children.add(makeColorBar());
+ rowDiv.children.add(makeGap(ems: 1.0));
+ rowDiv.children.add(makeExpander());
+ rowDiv.children.add(
+ makeText(percent, toolTip: 'tree node %', flexBasis: null));
+ rowDiv.children.add(makeGap(ems: 0.5));
+ codeRef.ref = node.profileCode.code;
+ rowDiv.children.add(codeRef);
+ }
+
+ var codeRef = new Element.tag('code-ref');
+
+ int get childCount => node.children.length;
+
+ void onShow() {
+ if (children.length > 0) {
+ return;
+ }
+ for (var childNode in node.children) {
+ var row = new CodeCallTreeNodeRow(tree, depth + 1, profile, childNode);
+ children.add(row);
+ }
+ }
+}
+
/// Displays a CpuProfile
@CustomTag('cpu-profile')
class CpuProfileElement extends ObservatoryElement {
@@ -587,10 +690,32 @@ class CpuProfileElement extends ObservatoryElement {
shadowRoot.querySelector('#stackTraceTreeConfig');
assert(stackTraceTreeConfigElement != null);
stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
- cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
- assert(cpuProfileTreeElement != null);
- cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
+ cpuProfileVirtualTreeElement = shadowRoot.querySelector('#cpuProfileVirtualTree');
+ assert(cpuProfileVirtualTreeElement != null);
+ cpuProfileVirtualTreeElement.profile = sampleBufferControlElement.profile;
+ _resizeSubscription = window.onResize.listen((_) => _updateSize());
_updateTask.queue();
+ _updateSize();
+ }
+
+ detached() {
+ super.detached();
+ if (_resizeSubscription != null) {
+ _resizeSubscription.cancel();
+ }
+ }
+
+ _updateSize() {
+ var applySize = (e) {
+ Rectangle rect = e.getBoundingClientRect();
+ final totalHeight = window.innerHeight;
+ final top = rect.top;
+ final bottomMargin = 200;
+ final mainHeight = totalHeight - top - bottomMargin;
+ e.style.setProperty('height', '${mainHeight}px');
+ };
+ HtmlElement e2 = $['cpuProfileVirtualTree'];
+ applySize(e2);
}
isolateChanged(oldValue) {
@@ -616,8 +741,8 @@ class CpuProfileElement extends ObservatoryElement {
if (modeSelector == 'Code') {
mode = ProfileTreeMode.Code;
}
- cpuProfileTreeElement.direction = direction;
- cpuProfileTreeElement.mode = mode;
+ cpuProfileVirtualTreeElement.direction = direction;
+ cpuProfileVirtualTreeElement.mode = mode;
_renderTask.queue();
}
@@ -633,16 +758,17 @@ class CpuProfileElement extends ObservatoryElement {
}
render() {
- cpuProfileTreeElement.render();
+ cpuProfileVirtualTreeElement.render();
}
@published Isolate isolate;
+ StreamSubscription _resizeSubscription;
Task _updateTask;
Task _renderTask;
SampleBufferControlElement sampleBufferControlElement;
StackTraceTreeConfigElement stackTraceTreeConfigElement;
- CpuProfileTreeElement cpuProfileTreeElement;
+ CpuProfileVirtualTreeElement cpuProfileVirtualTreeElement;
}
class NameSortedTable extends SortedTable {
@@ -1140,6 +1266,85 @@ enum ProfileTreeMode {
Function,
}
+@CustomTag('cpu-profile-virtual-tree')
+class CpuProfileVirtualTreeElement extends ObservatoryElement {
+ ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
+ ProfileTreeMode mode = ProfileTreeMode.Function;
+ CpuProfile profile;
+ VirtualTree virtualTree;
+ FunctionCallTreeNodeFilter functionFilter;
+ @observable bool show = true;
+
+ CpuProfileVirtualTreeElement.created() : super.created();
+
+ void render() {
+ _updateView();
+ }
+
+ showChanged(oldValue) {
+ var treeTable = shadowRoot.querySelector('#treeTable');
+ assert(treeTable != null);
+ treeTable.style.display = show ? 'table' : 'none';
+ }
+
+ void _updateView() {
+ virtualTree?.clear();
+ virtualTree?.uninstall();
+ virtualTree = null;
+ bool exclusive = direction == ProfileTreeDirection.Exclusive;
+ if (mode == ProfileTreeMode.Code) {
+ _buildCodeTree(exclusive);
+ } else {
+ assert(mode == ProfileTreeMode.Function);
+ _buildFunctionTree(exclusive);
+ }
+ virtualTree?.refresh();
+ }
+
+ void _buildFunctionTree(bool exclusive) {
+ var treeBody = shadowRoot.querySelector('#tree');
+ assert(treeBody != null);
+ virtualTree = new VirtualTree(32, treeBody);
+ if (profile == null) {
+ return;
+ }
+ var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
+ if (tree == null) {
+ return;
+ }
+ if (functionFilter != null) {
+ tree = tree.filtered(functionFilter);
+ }
+ for (var child in tree.root.children) {
+ virtualTree.rows.add(
+ new FunctionCallTreeNodeRow(virtualTree, 0, profile, child));
+ }
+ if (virtualTree.rows.length == 1) {
+ virtualTree.rows[0].expanded = true;
+ }
+ }
+
+ void _buildCodeTree(bool exclusive) {
+ var treeBody = shadowRoot.querySelector('#tree');
+ assert(treeBody != null);
+ virtualTree = new VirtualTree(32, treeBody);
+ if (profile == null) {
+ return;
+ }
+ var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive');
+ if (tree == null) {
+ return;
+ }
+ for (var child in tree.root.children) {
+ virtualTree.rows.add(
+ new CodeCallTreeNodeRow(virtualTree, 0, profile, child));
+ }
+ if (virtualTree.rows.length == 1) {
+ virtualTree.rows[0].expanded = true;
+ }
+ }
+}
+
@CustomTag('cpu-profile-tree')
class CpuProfileTreeElement extends ObservatoryElement {
ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
« no previous file with comments | « runtime/observatory/lib/src/app/view_model.dart ('k') | runtime/observatory/lib/src/elements/cpu_profile.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698