OLD | NEW |
---|---|
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 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:html'; | 6 import 'dart:html'; |
7 import 'dart:math' as Math; | 7 import 'dart:math' as Math; |
8 import 'package:observatory/models.dart' as M; | 8 import 'package:observatory/models.dart' as M; |
9 import 'package:observatory/src/elements/stack_trace_tree_config.dart' | 9 import 'package:observatory/src/elements/stack_trace_tree_config.dart' |
10 show ProfileTreeMode; | 10 show ProfileTreeMode, |
11 ProfileTreeType; | |
11 import 'package:observatory/src/elements/code_ref.dart'; | 12 import 'package:observatory/src/elements/code_ref.dart'; |
12 import 'package:observatory/src/elements/containers/virtual_tree.dart'; | 13 import 'package:observatory/src/elements/containers/virtual_tree.dart'; |
13 import 'package:observatory/src/elements/function_ref.dart'; | 14 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/rendering_scheduler.dart'; |
15 import 'package:observatory/src/elements/helpers/tag.dart'; | 16 import 'package:observatory/src/elements/helpers/tag.dart'; |
16 import 'package:observatory/utils.dart'; | 17 import 'package:observatory/utils.dart'; |
17 | 18 |
18 export 'package:observatory/src/elements/stack_trace_tree_config.dart' | 19 export 'package:observatory/src/elements/stack_trace_tree_config.dart' |
19 show ProfileTreeMode; | 20 show ProfileTreeMode, |
21 ProfileTreeType; | |
20 | 22 |
21 class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 23 class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { |
22 static const tag = | 24 static const tag = |
23 const Tag<CpuProfileVirtualTreeElement>('cpu-profile-virtual-tree'); | 25 const Tag<CpuProfileVirtualTreeElement>('cpu-profile-virtual-tree'); |
24 | 26 |
25 RenderingScheduler<CpuProfileVirtualTreeElement> _r; | 27 RenderingScheduler<CpuProfileVirtualTreeElement> _r; |
26 | 28 |
27 Stream<RenderedEvent<CpuProfileVirtualTreeElement>> get onRendered => | 29 Stream<RenderedEvent<CpuProfileVirtualTreeElement>> get onRendered => |
28 _r.onRendered; | 30 _r.onRendered; |
29 | 31 |
30 M.ProfileTreeDirection _direction; | 32 M.ProfileTreeDirection _direction; |
31 ProfileTreeMode _mode; | 33 ProfileTreeMode _mode; |
34 ProfileTreeType _type; | |
32 M.IsolateRef _isolate; | 35 M.IsolateRef _isolate; |
33 M.SampleProfile _profile; | 36 M.SampleProfile _profile; |
34 Iterable<M.CallTreeNodeFilter> _filters; | 37 Iterable<M.CallTreeNodeFilter> _filters; |
35 | 38 |
36 M.ProfileTreeDirection get direction => _direction; | 39 M.ProfileTreeDirection get direction => _direction; |
37 ProfileTreeMode get mode => _mode; | 40 ProfileTreeMode get mode => _mode; |
41 ProfileTreeType get type => _type; | |
38 M.IsolateRef get isolate => _isolate; | 42 M.IsolateRef get isolate => _isolate; |
39 M.SampleProfile get profile => _profile; | 43 M.SampleProfile get profile => _profile; |
40 Iterable<M.CallTreeNodeFilter> get filters => _filters; | 44 Iterable<M.CallTreeNodeFilter> get filters => _filters; |
41 | 45 |
42 set direction(M.ProfileTreeDirection value) => | 46 set direction(M.ProfileTreeDirection value) => |
43 _direction = _r.checkAndReact(_direction, value); | 47 _direction = _r.checkAndReact(_direction, value); |
44 set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value); | 48 set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value); |
45 set filters(Iterable<M.CallTreeNodeFilter> value) { | 49 set filters(Iterable<M.CallTreeNodeFilter> value) { |
46 _filters = new List.unmodifiable(value); | 50 _filters = new List.unmodifiable(value); |
47 _r.dirty(); | 51 _r.dirty(); |
48 } | 52 } |
49 | 53 |
50 factory CpuProfileVirtualTreeElement( | 54 factory CpuProfileVirtualTreeElement( |
51 M.IsolateRef isolate, M.SampleProfile profile, | 55 M.IsolateRef isolate, M.SampleProfile profile, |
52 {ProfileTreeMode mode: ProfileTreeMode.function, | 56 {ProfileTreeMode mode: ProfileTreeMode.function, |
57 ProfileTreeType type: ProfileTreeType.cpu, | |
53 M.ProfileTreeDirection direction: M.ProfileTreeDirection.exclusive, | 58 M.ProfileTreeDirection direction: M.ProfileTreeDirection.exclusive, |
54 RenderingQueue queue}) { | 59 RenderingQueue queue}) { |
55 assert(isolate != null); | |
56 assert(profile != null); | 60 assert(profile != null); |
57 assert(mode != null); | 61 assert(mode != null); |
58 assert(direction != null); | 62 assert(direction != null); |
59 CpuProfileVirtualTreeElement e = document.createElement(tag.name); | 63 CpuProfileVirtualTreeElement e = document.createElement(tag.name); |
60 e._r = new RenderingScheduler(e, queue: queue); | 64 e._r = new RenderingScheduler(e, queue: queue); |
61 e._isolate = isolate; | 65 e._isolate = isolate; |
62 e._profile = profile; | 66 e._profile = profile; |
63 e._mode = mode; | 67 e._mode = mode; |
68 e._type = type; | |
64 e._direction = direction; | 69 e._direction = direction; |
65 return e; | 70 return e; |
66 } | 71 } |
67 | 72 |
68 CpuProfileVirtualTreeElement.created() : super.created(); | 73 CpuProfileVirtualTreeElement.created() : super.created(); |
69 | 74 |
70 @override | 75 @override |
71 attached() { | 76 attached() { |
72 super.attached(); | 77 super.attached(); |
73 _r.enable(); | 78 _r.enable(); |
74 } | 79 } |
75 | 80 |
76 @override | 81 @override |
77 detached() { | 82 detached() { |
78 super.detached(); | 83 super.detached(); |
79 _r.disable(notify: true); | 84 _r.disable(notify: true); |
80 children = []; | 85 children = []; |
81 } | 86 } |
82 | 87 |
83 VirtualTreeElement _tree; | 88 VirtualTreeElement _tree; |
84 | 89 |
85 void render() { | 90 void render() { |
86 var tree; | 91 var tree; |
92 var create; | |
87 var update; | 93 var update; |
94 | |
95 if (type == ProfileTreeType.cpu) { | |
96 create = _createCpuRow; | |
97 } else { | |
98 create = _createMemoryRow; | |
99 } | |
100 | |
88 switch (mode) { | 101 switch (mode) { |
89 case ProfileTreeMode.code: | 102 case ProfileTreeMode.code: |
90 tree = _profile.loadCodeTree(_direction); | 103 tree = _profile.loadCodeTree(_direction); |
91 update = _updateCodeRow; | 104 if (type == ProfileTreeType.cpu) { |
105 update = _updateCpuCodeRow; | |
106 } else { | |
Cutch
2017/03/21 20:27:10
} else if (type == ProfileTreeType.memory) {
} els
bkonyi
2017/03/22 21:25:21
Done in the check above so we don't have to do it
| |
107 update = _updateMemoryCodeRow; | |
108 } | |
92 break; | 109 break; |
93 case ProfileTreeMode.function: | 110 case ProfileTreeMode.function: |
94 tree = _profile.loadFunctionTree(_direction); | 111 tree = _profile.loadFunctionTree(_direction); |
95 update = _updateFunctionRow; | 112 if (type == ProfileTreeType.cpu) { |
113 update = _updateCpuFunctionRow; | |
114 } else { | |
115 update = _updateMemoryFunctionRow; | |
Cutch
2017/03/21 20:27:10
ditto
bkonyi
2017/03/22 21:25:21
See above response.
| |
116 } | |
96 break; | 117 break; |
97 default: | 118 default: |
98 throw new Exception('Unknown ProfileTreeMode: $mode'); | 119 throw new Exception('Unknown ProfileTreeMode: $mode'); |
99 } | 120 } |
100 if (filters != null) { | 121 if (filters != null) { |
101 tree = filters.fold(tree, (tree, filter) { | 122 tree = filters.fold(tree, (tree, filter) { |
102 return tree?.filtered(filter); | 123 return tree?.filtered(filter); |
103 }); | 124 }); |
104 } | 125 } |
105 if (tree == null) { | 126 if (tree == null) { |
106 children = [new HeadingElement.h1()..text = 'No Results']; | 127 children = [new HeadingElement.h1()..text = 'No Results']; |
107 return; | 128 return; |
108 } | 129 } |
109 _tree = new VirtualTreeElement(_createRow, update, _getChildren, | 130 _tree = new VirtualTreeElement(create, update, _getChildren, |
110 items: tree.root.children, queue: _r.queue); | 131 items: tree.root.children, queue: _r.queue); |
111 if (tree.root.children.length == 1) { | 132 if (tree.root.children.length == 1) { |
112 _tree.expand(tree.root.children.first, autoExpandSingleChildNodes: true); | 133 _tree.expand(tree.root.children.first, autoExpandSingleChildNodes: true); |
113 } | 134 } |
114 children = [_tree]; | 135 children = [_tree]; |
115 } | 136 } |
116 | 137 |
117 static Element _createRow(toggle) { | 138 static Element _createCpuRow(toggle) { |
118 return new DivElement() | 139 return new DivElement() |
119 ..classes = ['tree-item'] | 140 ..classes = ['tree-item'] |
120 ..children = [ | 141 ..children = [ |
121 new SpanElement() | 142 new SpanElement() |
122 ..classes = ['inclusive'] | 143 ..classes = ['inclusive'] |
123 ..title = 'global % on stack', | 144 ..title = 'global % on stack', |
124 new SpanElement() | 145 new SpanElement() |
125 ..classes = ['exclusive'] | 146 ..classes = ['exclusive'] |
126 ..title = 'global % executing', | 147 ..title = 'global % executing', |
127 new SpanElement()..classes = ['lines'], | 148 new SpanElement()..classes = ['lines'], |
128 new ButtonElement() | 149 new ButtonElement() |
129 ..classes = ['expander'] | 150 ..classes = ['expander'] |
130 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), | 151 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
131 new SpanElement() | 152 new SpanElement() |
132 ..classes = ['percentage'] | 153 ..classes = ['percentage'] |
133 ..title = 'tree node %', | 154 ..title = 'tree node %', |
134 new SpanElement()..classes = ['name'] | 155 new SpanElement()..classes = ['name'] |
135 ]; | 156 ]; |
136 } | 157 } |
137 | 158 |
159 static Element _createMemoryRow(toggle) { | |
160 return new DivElement() | |
161 ..classes = ['tree-item'] | |
162 ..children = [ | |
163 new SpanElement() | |
164 ..classes = ['inclusive'] | |
165 ..title = 'memory allocated from resulting calls: ', | |
166 new SpanElement() | |
167 ..classes = ['exclusive'] | |
168 ..title = 'memory allocated during execution: ', | |
169 new SpanElement()..classes = ['lines'], | |
170 new ButtonElement() | |
171 ..classes = ['expander'] | |
172 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), | |
173 new SpanElement() | |
174 ..classes = ['percentage'] | |
175 ..title = 'tree node %', | |
176 new SpanElement()..classes = ['name'] | |
177 ]; | |
178 } | |
179 | |
138 static _getChildren(M.CallTreeNode node) => node.children; | 180 static _getChildren(M.CallTreeNode node) => node.children; |
139 | 181 |
140 void _updateFunctionRow( | 182 void _updateCpuFunctionRow( |
141 HtmlElement element, M.FunctionCallTreeNode item, int depth) { | 183 HtmlElement element, M.FunctionCallTreeNode item, int depth) { |
142 element.children[0].text = Utils | 184 element.children[0].text = Utils |
143 .formatPercentNormalized(item.profileFunction.normalizedInclusiveTicks); | 185 .formatPercentNormalized(item.profileFunction.normalizedInclusiveTicks); |
144 element.children[1].text = Utils | 186 element.children[1].text = Utils |
145 .formatPercentNormalized(item.profileFunction.normalizedExclusiveTicks); | 187 .formatPercentNormalized(item.profileFunction.normalizedExclusiveTicks); |
146 _updateLines(element.children[2].children, depth); | 188 _updateLines(element.children[2].children, depth); |
147 if (item.children.isNotEmpty) { | 189 if (item.children.isNotEmpty) { |
148 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; | 190 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; |
Cutch
2017/03/21 20:27:10
factor these strings into named constants and use
| |
149 } else { | 191 } else { |
150 element.children[3].text = ''; | 192 element.children[3].text = ''; |
151 } | 193 } |
152 element.children[4].text = Utils.formatPercentNormalized(item.percentage); | 194 element.children[4].text = Utils.formatPercentNormalized(item.percentage); |
153 element.children[5] = new FunctionRefElement( | 195 element.children[5] = new FunctionRefElement( |
154 _isolate, item.profileFunction.function, queue: _r.queue) | 196 _isolate, item.profileFunction.function, queue: _r.queue) |
155 ..classes = ['name']; | 197 ..classes = ['name']; |
156 } | 198 } |
157 | 199 |
158 void _updateCodeRow(HtmlElement element, M.CodeCallTreeNode item, int depth) { | 200 void _updateMemoryFunctionRow( |
201 HtmlElement element, M.FunctionCallTreeNode item, int depth) { | |
202 element.children[0].text = Utils | |
203 .formatSize(item.inclusiveNativeAllocations); | |
204 element.children[0].title = 'memory allocated from resulting calls: ' + | |
205 '${item.inclusiveNativeAllocations}B'; | |
206 element.children[1].text = Utils | |
207 .formatSize(item.exclusiveNativeAllocations); | |
208 element.children[1].title = 'memory allocated during execution: ' + | |
209 '${item.exclusiveNativeAllocations}B'; | |
210 _updateLines(element.children[2].children, depth); | |
211 if (item.children.isNotEmpty) { | |
212 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; | |
213 } else { | |
214 element.children[3].text = ''; | |
215 } | |
216 element.children[4].text = | |
217 Utils.formatPercentNormalized(item.percentage); | |
218 element.children[5] = new FunctionRefElement( | |
219 null, item.profileFunction.function, queue: _r.queue) | |
220 ..classes = ['name']; | |
221 } | |
222 | |
223 void _updateCpuCodeRow(HtmlElement element, M.CodeCallTreeNode item, int depth ) { | |
159 element.children[0].text = Utils | 224 element.children[0].text = Utils |
160 .formatPercentNormalized(item.profileCode.normalizedInclusiveTicks); | 225 .formatPercentNormalized(item.profileCode.normalizedInclusiveTicks); |
161 element.children[1].text = Utils | 226 element.children[1].text = Utils |
162 .formatPercentNormalized(item.profileCode.normalizedExclusiveTicks); | 227 .formatPercentNormalized(item.profileCode.normalizedExclusiveTicks); |
163 _updateLines(element.children[2].children, depth); | 228 _updateLines(element.children[2].children, depth); |
164 if (item.children.isNotEmpty) { | 229 if (item.children.isNotEmpty) { |
165 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; | 230 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; |
166 } else { | 231 } else { |
167 element.children[3].text = ''; | 232 element.children[3].text = ''; |
168 } | 233 } |
169 element.children[4].text = Utils.formatPercentNormalized(item.percentage); | 234 element.children[4].text = Utils.formatPercentNormalized(item.percentage); |
170 element.children[5] = new CodeRefElement(_isolate, item.profileCode.code, | 235 element.children[5] = new CodeRefElement(_isolate, item.profileCode.code, |
171 queue: _r.queue)..classes = ['name']; | 236 queue: _r.queue)..classes = ['name']; |
172 } | 237 } |
173 | 238 |
239 void _updateMemoryCodeRow(HtmlElement element, M.CodeCallTreeNode item, int de pth) { | |
Cutch
2017/03/21 20:27:10
long line..
bkonyi
2017/03/22 21:25:21
Done.
| |
240 element.children[0].text = Utils | |
241 .formatSize(item.inclusiveNativeAllocations); | |
242 element.children[0].title = 'memory allocated from resulting calls: ' + | |
243 '${item.inclusiveNativeAllocations}B'; | |
244 element.children[1].text = Utils | |
245 .formatSize(item.exclusiveNativeAllocations); | |
246 element.children[1].title = 'memory allocated during execution: ' + | |
247 '${item.exclusiveNativeAllocations}B'; | |
248 _updateLines(element.children[2].children, depth); | |
249 if (item.children.isNotEmpty) { | |
250 element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; | |
251 } else { | |
252 element.children[3].text = ''; | |
253 } | |
254 element.children[4].text = | |
255 Utils.formatPercentNormalized(item.percentage); | |
256 element.children[5] = new CodeRefElement(null, item.profileCode.code, | |
257 queue: _r.queue)..classes = ['name']; | |
258 } | |
259 | |
174 static _updateLines(List<Element> lines, int n) { | 260 static _updateLines(List<Element> lines, int n) { |
175 n = Math.max(0, n); | 261 n = Math.max(0, n); |
176 while (lines.length > n) { | 262 while (lines.length > n) { |
177 lines.removeLast(); | 263 lines.removeLast(); |
178 } | 264 } |
179 while (lines.length < n) { | 265 while (lines.length < n) { |
180 lines.add(new SpanElement()); | 266 lines.add(new SpanElement()); |
181 } | 267 } |
182 } | 268 } |
183 } | 269 } |
OLD | NEW |