OLD | NEW |
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/helpers/uris.dart'; | 20 import 'package:observatory/src/elements/helpers/uris.dart'; |
21 import 'package:observatory/src/elements/nav/isolate_menu.dart'; | 21 import 'package:observatory/src/elements/nav/isolate_menu.dart'; |
22 import 'package:observatory/src/elements/nav/notify.dart'; | 22 import 'package:observatory/src/elements/nav/notify.dart'; |
23 import 'package:observatory/src/elements/nav/refresh.dart'; | 23 import 'package:observatory/src/elements/nav/refresh.dart'; |
24 import 'package:observatory/src/elements/nav/top_menu.dart'; | 24 import 'package:observatory/src/elements/nav/top_menu.dart'; |
25 import 'package:observatory/src/elements/nav/vm_menu.dart'; | 25 import 'package:observatory/src/elements/nav/vm_menu.dart'; |
26 import 'package:observatory/utils.dart'; | 26 import 'package:observatory/utils.dart'; |
27 | 27 |
28 enum HeapSnapshotTreeMode { dominatorTree, mergedDominatorTree, groupByClass } | 28 enum HeapSnapshotTreeMode { |
| 29 dominatorTree, |
| 30 mergedDominatorTree, |
| 31 ownershipTable, |
| 32 groupByClass |
| 33 } |
29 | 34 |
30 class HeapSnapshotElement extends HtmlElement implements Renderable { | 35 class HeapSnapshotElement extends HtmlElement implements Renderable { |
31 static const tag = | 36 static const tag = |
32 const Tag<HeapSnapshotElement>('heap-snapshot', dependencies: const [ | 37 const Tag<HeapSnapshotElement>('heap-snapshot', dependencies: const [ |
33 ClassRefElement.tag, | 38 ClassRefElement.tag, |
34 NavTopMenuElement.tag, | 39 NavTopMenuElement.tag, |
35 NavVMMenuElement.tag, | 40 NavVMMenuElement.tag, |
36 NavIsolateMenuElement.tag, | 41 NavIsolateMenuElement.tag, |
37 NavRefreshElement.tag, | 42 NavRefreshElement.tag, |
38 NavNotifyElement.tag, | 43 NavNotifyElement.tag, |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 final text = 'A heap dominator tree, where siblings with the same class' | 292 final text = 'A heap dominator tree, where siblings with the same class' |
288 ' have been merged into a single node.'; | 293 ' have been merged into a single node.'; |
289 report.addAll([ | 294 report.addAll([ |
290 new DivElement() | 295 new DivElement() |
291 ..classes = ['content-centered-big', 'explanation'] | 296 ..classes = ['content-centered-big', 'explanation'] |
292 ..text = text | 297 ..text = text |
293 ..title = text, | 298 ..title = text, |
294 _tree | 299 _tree |
295 ]); | 300 ]); |
296 break; | 301 break; |
| 302 case HeapSnapshotTreeMode.ownershipTable: |
| 303 final items = _snapshot.ownershipClasses.toList(); |
| 304 items.sort((a, b) => b.size - a.size); |
| 305 _tree = new VirtualTreeElement(_createOwnershipClass, |
| 306 _updateOwnershipClass, _getChildrenOwnershipClass, |
| 307 items: items, queue: _r.queue); |
| 308 _tree.expand(_snapshot.dominatorTree); |
| 309 report.add(_tree); |
| 310 break; |
297 case HeapSnapshotTreeMode.groupByClass: | 311 case HeapSnapshotTreeMode.groupByClass: |
298 final items = _snapshot.classReferences.toList(); | 312 final items = _snapshot.classReferences.toList(); |
299 items.sort((a, b) => b.shallowSize - a.shallowSize); | 313 items.sort((a, b) => b.shallowSize - a.shallowSize); |
300 _tree = new VirtualTreeElement( | 314 _tree = new VirtualTreeElement( |
301 _createGroup, _updateGroup, _getChildrenGroup, | 315 _createGroup, _updateGroup, _getChildrenGroup, |
302 items: items, queue: _r.queue); | 316 items: items, queue: _r.queue); |
303 _tree.expand(_snapshot.dominatorTree); | 317 _tree.expand(_snapshot.dominatorTree); |
304 report.add(_tree); | 318 report.add(_tree); |
305 break; | 319 break; |
306 default: | 320 default: |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 new ButtonElement() | 370 new ButtonElement() |
357 ..classes = ['expander'] | 371 ..classes = ['expander'] |
358 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), | 372 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
359 new SpanElement() | 373 new SpanElement() |
360 ..classes = ['count'] | 374 ..classes = ['count'] |
361 ..title = 'shallow size', | 375 ..title = 'shallow size', |
362 new SpanElement()..classes = ['name'] | 376 new SpanElement()..classes = ['name'] |
363 ]; | 377 ]; |
364 } | 378 } |
365 | 379 |
| 380 static Element _createOwnershipClass(toggle) { |
| 381 return new DivElement() |
| 382 ..classes = ['tree-item'] |
| 383 ..children = [ |
| 384 new SpanElement() |
| 385 ..classes = ['size'] |
| 386 ..title = 'size', |
| 387 new SpanElement()..classes = ['name'] |
| 388 ]; |
| 389 } |
| 390 |
366 static const int kMaxChildren = 100; | 391 static const int kMaxChildren = 100; |
367 static const int kMinRetainedSize = 4096; | 392 static const int kMinRetainedSize = 4096; |
368 | 393 |
369 static _getChildrenDominator(M.HeapSnapshotDominatorNode node) { | 394 static _getChildrenDominator(M.HeapSnapshotDominatorNode node) { |
370 final list = node.children.toList(); | 395 final list = node.children.toList(); |
371 list.sort((a, b) => b.retainedSize - a.retainedSize); | 396 list.sort((a, b) => b.retainedSize - a.retainedSize); |
372 return list | 397 return list |
373 .where((child) => child.retainedSize >= kMinRetainedSize) | 398 .where((child) => child.retainedSize >= kMinRetainedSize) |
374 .take(kMaxChildren); | 399 .take(kMaxChildren); |
375 } | 400 } |
(...skipping 10 matching lines...) Expand all Loading... |
386 if (item is M.HeapSnapshotClassReferences) { | 411 if (item is M.HeapSnapshotClassReferences) { |
387 if (item.inbounds.isNotEmpty || item.outbounds.isNotEmpty) { | 412 if (item.inbounds.isNotEmpty || item.outbounds.isNotEmpty) { |
388 return [item.inbounds, item.outbounds]; | 413 return [item.inbounds, item.outbounds]; |
389 } | 414 } |
390 } else if (item is Iterable) { | 415 } else if (item is Iterable) { |
391 return item.toList()..sort((a, b) => b.shallowSize - a.shallowSize); | 416 return item.toList()..sort((a, b) => b.shallowSize - a.shallowSize); |
392 } | 417 } |
393 return const []; | 418 return const []; |
394 } | 419 } |
395 | 420 |
| 421 static _getChildrenOwnershipClass(item) { |
| 422 return const []; |
| 423 } |
| 424 |
396 void _updateDominator( | 425 void _updateDominator( |
397 HtmlElement element, M.HeapSnapshotDominatorNode node, int depth) { | 426 HtmlElement element, M.HeapSnapshotDominatorNode node, int depth) { |
398 element.children[0].text = Utils.formatSize(node.retainedSize); | 427 element.children[0].text = Utils.formatSize(node.retainedSize); |
399 _updateLines(element.children[1].children, depth); | 428 _updateLines(element.children[1].children, depth); |
400 if (_getChildrenDominator(node).isNotEmpty) { | 429 if (_getChildrenDominator(node).isNotEmpty) { |
401 element.children[2].text = _tree.isExpanded(node) ? '▼' : '►'; | 430 element.children[2].text = _tree.isExpanded(node) ? '▼' : '►'; |
402 } else { | 431 } else { |
403 element.children[2].text = ''; | 432 element.children[2].text = ''; |
404 } | 433 } |
405 element.children[3].text = | 434 element.children[3].text = |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 ]; | 532 ]; |
504 } else if (item is M.HeapSnapshotClassOutbound) { | 533 } else if (item is M.HeapSnapshotClassOutbound) { |
505 element.children[3]..text = '${item.count} references to instances of '; | 534 element.children[3]..text = '${item.count} references to instances of '; |
506 element.children[4].children = [ | 535 element.children[4].children = [ |
507 new ClassRefElement(_isolate, item.target, queue: _r.queue) | 536 new ClassRefElement(_isolate, item.target, queue: _r.queue) |
508 ]; | 537 ]; |
509 } | 538 } |
510 } | 539 } |
511 } | 540 } |
512 | 541 |
| 542 void _updateOwnershipClass(HtmlElement element, item, int depth) { |
| 543 _updateLines(element.children[1].children, depth); |
| 544 element.children[0].text = Utils.formatSize(item.size); |
| 545 element.children[1] = |
| 546 new ClassRefElement(_isolate, item.clazz, queue: _r.queue) |
| 547 ..classes = ['name']; |
| 548 } |
| 549 |
513 static _updateLines(List<Element> lines, int n) { | 550 static _updateLines(List<Element> lines, int n) { |
514 n = Math.max(0, n); | 551 n = Math.max(0, n); |
515 while (lines.length > n) { | 552 while (lines.length > n) { |
516 lines.removeLast(); | 553 lines.removeLast(); |
517 } | 554 } |
518 while (lines.length < n) { | 555 while (lines.length < n) { |
519 lines.add(new SpanElement()); | 556 lines.add(new SpanElement()); |
520 } | 557 } |
521 } | 558 } |
522 | 559 |
(...skipping 24 matching lines...) Expand all Loading... |
547 }) | 584 }) |
548 ]; | 585 ]; |
549 } | 586 } |
550 | 587 |
551 static String modeToString(HeapSnapshotTreeMode mode) { | 588 static String modeToString(HeapSnapshotTreeMode mode) { |
552 switch (mode) { | 589 switch (mode) { |
553 case HeapSnapshotTreeMode.dominatorTree: | 590 case HeapSnapshotTreeMode.dominatorTree: |
554 return 'Dominator tree'; | 591 return 'Dominator tree'; |
555 case HeapSnapshotTreeMode.mergedDominatorTree: | 592 case HeapSnapshotTreeMode.mergedDominatorTree: |
556 return 'Dominator tree (merged siblings by class)'; | 593 return 'Dominator tree (merged siblings by class)'; |
| 594 case HeapSnapshotTreeMode.ownershipTable: |
| 595 return 'Ownership table'; |
557 case HeapSnapshotTreeMode.groupByClass: | 596 case HeapSnapshotTreeMode.groupByClass: |
558 return 'Group by class'; | 597 return 'Group by class'; |
559 } | 598 } |
560 throw new Exception('Unknown HeapSnapshotTreeMode'); | 599 throw new Exception('Unknown HeapSnapshotTreeMode'); |
561 } | 600 } |
562 | 601 |
563 List<Element> _createModeSelect() { | 602 List<Element> _createModeSelect() { |
564 var s; | 603 var s; |
565 return [ | 604 return [ |
566 s = new SelectElement() | 605 s = new SelectElement() |
567 ..classes = ['analysis-select'] | 606 ..classes = ['analysis-select'] |
568 ..value = modeToString(_mode) | 607 ..value = modeToString(_mode) |
569 ..children = HeapSnapshotTreeMode.values.map((mode) { | 608 ..children = HeapSnapshotTreeMode.values.map((mode) { |
570 return new OptionElement( | 609 return new OptionElement( |
571 value: modeToString(mode), selected: _mode == mode) | 610 value: modeToString(mode), selected: _mode == mode) |
572 ..text = modeToString(mode); | 611 ..text = modeToString(mode); |
573 }).toList(growable: false) | 612 }).toList(growable: false) |
574 ..onChange.listen((_) { | 613 ..onChange.listen((_) { |
575 _mode = HeapSnapshotTreeMode.values[s.selectedIndex]; | 614 _mode = HeapSnapshotTreeMode.values[s.selectedIndex]; |
576 _r.dirty(); | 615 _r.dirty(); |
577 }) | 616 }) |
578 ]; | 617 ]; |
579 } | 618 } |
580 } | 619 } |
OLD | NEW |