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

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

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

Powered by Google App Engine
This is Rietveld 408576698