| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'dart:async'; |
| 6 import 'dart:html'; |
| 7 import 'dart:math' as Math; |
| 8 import 'package:observatory/models.dart' as M; |
| 9 import 'package:observatory/src/elements/stack_trace_tree_config.dart' |
| 10 show ProfileTreeMode; |
| 11 import 'package:observatory/src/elements/code_ref.dart'; |
| 12 import 'package:observatory/src/elements/containers/virtual_tree.dart'; |
| 13 import 'package:observatory/src/elements/function_ref.dart'; |
| 14 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 15 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 16 import 'package:observatory/utils.dart'; |
| 17 |
| 18 export 'package:observatory/src/elements/stack_trace_tree_config.dart' |
| 19 show ProfileTreeMode; |
| 20 |
| 21 class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { |
| 22 static const tag = |
| 23 const Tag<CpuProfileVirtualTreeElement>('cpu-profile-virtual-tree'); |
| 24 |
| 25 RenderingScheduler<CpuProfileVirtualTreeElement> _r; |
| 26 |
| 27 Stream<RenderedEvent<CpuProfileVirtualTreeElement>> get onRendered => |
| 28 _r.onRendered; |
| 29 |
| 30 M.ProfileTreeDirection _direction; |
| 31 ProfileTreeMode _mode; |
| 32 M.IsolateRef _isolate; |
| 33 M.SampleProfile _profile; |
| 34 M.CallTreeNodeFilter _filter; |
| 35 |
| 36 M.ProfileTreeDirection get direction => _direction; |
| 37 ProfileTreeMode get mode => _mode; |
| 38 M.IsolateRef get isolate => _isolate; |
| 39 M.SampleProfile get profile => _profile; |
| 40 M.CallTreeNodeFilter get filter => _filter; |
| 41 |
| 42 set direction(M.ProfileTreeDirection value) => |
| 43 _direction = _r.checkAndReact(_direction, value); |
| 44 set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value); |
| 45 set filter(M.CallTreeNodeFilter value) => |
| 46 _filter = _r.checkAndReact(_filter, value); |
| 47 |
| 48 factory CpuProfileVirtualTreeElement(M.IsolateRef isolate, |
| 49 M.SampleProfile profile, {ProfileTreeMode mode: ProfileTreeMode.function, |
| 50 M.ProfileTreeDirection direction: M.ProfileTreeDirection.exclusive, |
| 51 RenderingQueue queue}) { |
| 52 assert(isolate != null); |
| 53 assert(profile != null); |
| 54 assert(mode != null); |
| 55 assert(direction != null); |
| 56 CpuProfileVirtualTreeElement e = document.createElement(tag.name); |
| 57 e._r = new RenderingScheduler(e, queue: queue); |
| 58 e._isolate = isolate; |
| 59 e._profile = profile; |
| 60 e._mode = mode; |
| 61 e._direction = direction; |
| 62 return e; |
| 63 } |
| 64 |
| 65 CpuProfileVirtualTreeElement.created() : super.created(); |
| 66 |
| 67 @override |
| 68 attached() { |
| 69 super.attached(); |
| 70 _r.enable(); |
| 71 } |
| 72 |
| 73 @override |
| 74 detached() { |
| 75 super.detached(); |
| 76 _r.disable(notify: true); |
| 77 children = []; |
| 78 } |
| 79 |
| 80 VirtualTreeElement _tree; |
| 81 |
| 82 void render() { |
| 83 var tree; |
| 84 var update; |
| 85 switch (mode) { |
| 86 case ProfileTreeMode.code: |
| 87 tree = _profile.loadCodeTree(_direction); |
| 88 update = _updateCodeRow; |
| 89 break; |
| 90 case ProfileTreeMode.function: |
| 91 tree = _profile.loadFunctionTree(_direction); |
| 92 update = _updateFunctionRow; |
| 93 break; |
| 94 default: |
| 95 throw new Exception('Unknown ProfileTreeMode: $mode'); |
| 96 } |
| 97 if (tree == null) { |
| 98 children = [ |
| 99 new HeadingElement.h1()..text = 'No Results' |
| 100 ]; |
| 101 return; |
| 102 } |
| 103 if (filter != null) { |
| 104 tree = tree.filtered(filter); |
| 105 } |
| 106 _tree = new VirtualTreeElement(_createRow, update, _getChildren, |
| 107 items: tree.root.children, queue: _r.queue); |
| 108 if (tree.root.children.length == 1) { |
| 109 _tree.expand(tree.root.children.first, autoExpandSingleChildNodes: true); |
| 110 } |
| 111 children = [_tree]; |
| 112 } |
| 113 |
| 114 static Element _createRow(toggle) { |
| 115 return new DivElement() |
| 116 ..classes = const ['tree-item'] |
| 117 ..children = [ |
| 118 new SpanElement()..classes = const ['inclusive'] |
| 119 ..title = 'global % on stack', |
| 120 new SpanElement()..classes = const ['exclusive'] |
| 121 ..title = 'global % executing', |
| 122 new SpanElement()..classes = const ['lines'], |
| 123 new ButtonElement()..classes = const ['expander'] |
| 124 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
| 125 new SpanElement()..classes = const ['percentage'] |
| 126 ..title = 'tree node %', |
| 127 new SpanElement()..classes = const ['name'] |
| 128 ]; |
| 129 } |
| 130 |
| 131 static _getChildren(M.CallTreeNode node) => node.children; |
| 132 |
| 133 void _updateFunctionRow(HtmlElement element, M.FunctionCallTreeNode item, |
| 134 int depth) { |
| 135 element.children[0].text = Utils.formatPercentNormalized( |
| 136 item.profileFunction.normalizedInclusiveTicks); |
| 137 element.children[1].text = Utils.formatPercentNormalized( |
| 138 item.profileFunction.normalizedExclusiveTicks); |
| 139 _updateLines(element.children[2].children, depth); |
| 140 if (item.children.isNotEmpty) { |
| 141 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; |
| 142 } else { |
| 143 element.children[3].text = ''; |
| 144 } |
| 145 element.children[4].text = Utils.formatPercentNormalized( |
| 146 item.percentage); |
| 147 element.children[5] = new FunctionRefElement(_isolate, |
| 148 item.profileFunction.function, queue: _r.queue) |
| 149 ..classes = const ['name']; |
| 150 } |
| 151 |
| 152 void _updateCodeRow(HtmlElement element, M.CodeCallTreeNode item, int depth) { |
| 153 element.children[0].text = Utils.formatPercentNormalized( |
| 154 item.profileCode.normalizedInclusiveTicks); |
| 155 element.children[1].text = Utils.formatPercentNormalized( |
| 156 item.profileCode.normalizedExclusiveTicks); |
| 157 _updateLines(element.children[2].children, depth); |
| 158 if (item.children.isNotEmpty) { |
| 159 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; |
| 160 } else { |
| 161 element.children[3].text = ''; |
| 162 } |
| 163 element.children[4].text = Utils.formatPercentNormalized( |
| 164 item.percentage); |
| 165 element.children[5] = new CodeRefElement(_isolate, |
| 166 item.profileCode.code, queue: _r.queue) |
| 167 ..classes = const ['name']; |
| 168 } |
| 169 |
| 170 static _updateLines(List<Element> lines, int n) { |
| 171 n = Math.max(0, n); |
| 172 while (lines.length > n) { |
| 173 lines.removeLast(); |
| 174 } |
| 175 while (lines.length < n) { |
| 176 lines.add(new SpanElement()); |
| 177 } |
| 178 } |
| 179 } |
| OLD | NEW |