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

Side by Side Diff: runtime/observatory/lib/object_graph.dart

Issue 3009743003: [observatory] Add an "ownership" analysis for the heap snapshot. (Closed)
Patch Set: . Created 3 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 object_graph; 5 library object_graph;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:typed_data'; 9 import 'dart:typed_data';
10 10
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 437
438 int get internalSize => _internalSize; 438 int get internalSize => _internalSize;
439 int get externalSize => _externalSize; 439 int get externalSize => _externalSize;
440 int get vertexCount => _N; 440 int get vertexCount => _N;
441 int get edgeCount => _E; 441 int get edgeCount => _E;
442 442
443 ObjectVertex get root => new ObjectVertex._(ROOT, this); 443 ObjectVertex get root => new ObjectVertex._(ROOT, this);
444 MergedObjectVertex get mergedRoot => new MergedObjectVertex._(ROOT, this); 444 MergedObjectVertex get mergedRoot => new MergedObjectVertex._(ROOT, this);
445 Iterable<ObjectVertex> get vertices => new _VerticesIterable(this); 445 Iterable<ObjectVertex> get vertices => new _VerticesIterable(this);
446 446
447 int get numCids => _numCids;
448 int getOwnedByCid(int cid) => _ownedSizesByCid[cid];
449
447 Iterable<ObjectVertex> getMostRetained({int classId, int limit}) { 450 Iterable<ObjectVertex> getMostRetained({int classId, int limit}) {
448 List<ObjectVertex> _mostRetained = 451 List<ObjectVertex> _mostRetained =
449 new List<ObjectVertex>.from(vertices.where((u) => !u.isRoot)); 452 new List<ObjectVertex>.from(vertices.where((u) => !u.isRoot));
450 _mostRetained.sort((u, v) => v.retainedSize - u.retainedSize); 453 _mostRetained.sort((u, v) => v.retainedSize - u.retainedSize);
451 454
452 var result = _mostRetained; 455 var result = _mostRetained;
453 if (classId != null) { 456 if (classId != null) {
454 result = result.where((u) => u.vmCid == classId); 457 result = result.where((u) => u.vmCid == classId);
455 } 458 }
456 if (limit != null) { 459 if (limit != null) {
457 result = result.take(limit); 460 result = result.take(limit);
458 } 461 }
459 return result; 462 return result;
460 } 463 }
461 464
462 Stream<List> process() { 465 Stream<List> process() {
463 final controller = new StreamController<List>.broadcast(); 466 final controller = new StreamController<List>.broadcast();
464 (() async { 467 (() async {
465 // We build futures here instead of marking the steps as async to avoid th e 468 // We build futures here instead of marking the steps as async to avoid th e
466 // heavy lifting being inside a transformed method. 469 // heavy lifting being inside a transformed method.
467 470
468 controller.add(["Remapping $_N objects...", 0.0]); 471 controller.add(["Remapping $_N objects...", 0.0]);
469 await new Future(() => _remapNodes()); 472 await new Future(() => _remapNodes());
470 473
471 controller.add(["Remapping $_E references...", 15.0]); 474 controller.add(["Remapping $_E references...", 10.0]);
472 await new Future(() => _remapEdges()); 475 await new Future(() => _remapEdges());
473 476
474 _addrToId = null; 477 _addrToId = null;
475 _chunks = null; 478 _chunks = null;
476 479
477 controller.add(["Finding depth-first order...", 30.0]); 480 controller.add(["Finding depth-first order...", 20.0]);
478 await new Future(() => _dfs()); 481 await new Future(() => _dfs());
479 482
480 controller.add(["Finding predecessors...", 40.0]); 483 controller.add(["Finding predecessors...", 30.0]);
481 await new Future(() => _buildPredecessors()); 484 await new Future(() => _buildPredecessors());
482 485
483 controller.add(["Finding dominators...", 50.0]); 486 controller.add(["Finding dominators...", 40.0]);
484 await new Future(() => _buildDominators()); 487 await new Future(() => _buildDominators());
485 488
489 _semi = null;
490 _parent = null;
491
492 controller.add(["Finding in-degree(1) groups...", 50.0]);
493 await new Future(() => _buildOwnedSizes());
494
486 _firstPreds = null; 495 _firstPreds = null;
487 _preds = null; 496 _preds = null;
488 497
489 _semi = null;
490 _parent = null;
491
492 controller.add(["Finding retained sizes...", 60.0]); 498 controller.add(["Finding retained sizes...", 60.0]);
493 await new Future(() => _calculateRetainedSizes()); 499 await new Future(() => _calculateRetainedSizes());
494 500
495 _vertex = null; 501 _vertex = null;
496 502
497 controller.add(["Linking dominator tree children...", 70.0]); 503 controller.add(["Linking dominator tree children...", 70.0]);
498 await new Future(() => _linkDominatorChildren()); 504 await new Future(() => _linkDominatorChildren());
499 505
500 controller.add(["Sorting dominator tree children...", 80.0]); 506 controller.add(["Sorting dominator tree children...", 80.0]);
501 await new Future(() => _sortDominatorChildren()); 507 await new Future(() => _sortDominatorChildren());
502 508
503 controller.add(["Merging dominator tree siblings...", 90.0]); 509 controller.add(["Merging dominator tree siblings...", 90.0]);
504 await new Future(() => _mergeDominatorSiblings()); 510 await new Future(() => _mergeDominatorSiblings());
505 511
506 controller.add(["Processed", 100.0]); 512 controller.add(["Processed", 100.0]);
507 controller.close(); 513 controller.close();
508 }()); 514 }());
509 return controller.stream; 515 return controller.stream;
510 } 516 }
511 517
512 List<ByteData> _chunks; 518 List<ByteData> _chunks;
513 519
514 int _kObjectAlignment; 520 int _kObjectAlignment;
515 int _kStackCid; 521 int _kStackCid;
522 int _kFieldCid;
523 int _numCids;
516 int _N; // Objects in the snapshot. 524 int _N; // Objects in the snapshot.
517 int _Nconnected; // Objects reachable from root. 525 int _Nconnected; // Objects reachable from root.
518 int _E; // References in the snapshot. 526 int _E; // References in the snapshot.
519 int _internalSize; 527 int _internalSize;
520 int _externalSize; 528 int _externalSize;
521 529
522 // Indexed by node id, with id 0 representing invalid/uninitialized. 530 // Indexed by node id, with id 0 representing invalid/uninitialized.
523 // From snapshot. 531 // From snapshot.
524 Uint16List _cids; 532 Uint16List _cids;
525 Uint32List _shallowSizes; 533 Uint32List _shallowSizes;
526 Uint32List _externalSizes; 534 Uint32List _externalSizes;
527 Uint32List _firstSuccs; 535 Uint32List _firstSuccs;
528 Uint32List _succs; 536 Uint32List _succs;
529 Uint32List _addressesLow; // No Uint64List in Javascript. 537 Uint32List _addressesLow; // No Uint64List in Javascript.
530 Uint32List _addressesHigh; 538 Uint32List _addressesHigh;
531 539
532 // Intermediates. 540 // Intermediates.
533 AddressMapper _addrToId; 541 AddressMapper _addrToId;
534 Uint32List _vertex; 542 Uint32List _vertex;
535 Uint32List _parent; 543 Uint32List _parent;
536 Uint32List _semi; 544 Uint32List _semi;
537 Uint32List _firstPreds; // Offset into preds. 545 Uint32List _firstPreds; // Offset into preds.
538 Uint32List _preds; 546 Uint32List _preds;
539 547
540 // Outputs. 548 // Outputs.
541 Uint32List _doms; 549 Uint32List _doms;
542 Uint32List _retainedSizes; 550 Uint32List _retainedSizes;
543 Uint32List _mergedDomHead; 551 Uint32List _mergedDomHead;
544 Uint32List _mergedDomNext; 552 Uint32List _mergedDomNext;
553 Uint32List _ownedSizesByCid;
545 554
546 void _remapNodes() { 555 void _remapNodes() {
547 var N = _N; 556 var N = _N;
548 var E = 0; 557 var E = 0;
549 var addrToId = new AddressMapper(N); 558 var addrToId = new AddressMapper(N);
550 559
551 var addressesHigh = new Uint32List(N + 1); 560 var addressesHigh = new Uint32List(N + 1);
552 var addressesLow = new Uint32List(N + 1); 561 var addressesLow = new Uint32List(N + 1);
553 var shallowSizes = new Uint32List(N + 1); 562 var shallowSizes = new Uint32List(N + 1);
554 var externalSizes = new Uint32List(N + 1); 563 var externalSizes = new Uint32List(N + 1);
555 var cids = new Uint16List(N + 1); 564 var cids = new Uint16List(N + 1);
556 565
557 var stream = new ReadStream(_chunks); 566 var stream = new ReadStream(_chunks);
558 stream.readUnsigned(); 567 stream.readUnsigned();
559 _kObjectAlignment = stream.clampedUint32; 568 _kObjectAlignment = stream.clampedUint32;
560 stream.readUnsigned(); 569 stream.readUnsigned();
561 _kStackCid = stream.clampedUint32; 570 _kStackCid = stream.clampedUint32;
571 stream.readUnsigned();
572 _kFieldCid = stream.clampedUint32;
573 stream.readUnsigned();
574 _numCids = stream.clampedUint32;
562 575
563 var id = ROOT; 576 var id = ROOT;
564 while (id <= N) { 577 while (id <= N) {
565 stream.readUnsigned(); // addr 578 stream.readUnsigned(); // addr
566 addrToId.put(stream.high, stream.mid, stream.low, id); 579 addrToId.put(stream.high, stream.mid, stream.low, id);
567 addressesHigh[id] = stream.highUint32; 580 addressesHigh[id] = stream.highUint32;
568 addressesLow[id] = stream.lowUint32; 581 addressesLow[id] = stream.lowUint32;
569 stream.readUnsigned(); // shallowSize 582 stream.readUnsigned(); // shallowSize
570 shallowSizes[id] = stream.clampedUint32; 583 shallowSizes[id] = stream.clampedUint32;
571 stream.readUnsigned(); // cid 584 stream.readUnsigned(); // cid
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 var N = _N; 619 var N = _N;
607 var E = _E; 620 var E = _E;
608 var addrToId = _addrToId; 621 var addrToId = _addrToId;
609 622
610 var firstSuccs = new Uint32List(N + 2); 623 var firstSuccs = new Uint32List(N + 2);
611 var succs = new Uint32List(E); 624 var succs = new Uint32List(E);
612 625
613 var stream = new ReadStream(_chunks); 626 var stream = new ReadStream(_chunks);
614 stream.skipUnsigned(); // kObjectAlignment 627 stream.skipUnsigned(); // kObjectAlignment
615 stream.skipUnsigned(); // kStackCid 628 stream.skipUnsigned(); // kStackCid
629 stream.skipUnsigned(); // kFieldCid
630 stream.skipUnsigned(); // numCids
616 631
617 var id = 1, edge = 0; 632 var id = 1, edge = 0;
618 while (id <= N) { 633 while (id <= N) {
619 stream.skipUnsigned(); // addr 634 stream.skipUnsigned(); // addr
620 stream.skipUnsigned(); // shallowSize 635 stream.skipUnsigned(); // shallowSize
621 stream.skipUnsigned(); // cid 636 stream.skipUnsigned(); // cid
622 637
623 firstSuccs[id] = edge; 638 firstSuccs[id] = edge;
624 639
625 stream.readUnsigned(); 640 stream.readUnsigned();
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
784 var predIndex = nextPreds[succId]++; 799 var predIndex = nextPreds[succId]++;
785 preds[predIndex] = i; 800 preds[predIndex] = i;
786 } 801 }
787 } 802 }
788 } 803 }
789 804
790 _firstPreds = firstPreds; 805 _firstPreds = firstPreds;
791 _preds = preds; 806 _preds = preds;
792 } 807 }
793 808
809 // Fold the size of any object with in-degree(1) into its parent.
810 // Requires the DFS numbering and predecessor lists.
811 void _buildOwnedSizes() {
812 var N = _N;
813 var Nconnected = _Nconnected;
814 var kStackCid = _kStackCid;
815 var kFieldCid = _kFieldCid;
816
817 var cids = _cids;
818 var shallowSizes = _shallowSizes;
819 var externalSizes = _externalSizes;
820 var vertex = _vertex;
821 var firstPreds = _firstPreds;
822 var preds = _preds;
823
824 var ownedSizes = new Uint32List(N + 1);
825 for (var i = 1; i <= Nconnected; i++) {
826 var v = vertex[i];
827 ownedSizes[v] = shallowSizes[v] + externalSizes[v];
828 assert(ownedSizes[v] != 0);
829 }
830
831 for (var i = Nconnected; i > 1; i--) {
832 var w = vertex[i];
833 assert(w != ROOT);
834
835 var onlyPred = SENTINEL;
836
837 var startPred = firstPreds[w];
838 var limitPred = firstPreds[w + 1];
839 for (var predIndex = startPred; predIndex < limitPred; predIndex++) {
840 var v = preds[predIndex];
841 if (v == w) {
842 // Ignore self-predecessor.
843 } else if (onlyPred == SENTINEL) {
844 onlyPred = v;
845 } else if (onlyPred == v) {
846 // Repeated predecessor.
847 } else {
848 // Multiple-predecessors.
849 onlyPred = SENTINEL;
850 break;
851 }
852 }
853
854 // If this object has a single precessor which is not a Field, Stack or
855 // the root, blame its size against the precessor.
856 if ((onlyPred != SENTINEL) &&
857 (onlyPred != ROOT) &&
858 (cids[onlyPred] != kStackCid) &&
859 (cids[onlyPred] != kFieldCid)) {
860 assert(ownedSizes[w] != 0);
861 ownedSizes[onlyPred] += ownedSizes[w];
862 ownedSizes[w] = 0;
863 }
864 }
865
866 // TODO(rmacnak): Maybe keep the per-objects sizes to be able to provide
867 // examples of large owners for each class.
868 var ownedSizesByCid = new Uint32List(_numCids);
869 for (var i = 1; i <= Nconnected; i++) {
870 var v = vertex[i];
871 var cid = cids[v];
872 ownedSizesByCid[cid] += ownedSizes[v];
873 }
874
875 _ownedSizesByCid = ownedSizesByCid;
876 }
877
794 static int _eval(int v, Uint32List ancestor, Uint32List semi, 878 static int _eval(int v, Uint32List ancestor, Uint32List semi,
795 Uint32List label, Uint32List stackNode, Uint8List stackState) { 879 Uint32List label, Uint32List stackNode, Uint8List stackState) {
796 if (ancestor[v] == SENTINEL) { 880 if (ancestor[v] == SENTINEL) {
797 return label[v]; 881 return label[v];
798 } else { 882 } else {
799 { 883 {
800 // Inlined 'compress' with an explicit stack to prevent JS stack 884 // Inlined 'compress' with an explicit stack to prevent JS stack
801 // overflow. 885 // overflow.
802 var top = 0; 886 var top = 0;
803 stackNode[top] = v; 887 stackNode[top] = v;
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after
1131 1215
1132 // From all the siblings between child and after, take their children, 1216 // From all the siblings between child and after, take their children,
1133 // merge them and given to child. 1217 // merge them and given to child.
1134 mergeChildrenAndSort(child, after); 1218 mergeChildrenAndSort(child, after);
1135 1219
1136 child = after; 1220 child = after;
1137 } 1221 }
1138 } 1222 }
1139 } 1223 }
1140 } 1224 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698