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

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

Issue 2294073003: Converted Observatory class-view element (Closed)
Patch Set: Addessing optional missing fields Created 4 years, 3 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 library class_view_element; 5 library class_view_element;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'observatory_element.dart'; 8 import 'dart:html';
9 import 'sample_buffer_control.dart';
10 import 'stack_trace_tree_config.dart';
11 import 'cpu_profile/virtual_tree.dart';
12 import 'package:observatory/heap_snapshot.dart';
13 import 'package:observatory/elements.dart';
14 import 'package:observatory/models.dart' as M; 9 import 'package:observatory/models.dart' as M;
15 import 'package:observatory/service.dart'; 10 import 'package:observatory/src/elements/class_allocation_profile.dart';
16 import 'package:observatory/repositories.dart'; 11 import 'package:observatory/src/elements/class_instances.dart';
17 import 'package:polymer/polymer.dart'; 12 import 'package:observatory/src/elements/class_ref.dart';
18 13 import 'package:observatory/src/elements/curly_block.dart';
19 @CustomTag('class-view') 14 import 'package:observatory/src/elements/error_ref.dart';
20 class ClassViewElement extends ObservatoryElement { 15 import 'package:observatory/src/elements/eval_box.dart';
21 @published Class cls; 16 import 'package:observatory/src/elements/field_ref.dart';
22 @observable ServiceMap instances; 17 import 'package:observatory/src/elements/function_ref.dart';
23 @observable int reachableBytes; 18 import 'package:observatory/src/elements/helpers/any_ref.dart';
24 @observable int retainedBytes; 19 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
25 @observable ObservableList mostRetained; 20 import 'package:observatory/src/elements/helpers/tag.dart';
26 SampleBufferControlElement sampleBufferControlElement; 21 import 'package:observatory/src/elements/instance_ref.dart';
27 StackTraceTreeConfigElement stackTraceTreeConfigElement; 22 import 'package:observatory/src/elements/library_ref.dart';
28 CpuProfileVirtualTreeElement cpuProfileTreeElement; 23 import 'package:observatory/src/elements/nav/bar.dart';
29 ClassSampleProfileRepository repository = new ClassSampleProfileRepository(); 24 import 'package:observatory/src/elements/nav/class_menu.dart';
30 25 import 'package:observatory/src/elements/nav/isolate_menu.dart';
26 import 'package:observatory/src/elements/nav/menu.dart';
27 import 'package:observatory/src/elements/nav/notify.dart';
28 import 'package:observatory/src/elements/nav/refresh.dart';
29 import 'package:observatory/src/elements/nav/top_menu.dart';
30 import 'package:observatory/src/elements/nav/vm_menu.dart';
31 import 'package:observatory/src/elements/object_common.dart';
32 import 'package:observatory/src/elements/source_inset.dart';
33 import 'package:observatory/src/elements/source_link.dart';
34 import 'package:observatory/src/elements/view_footer.dart';
35
36 class ClassViewElement extends HtmlElement implements Renderable {
37 static const tag = const Tag<ClassViewElement>('class-view',
38 dependencies: const [
39 ClassInstancesElement.tag,
40 ClassRefElement.tag,
41 CurlyBlockElement.tag,
42 ErrorRefElement.tag,
43 EvalBoxElement.tag,
44 FieldRefElement.tag,
45 FunctionRefElement.tag,
46 InstanceRefElement.tag,
47 LibraryRefElement.tag,
48 NavBarElement.tag,
49 NavClassMenuElement.tag,
50 NavTopMenuElement.tag,
51 NavVMMenuElement.tag,
52 NavIsolateMenuElement.tag,
53 NavMenuElement.tag,
54 NavRefreshElement.tag,
55 NavNotifyElement.tag,
56 ObjectCommonElement.tag,
57 SourceInsetElement.tag,
58 SourceLinkElement.tag,
59 ViewFooterElement.tag
60 ]);
61
62 RenderingScheduler<ClassViewElement> _r;
63
64 Stream<RenderedEvent<ClassViewElement>> get onRendered => _r.onRendered;
65
66 M.VM _vm;
67 M.IsolateRef _isolate;
68 M.EventRepository _events;
69 M.NotificationRepository _notifications;
70 M.Class _cls;
71 M.ClassRepository _classes;
72 M.RetainedSizeRepository _retainedSizes;
73 M.ReachableSizeRepository _reachableSizes;
74 M.InboundReferencesRepository _references;
75 M.RetainingPathRepository _retainingPaths;
76 M.StronglyReachableInstancesRepository _stronglyReachableInstances;
77 M.TopRetainingInstancesRepository _topRetainedInstances;
78 M.FieldRepository _fields;
79 M.ScriptRepository _scripts;
80 M.InstanceRepository _instances;
81 M.EvalRepository _eval;
82 M.ClassSampleProfileRepository _profiles;
83 Iterable<M.Field> _classFields;
84
85
86 M.VMRef get vm => _vm;
87 M.IsolateRef get isolate => _isolate;
88 M.NotificationRepository get notifications => _notifications;
89 M.Class get cls => _cls;
90
91 factory ClassViewElement(M.VM vm, M.IsolateRef isolate, M.Class cls,
92 M.EventRepository events,
93 M.NotificationRepository notifications,
94 M.ClassRepository classes,
95 M.RetainedSizeRepository retainedSizes,
96 M.ReachableSizeRepository reachableSizes,
97 M.InboundReferencesRepository references,
98 M.RetainingPathRepository retainingPaths,
99 M.FieldRepository fields,
100 M.ScriptRepository scripts,
101 M.InstanceRepository instances,
102 M.EvalRepository eval,
103 M.StronglyReachableInstancesRepository stronglyReachable,
104 M.TopRetainingInstancesRepository topRetained,
105 M.ClassSampleProfileRepository profiles,
106 {RenderingQueue queue}) {
107 assert(vm != null);
108 assert(isolate != null);
109 assert(events != null);
110 assert(notifications != null);
111 assert(cls != null);
112 assert(classes != null);
113 assert(retainedSizes != null);
114 assert(reachableSizes != null);
115 assert(references != null);
116 assert(retainingPaths != null);
117 assert(fields != null);
118 assert(scripts != null);
119 assert(instances != null);
120 assert(eval != null);
121 assert(stronglyReachable != null);
122 assert(topRetained != null);
123 assert(profiles != null);
124 ClassViewElement e = document.createElement(tag.name);
125 e._r = new RenderingScheduler(e, queue: queue);
126 e._vm = vm;
127 e._isolate = isolate;
128 e._events = events;
129 e._notifications = notifications;
130 e._cls = cls;
131 e._classes = classes;
132 e._retainedSizes = retainedSizes;
133 e._reachableSizes = reachableSizes;
134 e._references = references;
135 e._retainingPaths = retainingPaths;
136 e._fields = fields;
137 e._scripts = scripts;
138 e._instances = instances;
139 e._eval = eval;
140 e._stronglyReachableInstances = stronglyReachable;
141 e._topRetainedInstances = topRetained;
142 e._profiles = profiles;
143 return e;
144 }
31 145
32 ClassViewElement.created() : super.created(); 146 ClassViewElement.created() : super.created();
33 147
34 Future<ServiceObject> evaluate(String expression) { 148 @override
35 return cls.evaluate(expression); 149 attached() {
36 }
37
38 Future<ServiceObject> reachable(var limit) {
39 return cls.isolate.getInstances(cls, limit).then((ServiceMap obj) {
40 instances = obj;
41 });
42 }
43
44 Future retainedToplist(var limit) async {
45 final raw = await cls.isolate.fetchHeapSnapshot(true).last;
46 final snapshot = new HeapSnapshot();
47 await snapshot.loadProgress(cls.isolate, raw).last;
48 final most = await Future.wait(snapshot.getMostRetained(cls.isolate,
49 classId: cls.vmCid ,
50 limit: 10));
51 mostRetained = new ObservableList.from(most);
52 }
53
54 // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
55 Future<ServiceObject> reachableSize(var dummy) {
56 return cls.isolate.getReachableSize(cls).then((Instance obj) {
57 reachableBytes = int.parse(obj.valueAsString);
58 });
59 }
60
61 Future<ServiceObject> retainedSize(var dummy) {
62 return cls.isolate.getRetainedSize(cls).then((Instance obj) {
63 retainedBytes = int.parse(obj.valueAsString);
64 });
65 }
66
67 void attached() {
68 super.attached(); 150 super.attached();
69 cls.fields.forEach((field) => field.reload()); 151 _r.enable();
70 } 152 _loadAdditionalData();
71 153 }
72 Future refresh() async { 154
73 instances = null; 155 @override
74 retainedBytes = null; 156 detached() {
75 mostRetained = null; 157 super.detached();
76 await cls.reload(); 158 _r.disable(notify: true);
77 await Future.wait(cls.fields.map((field) => field.reload())); 159 children = [];
78 } 160 }
79 161
80 M.SampleProfileTag _tag = M.SampleProfileTag.none; 162 ObjectCommonElement _common;
81 163 ClassInstancesElement _classInstances;
82 Future refreshAllocationProfile() async { 164 bool _loadProfile = false;
83 shadowRoot.querySelector('#sampleBufferControl').children = const []; 165
84 shadowRoot.querySelector('#stackTraceTreeConfig').children = const []; 166 void render() {
85 shadowRoot.querySelector('#cpuProfileTree').children = const []; 167 _common = _common ?? new ObjectCommonElement(_isolate, _cls, _retainedSizes,
86 final stream = repository.get(cls, _tag); 168 _reachableSizes, _references, _retainingPaths, _instances,
87 var progress = (await stream.first).progress; 169 queue: _r.queue);
88 shadowRoot.querySelector('#sampleBufferControl')..children = [ 170 _classInstances = _classInstances ?? new ClassInstancesElement(_isolate,
89 new SampleBufferControlElement(progress, stream, queue: app.queue, 171 _cls, _retainedSizes, _reachableSizes, _stronglyReachableInstances,
90 selectedTag: _tag) 172 _topRetainedInstances, _instances, queue: _r.queue);
91 ..onTagChange.listen((e) { 173 var header = '';
92 _tag = e.element.selectedTag; 174 if (_cls.isAbstract) {
93 refreshAllocationProfile(); 175 header += 'abstract ';
94 }) 176 }
177 if (_cls.isPatch) {
178 header += 'patch ';
179 }
180 if (_cls.mixin != null) {
rmacnak 2016/08/31 23:51:39 I'd remove this. If class's mixin isn't null, that
cbernaschina 2016/09/01 00:04:07 Done.
181 header += 'mixin ';
182 }
183 children = [
184 new NavBarElement(queue: _r.queue)
185 ..children = [
186 new NavTopMenuElement(queue: _r.queue),
187 new NavVMMenuElement(_vm, _events, queue: _r.queue),
188 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
189 new NavClassMenuElement(_isolate, _cls, queue: _r.queue),
190 new NavRefreshElement(label: 'Refresh Allocation Profile',
191 queue: _r.queue)
192 ..onRefresh.listen((e) {
193 e.element.disabled = true;
194 _loadProfile = true;
195 _r.dirty();
196 }),
197 new NavRefreshElement(queue: _r.queue)
198 ..onRefresh.listen((e) {
199 e.element.disabled = true;
200 _common = null;
201 _classInstances = null;
202 _fieldsExpanded = null;
203 _functionsExpanded = null;
204 _refresh();
205 }),
206 new NavNotifyElement(_notifications, queue: _r.queue)
207 ],
208 new DivElement()..classes = ['content-centered-big']
209 ..children = [
210 new HeadingElement.h2()..text = '$header class ${_cls.name}',
211 new HRElement(),
212 _common,
213 new BRElement(),
214 new DivElement()..classes = ['memberList']
215 ..children = _createMembers(),
216 new DivElement()
217 ..children = _cls.error == null
218 ? const []
219 : [
220 new HRElement(),
221 new ErrorRefElement(_cls.error, queue: _r.queue)
222 ],
223 new HRElement(),
224 new EvalBoxElement(_isolate, _cls, _instances, _eval,
225 queue: _r.queue),
226 new HRElement(),
227 new HeadingElement.h2()..text = 'Fields & Functions',
228 new DivElement()..classes = ['memberList']
229 ..children = _createElements(),
230 new HRElement(),
231 new HeadingElement.h2()..text = 'Instances',
232 new DivElement()
233 ..children = _cls.hasAllocations
234 ? [_classInstances]
235 : const [],
236 new HRElement(),
237 new HeadingElement.h2()..text = 'Allocations',
238 new DivElement()..classes = ['memberList']
239 ..children = [
240 new DivElement()..classes = ['memberName']
241 ..text = 'Tracing allocations?» ',
242 new DivElement()..classes = ['memberValue']
243 ..children = _cls.traceAllocations
244 ? [
245 new SpanElement()..text = 'Yes ',
246 new ButtonElement()..text = 'disable'
247 ..onClick.listen((e) async {
248 e.target.disabled = true;
249 await _profiles.disable(_isolate, _cls);
250 _loadProfile = true;
251 _refresh();
252 })
253 ]
254 : [
255 new SpanElement()..text = 'No ',
256 new ButtonElement()..text = 'enable'
257 ..onClick.listen((e) async {
258 e.target.disabled = true;
259 await _profiles.enable(_isolate, _cls);
260 _refresh();
261 })
262 ]
263 ],
264 new DivElement()
265 ..children = _loadProfile
266 ? [new ClassAllocationProfileElement(_isolate, _cls, _profiles,
267 queue: _r.queue)]
268 : const [],
269 new DivElement()
270 ..children = _cls.location != null
271 ? [new HRElement(),
272 new SourceInsetElement(_isolate, _cls.location, _scripts,
273 _instances, _events, queue: _r.queue)]
274 : const [],
275 new HRElement(),
276 new ViewFooterElement(queue: _r.queue)
277 ]
95 ]; 278 ];
96 if (M.isSampleProcessRunning(progress.status)) { 279 }
97 progress = (await stream.last).progress; 280
98 } 281 bool _fieldsExpanded;
99 if (progress.status == M.SampleProfileLoadingStatus.loaded) { 282 bool _functionsExpanded;
100 shadowRoot.querySelector('#stackTraceTreeConfig')..children = [ 283
101 new StackTraceTreeConfigElement( 284 List<Element> _createMembers() {
102 queue: app.queue) 285 final members = <Element>[];
103 ..showFilter = false 286 if (_cls.library != null) {
104 ..onModeChange.listen((e) { 287 members.add(
105 cpuProfileTreeElement.mode = e.element.mode; 288 new DivElement()..classes = ['memberItem']
106 }) 289 ..children = [
107 ..onDirectionChange.listen((e) { 290 new DivElement()..classes = ['memberName']
108 cpuProfileTreeElement.direction = e.element.direction; 291 ..text = 'library',
109 }) 292 new DivElement()..classes = ['memberValue']
110 ]; 293 ..children = [
111 shadowRoot.querySelector('#cpuProfileTree')..children = [ 294 new LibraryRefElement(_isolate, _cls.library, queue: _r.queue)
112 cpuProfileTreeElement = new CpuProfileVirtualTreeElement(cls.isolate, 295 ]
113 progress.profile, queue: app.queue) 296 ]
114 ]; 297 );
115 } 298 }
116 } 299 if (_cls.location != null) {
117 300 members.add(
118 Future toggleAllocationTrace() { 301 new DivElement()..classes = ['memberItem']
119 if (cls == null) { 302 ..children = [
120 return new Future(refresh); 303 new DivElement()..classes = ['memberName']
121 } 304 ..text = 'script',
122 if (cls.traceAllocations) { 305 new DivElement()..classes = ['memberValue']
123 refreshAllocationProfile(); 306 ..children = [
124 } 307 new SourceLinkElement(_isolate, _cls.location, _scripts,
125 return cls.setTraceAllocations(!cls.traceAllocations).whenComplete(refresh); 308 queue: _r.queue)
309 ]
310 ]
311 );
312 }
313 if (_cls.superclass != null) {
314 members.add(
315 new DivElement()..classes = ['memberItem']
316 ..children = [
317 new DivElement()..classes = ['memberName']
318 ..text = 'superclass',
319 new DivElement()..classes = ['memberValue']
320 ..children = [
321 new ClassRefElement(_isolate, _cls.superclass, queue: _r.queue)
322 ]
323 ]
324 );
325 }
326 if (_cls.superType != null) {
327 members.add(
328 new DivElement()..classes = ['memberItem']
329 ..children = [
330 new DivElement()..classes = ['memberName']
331 ..text = 'supertype',
332 new DivElement()..classes = ['memberValue']
333 ..children = [
334 new InstanceRefElement(_isolate, _cls.superType, _instances,
335 queue: _r.queue)
336 ]
337 ]
338 );
339 }
340 if (cls.mixin != null) {
341 members.add(
342 new DivElement()..classes = ['memberItem']
343 ..children = [
344 new DivElement()..classes = ['memberName']
345 ..text = 'mixin',
346 new DivElement()..classes = ['memberValue']
347 ..children = [
348 new InstanceRefElement(_isolate, _cls.mixin, _instances,
349 queue: _r.queue)
350 ]
351 ]
352 );
353 }
354 if (_cls.subclasses.length > 0) {
355 members.add(
356 new DivElement()..classes = ['memberItem']
357 ..children = [
358 new DivElement()..classes = ['memberName']
359 ..text = 'extended by',
360 new DivElement()..classes = ['memberValue']
361 ..children = (_cls.subclasses.expand((subcls) => [
362 new ClassRefElement(_isolate, subcls, queue: _r.queue),
363 new SpanElement()..text = ', '
364 ]).toList()..removeLast())
365 ]
366 );
367 }
368
369 members.add(new BRElement());
370
371 if (_cls.interfaces.length > 0) {
372 members.add(
rmacnak 2016/08/31 23:51:39 This pattern seems to get repeated a lot in many o
cbernaschina 2016/09/01 00:04:07 Acknowledged.
373 new DivElement()..classes = ['memberItem']
374 ..children = [
375 new DivElement()..classes = ['memberName']
376 ..text = 'implements',
377 new DivElement()..classes = ['memberValue']
378 ..children = (_cls.interfaces.expand((interf) => [
379 new InstanceRefElement(_isolate, interf, _instances,
380 queue: _r.queue),
381 new SpanElement()..text = ', '
382 ]).toList()..removeLast())
383 ]
384 );
385 }
386 if (_cls.name != _cls.vmName) {
387 members.add(
388 new DivElement()..classes = ['memberItem']
389 ..children = [
390 new DivElement()..classes = ['memberName']
391 ..text = 'vm name',
392 new DivElement()..classes = ['memberValue']
393 ..text = '${_cls.vmName}'
394 ]
395 );
396 }
397 return members;
398 }
399
400 List<Element> _createElements() {
401 final members = <Element>[];
402 if (_classFields != null && _classFields.isNotEmpty) {
403 final fields = _classFields.toList();
404 _fieldsExpanded = _fieldsExpanded ?? (fields.length <= 8);
405 members.add(
406 new DivElement()..classes = ['memberItem']
407 ..children = [
408 new DivElement()..classes = ['memberName']
409 ..text = 'fields ${fields.length}',
410 new DivElement()..classes = ['memberValue']
411 ..children =[
412 new CurlyBlockElement(expanded: _fieldsExpanded)
413 ..onToggle.listen((e) => _fieldsExpanded = e.control.expanded)
414 ..children = [
415 new DivElement()..classes = ['memberList']
416 ..children = (fields.map((f) =>
417 new DivElement()..classes = ['memberItem']
418 ..children = [
419 new DivElement()..classes = ['memberName']
420 ..children =[
421 new FieldRefElement(_isolate, f, _instances,
422 queue: _r.queue)
423 ],
424 new DivElement()..classes = ['memberValue']
425 ..children = [
426 anyRef(_isolate, f.staticValue, _instances,
427 queue: _r.queue)
428 ]
429 ]
430 ).toList())
431 ]
432 ]
433 ]
434 );
435 }
436
437 if (_cls.functions.isNotEmpty) {
438 final functions = _cls.functions.toList();
439 _functionsExpanded = _functionsExpanded ?? (functions.length <= 8);
440 members.add(
441 new DivElement()..classes = ['memberItem']
442 ..children = [
443 new DivElement()..classes = ['memberName']
444 ..text = 'functions (${functions.length})',
445 new DivElement()..classes = ['memberValue']
446 ..children =[
447 new CurlyBlockElement(expanded: _functionsExpanded)
448 ..onToggle.listen((e) =>
449 _functionsExpanded = e.control.expanded)
450 ..children = (functions.map((f) =>
451 new DivElement()..classes = ['indent']
452 ..children = [
453 new FunctionRefElement(_isolate, f, queue: _r.queue)
454 ]
455 ).toList())
456 ]
457 ]
458 );
459 }
460 return members;
461 }
462
463 Future _refresh() async {
464 _cls = await _classes.get(_isolate, _cls.id);
465 await _loadAdditionalData();
466 _r.dirty();
467 }
468
469 Future _loadAdditionalData() async {
470 _classFields = await Future.wait(_cls.fields.map((f)
471 => _fields.get(_isolate, f.id)));
472 _r.dirty();
126 } 473 }
127 } 474 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698