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

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

Issue 2294073003: Converted Observatory class-view element (Closed)
Patch Set: Addressed comments 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 children = [
181 new NavBarElement(queue: _r.queue)
182 ..children = [
183 new NavTopMenuElement(queue: _r.queue),
184 new NavVMMenuElement(_vm, _events, queue: _r.queue),
185 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
186 new NavClassMenuElement(_isolate, _cls, queue: _r.queue),
187 new NavRefreshElement(label: 'Refresh Allocation Profile',
188 queue: _r.queue)
189 ..onRefresh.listen((e) {
190 e.element.disabled = true;
191 _loadProfile = true;
192 _r.dirty();
193 }),
194 new NavRefreshElement(queue: _r.queue)
195 ..onRefresh.listen((e) {
196 e.element.disabled = true;
197 _common = null;
198 _classInstances = null;
199 _fieldsExpanded = null;
200 _functionsExpanded = null;
201 _refresh();
202 }),
203 new NavNotifyElement(_notifications, queue: _r.queue)
204 ],
205 new DivElement()..classes = ['content-centered-big']
206 ..children = [
207 new HeadingElement.h2()..text = '$header class ${_cls.name}',
208 new HRElement(),
209 _common,
210 new BRElement(),
211 new DivElement()..classes = ['memberList']
212 ..children = _createMembers(),
213 new DivElement()
214 ..children = _cls.error == null
215 ? const []
216 : [
217 new HRElement(),
218 new ErrorRefElement(_cls.error, queue: _r.queue)
219 ],
220 new HRElement(),
221 new EvalBoxElement(_isolate, _cls, _instances, _eval,
222 queue: _r.queue),
223 new HRElement(),
224 new HeadingElement.h2()..text = 'Fields & Functions',
225 new DivElement()..classes = ['memberList']
226 ..children = _createElements(),
227 new HRElement(),
228 new HeadingElement.h2()..text = 'Instances',
229 new DivElement()
230 ..children = _cls.hasAllocations
231 ? [_classInstances]
232 : const [],
233 new HRElement(),
234 new HeadingElement.h2()..text = 'Allocations',
235 new DivElement()..classes = ['memberList']
236 ..children = [
237 new DivElement()..classes = ['memberName']
238 ..text = 'Tracing allocations?» ',
239 new DivElement()..classes = ['memberValue']
240 ..children = _cls.traceAllocations
241 ? [
242 new SpanElement()..text = 'Yes ',
243 new ButtonElement()..text = 'disable'
244 ..onClick.listen((e) async {
245 e.target.disabled = true;
246 await _profiles.disable(_isolate, _cls);
247 _loadProfile = true;
248 _refresh();
249 })
250 ]
251 : [
252 new SpanElement()..text = 'No ',
253 new ButtonElement()..text = 'enable'
254 ..onClick.listen((e) async {
255 e.target.disabled = true;
256 await _profiles.enable(_isolate, _cls);
257 _refresh();
258 })
259 ]
260 ],
261 new DivElement()
262 ..children = _loadProfile
263 ? [new ClassAllocationProfileElement(_isolate, _cls, _profiles,
264 queue: _r.queue)]
265 : const [],
266 new DivElement()
267 ..children = _cls.location != null
268 ? [new HRElement(),
269 new SourceInsetElement(_isolate, _cls.location, _scripts,
270 _instances, _events, queue: _r.queue)]
271 : const [],
272 new HRElement(),
273 new ViewFooterElement(queue: _r.queue)
274 ]
95 ]; 275 ];
96 if (M.isSampleProcessRunning(progress.status)) { 276 }
97 progress = (await stream.last).progress; 277
98 } 278 bool _fieldsExpanded;
99 if (progress.status == M.SampleProfileLoadingStatus.loaded) { 279 bool _functionsExpanded;
100 shadowRoot.querySelector('#stackTraceTreeConfig')..children = [ 280
101 new StackTraceTreeConfigElement( 281 List<Element> _createMembers() {
102 queue: app.queue) 282 final members = <Element>[];
103 ..showFilter = false 283 if (_cls.library != null) {
104 ..onModeChange.listen((e) { 284 members.add(
105 cpuProfileTreeElement.mode = e.element.mode; 285 new DivElement()..classes = ['memberItem']
106 }) 286 ..children = [
107 ..onDirectionChange.listen((e) { 287 new DivElement()..classes = ['memberName']
108 cpuProfileTreeElement.direction = e.element.direction; 288 ..text = 'library',
109 }) 289 new DivElement()..classes = ['memberValue']
110 ]; 290 ..children = [
111 shadowRoot.querySelector('#cpuProfileTree')..children = [ 291 new LibraryRefElement(_isolate, _cls.library, queue: _r.queue)
112 cpuProfileTreeElement = new CpuProfileVirtualTreeElement(cls.isolate, 292 ]
113 progress.profile, queue: app.queue) 293 ]
114 ]; 294 );
115 } 295 }
116 } 296 if (_cls.location != null) {
117 297 members.add(
118 Future toggleAllocationTrace() { 298 new DivElement()..classes = ['memberItem']
119 if (cls == null) { 299 ..children = [
120 return new Future(refresh); 300 new DivElement()..classes = ['memberName']
121 } 301 ..text = 'script',
122 if (cls.traceAllocations) { 302 new DivElement()..classes = ['memberValue']
123 refreshAllocationProfile(); 303 ..children = [
124 } 304 new SourceLinkElement(_isolate, _cls.location, _scripts,
125 return cls.setTraceAllocations(!cls.traceAllocations).whenComplete(refresh); 305 queue: _r.queue)
306 ]
307 ]
308 );
309 }
310 if (_cls.superclass != null) {
311 members.add(
312 new DivElement()..classes = ['memberItem']
313 ..children = [
314 new DivElement()..classes = ['memberName']
315 ..text = 'superclass',
316 new DivElement()..classes = ['memberValue']
317 ..children = [
318 new ClassRefElement(_isolate, _cls.superclass, queue: _r.queue)
319 ]
320 ]
321 );
322 }
323 if (_cls.superType != null) {
324 members.add(
325 new DivElement()..classes = ['memberItem']
326 ..children = [
327 new DivElement()..classes = ['memberName']
328 ..text = 'supertype',
329 new DivElement()..classes = ['memberValue']
330 ..children = [
331 new InstanceRefElement(_isolate, _cls.superType, _instances,
332 queue: _r.queue)
333 ]
334 ]
335 );
336 }
337 if (cls.mixin != null) {
338 members.add(
339 new DivElement()..classes = ['memberItem']
340 ..children = [
341 new DivElement()..classes = ['memberName']
342 ..text = 'mixin',
343 new DivElement()..classes = ['memberValue']
344 ..children = [
345 new InstanceRefElement(_isolate, _cls.mixin, _instances,
346 queue: _r.queue)
347 ]
348 ]
349 );
350 }
351 if (_cls.subclasses.length > 0) {
352 members.add(
353 new DivElement()..classes = ['memberItem']
354 ..children = [
355 new DivElement()..classes = ['memberName']
356 ..text = 'extended by',
357 new DivElement()..classes = ['memberValue']
358 ..children = (_cls.subclasses.expand((subcls) => [
359 new ClassRefElement(_isolate, subcls, queue: _r.queue),
360 new SpanElement()..text = ', '
361 ]).toList()..removeLast())
362 ]
363 );
364 }
365
366 members.add(new BRElement());
367
368 if (_cls.interfaces.length > 0) {
369 members.add(
370 new DivElement()..classes = ['memberItem']
371 ..children = [
372 new DivElement()..classes = ['memberName']
373 ..text = 'implements',
374 new DivElement()..classes = ['memberValue']
375 ..children = (_cls.interfaces.expand((interf) => [
376 new InstanceRefElement(_isolate, interf, _instances,
377 queue: _r.queue),
378 new SpanElement()..text = ', '
379 ]).toList()..removeLast())
380 ]
381 );
382 }
383 if (_cls.name != _cls.vmName) {
384 members.add(
385 new DivElement()..classes = ['memberItem']
386 ..children = [
387 new DivElement()..classes = ['memberName']
388 ..text = 'vm name',
389 new DivElement()..classes = ['memberValue']
390 ..text = '${_cls.vmName}'
391 ]
392 );
393 }
394 return members;
395 }
396
397 List<Element> _createElements() {
398 final members = <Element>[];
399 if (_classFields != null && _classFields.isNotEmpty) {
400 final fields = _classFields.toList();
401 _fieldsExpanded = _fieldsExpanded ?? (fields.length <= 8);
402 members.add(
403 new DivElement()..classes = ['memberItem']
404 ..children = [
405 new DivElement()..classes = ['memberName']
406 ..text = 'fields ${fields.length}',
407 new DivElement()..classes = ['memberValue']
408 ..children =[
409 new CurlyBlockElement(expanded: _fieldsExpanded)
410 ..onToggle.listen((e) => _fieldsExpanded = e.control.expanded)
411 ..children = [
412 new DivElement()..classes = ['memberList']
413 ..children = (fields.map((f) =>
414 new DivElement()..classes = ['memberItem']
415 ..children = [
416 new DivElement()..classes = ['memberName']
417 ..children =[
418 new FieldRefElement(_isolate, f, _instances,
419 queue: _r.queue)
420 ],
421 new DivElement()..classes = ['memberValue']
422 ..children = [
423 anyRef(_isolate, f.staticValue, _instances,
424 queue: _r.queue)
425 ]
426 ]
427 ).toList())
428 ]
429 ]
430 ]
431 );
432 }
433
434 if (_cls.functions.isNotEmpty) {
435 final functions = _cls.functions.toList();
436 _functionsExpanded = _functionsExpanded ?? (functions.length <= 8);
437 members.add(
438 new DivElement()..classes = ['memberItem']
439 ..children = [
440 new DivElement()..classes = ['memberName']
441 ..text = 'functions (${functions.length})',
442 new DivElement()..classes = ['memberValue']
443 ..children =[
444 new CurlyBlockElement(expanded: _functionsExpanded)
445 ..onToggle.listen((e) =>
446 _functionsExpanded = e.control.expanded)
447 ..children = (functions.map((f) =>
448 new DivElement()..classes = ['indent']
449 ..children = [
450 new FunctionRefElement(_isolate, f, queue: _r.queue)
451 ]
452 ).toList())
453 ]
454 ]
455 );
456 }
457 return members;
458 }
459
460 Future _refresh() async {
461 _cls = await _classes.get(_isolate, _cls.id);
462 await _loadAdditionalData();
463 _r.dirty();
464 }
465
466 Future _loadAdditionalData() async {
467 _classFields = await Future.wait(_cls.fields.map((f)
468 => _fields.get(_isolate, f.id)));
469 _r.dirty();
126 } 470 }
127 } 471 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/class_instances.dart ('k') | runtime/observatory/lib/src/elements/class_view.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698