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

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

Issue 2480293003: Observatory: Add view of dominator tree with siblings merged by class. (Closed)
Patch Set: . Created 4 years, 1 month 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) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 5 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
6 // for details. All rights reserved. Use of this source code is governed by a 6 // for details. All rights reserved. Use of this source code is governed by a
7 // BSD-style license that can be found in the LICENSE file. 7 // BSD-style license that can be found in the LICENSE file.
8 8
9 import 'dart:async'; 9 import 'dart:async';
10 import 'dart:html'; 10 import 'dart:html';
11 import 'dart:math' as Math; 11 import 'dart:math' as Math;
12 import 'package:observatory/models.dart' as M; 12 import 'package:observatory/models.dart' as M;
13 import 'package:observatory/src/elements/class_ref.dart'; 13 import 'package:observatory/src/elements/class_ref.dart';
14 import 'package:observatory/src/elements/containers/virtual_tree.dart'; 14 import 'package:observatory/src/elements/containers/virtual_tree.dart';
15 import 'package:observatory/src/elements/helpers/any_ref.dart'; 15 import 'package:observatory/src/elements/helpers/any_ref.dart';
16 import 'package:observatory/src/elements/helpers/nav_bar.dart'; 16 import 'package:observatory/src/elements/helpers/nav_bar.dart';
17 import 'package:observatory/src/elements/helpers/nav_menu.dart'; 17 import 'package:observatory/src/elements/helpers/nav_menu.dart';
18 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; 18 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
19 import 'package:observatory/src/elements/helpers/tag.dart'; 19 import 'package:observatory/src/elements/helpers/tag.dart';
20 import 'package:observatory/src/elements/nav/isolate_menu.dart'; 20 import 'package:observatory/src/elements/nav/isolate_menu.dart';
21 import 'package:observatory/src/elements/nav/notify.dart'; 21 import 'package:observatory/src/elements/nav/notify.dart';
22 import 'package:observatory/src/elements/nav/refresh.dart'; 22 import 'package:observatory/src/elements/nav/refresh.dart';
23 import 'package:observatory/src/elements/nav/top_menu.dart'; 23 import 'package:observatory/src/elements/nav/top_menu.dart';
24 import 'package:observatory/src/elements/nav/vm_menu.dart'; 24 import 'package:observatory/src/elements/nav/vm_menu.dart';
25 import 'package:observatory/utils.dart'; 25 import 'package:observatory/utils.dart';
26 26
27 enum HeapSnapshotTreeMode { dominatorTree, groupByClass } 27 enum HeapSnapshotTreeMode { dominatorTree, mergedDominatorTree, groupByClass }
28 28
29 class HeapSnapshotElement extends HtmlElement implements Renderable { 29 class HeapSnapshotElement extends HtmlElement implements Renderable {
30 static const tag = 30 static const tag =
31 const Tag<HeapSnapshotElement>('heap-snapshot', dependencies: const [ 31 const Tag<HeapSnapshotElement>('heap-snapshot', dependencies: const [
32 ClassRefElement.tag, 32 ClassRefElement.tag,
33 NavTopMenuElement.tag, 33 NavTopMenuElement.tag,
34 NavVMMenuElement.tag, 34 NavVMMenuElement.tag,
35 NavIsolateMenuElement.tag, 35 NavIsolateMenuElement.tag,
36 NavRefreshElement.tag, 36 NavRefreshElement.tag,
37 NavNotifyElement.tag, 37 NavNotifyElement.tag,
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 'plus its own shallow size, and is the amount of memory ' 259 'plus its own shallow size, and is the amount of memory '
260 'that would be freed if the object became garbage.'; 260 'that would be freed if the object became garbage.';
261 report.addAll([ 261 report.addAll([
262 new DivElement() 262 new DivElement()
263 ..classes = ['content-centered-big', 'explanation'] 263 ..classes = ['content-centered-big', 'explanation']
264 ..text = text 264 ..text = text
265 ..title = text, 265 ..title = text,
266 _tree 266 _tree
267 ]); 267 ]);
268 break; 268 break;
269 case HeapSnapshotTreeMode.mergedDominatorTree:
270 _tree = new VirtualTreeElement(
271 _createMergedDominator, _updateMergedDominator,
272 _getChildrenMergedDominator,
273 items: _getChildrenMergedDominator(_snapshot.mergedDominatorTree),
274 queue: _r.queue);
275 _tree.expand(_snapshot.mergedDominatorTree);
276 final text = 'A heap dominator tree, where siblings with the same class'
277 ' have been merged into a single node.';
278 report.addAll([
279 new DivElement()
280 ..classes = ['content-centered-big', 'explanation']
281 ..text = text
282 ..title = text,
283 _tree
284 ]);
285 break;
269 case HeapSnapshotTreeMode.groupByClass: 286 case HeapSnapshotTreeMode.groupByClass:
270 final items = _snapshot.classReferences.toList(); 287 final items = _snapshot.classReferences.toList();
271 items.sort((a, b) => b.shallowSize - a.shallowSize); 288 items.sort((a, b) => b.shallowSize - a.shallowSize);
272 _tree = new VirtualTreeElement( 289 _tree = new VirtualTreeElement(
273 _createGroup, _updateGroup, _getChildrenGroup, 290 _createGroup, _updateGroup, _getChildrenGroup,
274 items: items, queue: _r.queue); 291 items: items, queue: _r.queue);
275 _tree.expand(_snapshot.dominatorTree); 292 _tree.expand(_snapshot.dominatorTree);
276 report.add(_tree); 293 report.add(_tree);
277 break; 294 break;
278 default: 295 default:
(...skipping 13 matching lines...) Expand all
292 new ButtonElement() 309 new ButtonElement()
293 ..classes = ['expander'] 310 ..classes = ['expander']
294 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), 311 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
295 new SpanElement() 312 new SpanElement()
296 ..classes = ['percentage'] 313 ..classes = ['percentage']
297 ..title = 'percentage of heap being retained', 314 ..title = 'percentage of heap being retained',
298 new SpanElement()..classes = ['name'] 315 new SpanElement()..classes = ['name']
299 ]; 316 ];
300 } 317 }
301 318
319 static Element _createMergedDominator(toggle) {
320 return new DivElement()
321 ..classes = ['tree-item']
322 ..children = [
323 new SpanElement()
324 ..classes = ['size']
325 ..title = 'retained size',
326 new SpanElement()..classes = ['lines'],
327 new ButtonElement()
328 ..classes = ['expander']
329 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
330 new SpanElement()
331 ..classes = ['percentage']
332 ..title = 'percentage of heap being retained',
333 new SpanElement()..classes = ['name']
334 ];
335 }
336
302 static Element _createGroup(toggle) { 337 static Element _createGroup(toggle) {
303 return new DivElement() 338 return new DivElement()
304 ..classes = ['tree-item'] 339 ..classes = ['tree-item']
305 ..children = [ 340 ..children = [
306 new SpanElement() 341 new SpanElement()
307 ..classes = ['size'] 342 ..classes = ['size']
308 ..title = 'shallow size', 343 ..title = 'shallow size',
309 new SpanElement()..classes = ['lines'], 344 new SpanElement()..classes = ['lines'],
310 new ButtonElement() 345 new ButtonElement()
311 ..classes = ['expander'] 346 ..classes = ['expander']
312 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), 347 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
313 new SpanElement() 348 new SpanElement()
314 ..classes = ['count'] 349 ..classes = ['count']
315 ..title = 'shallow size', 350 ..title = 'shallow size',
316 new SpanElement()..classes = ['name'] 351 new SpanElement()..classes = ['name']
317 ]; 352 ];
318 } 353 }
319 354
320 static const int kMaxChildren = 100; 355 static const int kMaxChildren = 100;
321 static const int kMinRetainedSize = 4096; 356 static const int kMinRetainedSize = 4096;
322 357
323 static _getChildrenDominator(M.HeapSnapshotDominatorNode node) { 358 static _getChildrenDominator(M.HeapSnapshotDominatorNode node) {
324 final list = node.children.toList(); 359 final list = node.children.toList();
325 list.sort((a, b) => b.retainedSize - a.retainedSize); 360 list.sort((a, b) => b.retainedSize - a.retainedSize);
326 return list 361 return list
327 .where((child) => child.retainedSize >= kMinRetainedSize) 362 .where((child) => child.retainedSize >= kMinRetainedSize)
328 .take(kMaxChildren); 363 .take(kMaxChildren);
329 } 364 }
365 static _getChildrenMergedDominator(M.HeapSnapshotMergedDominatorNode node) {
366 final list = node.children.toList();
367 list.sort((a, b) => b.retainedSize - a.retainedSize);
368 return list
369 .where((child) => child.retainedSize >= kMinRetainedSize)
370 .take(kMaxChildren);
371 }
330 372
331 static _getChildrenGroup(item) { 373 static _getChildrenGroup(item) {
332 if (item is M.HeapSnapshotClassReferences) { 374 if (item is M.HeapSnapshotClassReferences) {
333 if (item.inbounds.isNotEmpty || item.outbounds.isNotEmpty) { 375 if (item.inbounds.isNotEmpty || item.outbounds.isNotEmpty) {
334 return [item.inbounds, item.outbounds]; 376 return [item.inbounds, item.outbounds];
335 } 377 }
336 } else if (item is Iterable) { 378 } else if (item is Iterable) {
337 return item.toList()..sort((a, b) => b.shallowSize - a.shallowSize); 379 return item.toList()..sort((a, b) => b.shallowSize - a.shallowSize);
338 } 380 }
339 return const []; 381 return const [];
(...skipping 14 matching lines...) Expand all
354 ..classes = ['name'] 396 ..classes = ['name']
355 ..text = 'Loading...'; 397 ..text = 'Loading...';
356 element.children[4] = wrapper; 398 element.children[4] = wrapper;
357 node.object.then((object) { 399 node.object.then((object) {
358 wrapper 400 wrapper
359 ..text = '' 401 ..text = ''
360 ..children = [anyRef(_isolate, object, _instances, queue: _r.queue)]; 402 ..children = [anyRef(_isolate, object, _instances, queue: _r.queue)];
361 }); 403 });
362 } 404 }
363 405
406 void _updateMergedDominator(
407 HtmlElement element, M.HeapSnapshotMergedDominatorNode node, int depth) {
408 element.children[0].text = Utils.formatSize(node.retainedSize);
409 _updateLines(element.children[1].children, depth);
410 if (_getChildrenMergedDominator(node).isNotEmpty) {
411 element.children[2].text = _tree.isExpanded(node) ? '▼' : '►';
412 } else {
413 element.children[2].text = '';
414 }
415 element.children[3].text =
416 Utils.formatPercentNormalized(node.retainedSize * 1.0 / _snapshot.size);
417 final wrapper = new SpanElement()
418 ..classes = ['name']
419 ..text = 'Loading...';
420 element.children[4] = wrapper;
421 node.klass.then((klass) {
422 wrapper
423 ..text = ''
424 ..children = [
425 new SpanElement()..text = '${node.instanceCount} instances of ',
426 anyRef(_isolate, klass, _instances, queue: _r.queue)
427 ];
428 });
429 }
430
364 void _updateGroup(HtmlElement element, item, int depth) { 431 void _updateGroup(HtmlElement element, item, int depth) {
365 _updateLines(element.children[1].children, depth); 432 _updateLines(element.children[1].children, depth);
366 if (item is M.HeapSnapshotClassReferences) { 433 if (item is M.HeapSnapshotClassReferences) {
367 element.children[0].text = Utils.formatSize(item.shallowSize); 434 element.children[0].text = Utils.formatSize(item.shallowSize);
368 element.children[2].text = _tree.isExpanded(item) ? '▼' : '►'; 435 element.children[2].text = _tree.isExpanded(item) ? '▼' : '►';
369 element.children[3].text = '${item.instances} instances of '; 436 element.children[3].text = '${item.instances} instances of ';
370 element.children[4] = new ClassRefElement(_isolate, item.clazz, 437 element.children[4] = new ClassRefElement(_isolate, item.clazz,
371 queue: _r.queue)..classes = ['name']; 438 queue: _r.queue)..classes = ['name'];
372 } else if (item is Iterable) { 439 } else if (item is Iterable) {
373 element.children[0].text = ''; 440 element.children[0].text = '';
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 } 484 }
418 while (lines.length < n) { 485 while (lines.length < n) {
419 lines.add(new SpanElement()); 486 lines.add(new SpanElement());
420 } 487 }
421 } 488 }
422 489
423 static String modeToString(HeapSnapshotTreeMode mode) { 490 static String modeToString(HeapSnapshotTreeMode mode) {
424 switch (mode) { 491 switch (mode) {
425 case HeapSnapshotTreeMode.dominatorTree: 492 case HeapSnapshotTreeMode.dominatorTree:
426 return 'Dominator tree'; 493 return 'Dominator tree';
494 case HeapSnapshotTreeMode.mergedDominatorTree:
495 return 'Dominator tree (merged siblings by class)';
427 case HeapSnapshotTreeMode.groupByClass: 496 case HeapSnapshotTreeMode.groupByClass:
428 return 'Group by class'; 497 return 'Group by class';
429 } 498 }
430 throw new Exception('Unknown ProfileTreeMode'); 499 throw new Exception('Unknown ProfileTreeMode');
431 } 500 }
432 501
433 List<Element> _createModeSelect() { 502 List<Element> _createModeSelect() {
434 var s; 503 var s;
435 return [ 504 return [
436 s = new SelectElement() 505 s = new SelectElement()
437 ..classes = ['analysis-select'] 506 ..classes = ['analysis-select']
438 ..value = modeToString(_mode) 507 ..value = modeToString(_mode)
439 ..children = HeapSnapshotTreeMode.values.map((mode) { 508 ..children = HeapSnapshotTreeMode.values.map((mode) {
440 return new OptionElement( 509 return new OptionElement(
441 value: modeToString(mode), 510 value: modeToString(mode),
442 selected: _mode == mode)..text = modeToString(mode); 511 selected: _mode == mode)..text = modeToString(mode);
443 }).toList(growable: false) 512 }).toList(growable: false)
444 ..onChange.listen((_) { 513 ..onChange.listen((_) {
445 _mode = HeapSnapshotTreeMode.values[s.selectedIndex]; 514 _mode = HeapSnapshotTreeMode.values[s.selectedIndex];
446 _r.dirty(); 515 _r.dirty();
447 }) 516 })
448 ]; 517 ];
449 } 518 }
450 } 519 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698