Chromium Code Reviews| Index: runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart |
| diff --git a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..83a1f5a90a7bb16d6228257bb62282f26ef895ec |
| --- /dev/null |
| +++ b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart |
| @@ -0,0 +1,204 @@ |
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +import 'dart:async'; |
| +import 'dart:html'; |
| +import 'dart:math' as Math; |
| +import 'package:observatory/models.dart' as M; |
| +import 'package:observatory/src/elements/stack_trace_tree_config.dart' |
| + show ProfileTreeMode, ProfileTreeDirection; |
| +import 'package:observatory/src/elements/code_ref.dart'; |
| +import 'package:observatory/src/elements/containers/virtual_tree.dart'; |
| +import 'package:observatory/src/elements/function_ref.dart'; |
| +import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| +import 'package:observatory/src/elements/helpers/tag.dart'; |
| +import 'package:observatory/utils.dart'; |
| + |
| +class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { |
| + static const tag = |
| + const Tag<CpuProfileVirtualTreeElement>('cpu-profile-virtual-tree'); |
| + |
| + RenderingScheduler<CpuProfileVirtualTreeElement> _r; |
| + |
| + Stream<RenderedEvent<CpuProfileVirtualTreeElement>> get onRendered => |
| + _r.onRendered; |
| + |
| + ProfileTreeDirection _direction; |
| + ProfileTreeMode _mode; |
| + M.Isolate _isolate; |
| + M.SampleProfile _profile; |
| + M.CallTreeNodeFilter _filter; |
| + |
| + ProfileTreeDirection get direction => _direction; |
| + ProfileTreeMode get mode => _mode; |
| + M.Isolate get isolate => _isolate; |
| + M.SampleProfile get profile => _profile; |
| + M.CallTreeNodeFilter get filter => _filter; |
| + |
| + set direction(ProfileTreeDirection value) => |
| + _direction = _r.checkAndReact(_direction, value); |
| + set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value); |
| + set filter(M.CallTreeNodeFilter value) => |
| + _filter = _r.checkAndReact(_filter, value); |
| + |
| + factory CpuProfileVirtualTreeElement(M.IsolateRef isolate, |
| + M.SampleProfile profile, {ProfileTreeMode mode: ProfileTreeMode.Function, |
| + ProfileTreeDirection direction: ProfileTreeDirection.Exclusive, |
| + RenderingQueue queue}) { |
| + assert(isolate != null); |
| + assert(profile != null); |
| + assert(mode != null); |
| + assert(direction != null); |
| + CpuProfileVirtualTreeElement e = document.createElement(tag.name); |
| + e._r = new RenderingScheduler(e, queue: queue); |
| + e._isolate = isolate; |
| + e._profile = profile; |
| + e._mode = mode; |
| + e._direction = direction; |
| + return e; |
| + } |
| + |
| + |
| + CpuProfileVirtualTreeElement.created() : super.created(); |
| + |
| + @override |
| + attached() { |
| + super.attached(); |
| + _r.enable(); |
| + } |
| + |
| + @override |
| + detached() { |
| + super.detached(); _r.disable(notify: true); |
| + children = []; |
| + } |
| + |
| + void render() { |
| + children = const []; |
| + bool exclusive = direction == ProfileTreeDirection.Exclusive; |
| + switch (mode) { |
| + case ProfileTreeMode.Code: |
| + _buildCodeTree(exclusive); |
| + break; |
| + case ProfileTreeMode.Function: |
| + _buildFunctionTree(exclusive); |
| + break; |
| + default: |
| + throw new Exception('Unknown ProfileTreeMode'); |
| + } |
| + } |
| + |
| + static const kHotThreshold = 0.05; // 5%. |
| + static const kMediumThreshold = 0.02; // 2%. |
| + |
| + void _buildFunctionTree(bool exclusive) { |
| + var tree = _profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive'); |
| + if (tree == null) { |
| + return; |
| + } |
| + if (filter != null) { |
| + tree = tree.filtered(filter); |
| + } |
| + var t; |
| + children = [ |
| + t = new VirtualTreeElement((toggle) { |
|
Cutch
2016/08/02 15:52:20
could this closure be turned into a named method?
cbernaschina
2016/08/02 17:40:24
Done.
|
| + return new DivElement() |
| + ..classes = const ['tmp-collection-item'] |
| + ..children = [ |
| + new SpanElement()..classes = const ['inclusive'] |
| + ..title = 'global % on stack', |
| + new SpanElement()..classes = const ['exclusive'] |
| + ..title = 'global % executing', |
| + new SpanElement()..classes = const ['lines'], |
| + new SpanElement()..classes = const ['expander'] |
| + ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
| + new SpanElement()..classes = const ['percentage'] |
| + ..title = 'tree node %', |
| + new SpanElement()..classes = const ['name'] |
| + ]; |
| + }, (HtmlElement element, M.FunctionCallTreeNode item, int depth) { |
| + element.children[0].text = Utils.formatPercentNormalized( |
| + item.profileFunction.normalizedInclusiveTicks); |
| + element.children[1].text = Utils.formatPercentNormalized( |
| + item.profileFunction.normalizedExclusiveTicks); |
| + _updateLines(element.children[2].children, depth); |
| + if (item.children.isNotEmpty) { |
| + element.children[3].text = t.isExpanded(item) ? '▼' : '►'; |
| + } else { |
| + element.children[3].text = ''; |
| + } |
| + element.children[4].text = Utils.formatPercentNormalized( |
| + item.percentage); |
| + element.children[5] = new FunctionRefElement(_isolate, |
| + item.profileFunction.function, queue: _r.queue) |
| + ..classes = const ['name']; |
| + }, (M.FunctionCallTreeNode node) => node.children, |
| + items: tree.root.children, queue: _r.queue) |
| + ]; |
| + if (tree.root.children.length == 1) { |
| + t.expand(tree.root.children.first, autoExpandSingleChildNodes: true); |
| + } |
| + } |
| + |
| + |
| + |
| + void _buildCodeTree(bool exclusive) { |
| + var tree = _profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive'); |
| + if (tree == null) { |
| + return; |
| + } |
| + if (filter != null) { |
| + tree = tree.filtered(filter); |
| + } |
| + var t; |
| + children = [ |
| + t = new VirtualTreeElement((toggle) { |
|
Cutch
2016/08/02 15:52:20
could this closure be turned into a named method?
cbernaschina
2016/08/02 17:40:24
Done.
|
| + return new DivElement() |
| + ..classes = const ['tmp-collection-item'] |
| + ..children = [ |
| + new SpanElement()..classes = const ['inclusive'] |
| + ..title = 'global % on stack', |
| + new SpanElement()..classes = const ['exclusive'] |
| + ..title = 'global % executing', |
| + new SpanElement()..classes = const ['lines'], |
| + new SpanElement()..classes = const ['expander'] |
| + ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
| + new SpanElement()..classes = const ['percentage'] |
| + ..title = 'tree node %', |
| + new AnchorElement()..classes = const ['name'] |
| + ]; |
| + }, (HtmlElement element, M.CodeCallTreeNode item, int depth) { |
| + element.children[0].text = Utils.formatPercentNormalized( |
| + item.profileCode.normalizedInclusiveTicks); |
| + element.children[1].text = Utils.formatPercentNormalized( |
| + item.profileCode.normalizedExclusiveTicks); |
| + _updateLines(element.children[2].children, depth); |
| + if (item.children.isNotEmpty) { |
| + element.children[3].text = t.isExpanded(item) ? '▼' : '►'; |
| + } else { |
| + element.children[3].text = ''; |
| + } |
| + element.children[4].text = Utils.formatPercentNormalized( |
| + item.percentage); |
| + element.children[5] = new CodeRefElement(_isolate, |
| + item.profileCode.code, queue: _r.queue) |
| + ..classes = const ['name']; |
| + }, (M.CodeCallTreeNode node) => node.children, |
| + items: tree.root.children, queue: _r.queue) |
| + ]; |
| + if (tree.root.children.length == 1) { |
| + t.expand(tree.root.children.first, autoExpandSingleChildNodes: true); |
| + } |
| + } |
| + |
| + static _updateLines(List<Element> lines, int n) { |
| + n = Math.max(0, n); |
| + while (lines.length > n) { |
| + lines.removeLast(); |
| + } |
| + while (lines.length < n) { |
| + lines.add(new SpanElement()); |
| + } |
| + } |
| +} |