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

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

Issue 2502283003: Add a version of heap snapshots that use only fields and stack frames as roots and only include ins… (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) 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
11 import 'package:logging/logging.dart';
12
11 class _JenkinsSmiHash { 13 class _JenkinsSmiHash {
12 static int combine(int hash, int value) { 14 static int combine(int hash, int value) {
13 hash = 0x1fffffff & (hash + value); 15 hash = 0x1fffffff & (hash + value);
14 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); 16 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
15 return hash ^ (hash >> 6); 17 return hash ^ (hash >> 6);
16 } 18 }
17 19
18 static int finish(int hash) { 20 static int finish(int hash) {
19 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); 21 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
20 hash = hash ^ (hash >> 11); 22 hash = hash ^ (hash >> 11);
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 const ROOT = 1; 222 const ROOT = 1;
221 const SENTINEL = 0; 223 const SENTINEL = 0;
222 224
223 class ObjectVertex { 225 class ObjectVertex {
224 final int _id; 226 final int _id;
225 final ObjectGraph _graph; 227 final ObjectGraph _graph;
226 228
227 ObjectVertex._(this._id, this._graph); 229 ObjectVertex._(this._id, this._graph);
228 230
229 bool get isRoot => ROOT == _id; 231 bool get isRoot => ROOT == _id;
232 bool get isStack => vmCid == _graph._kStackCid;
230 233
231 bool operator ==(other) => _id == other._id && _graph == other._graph; 234 bool operator ==(other) => _id == other._id && _graph == other._graph;
232 int get hashCode => _id; 235 int get hashCode => _id;
233 236
234 int get retainedSize => _graph._retainedSizes[_id]; 237 int get retainedSize => _graph._retainedSizes[_id];
235 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); 238 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph);
236 239
237 int get shallowSize => _graph._shallowSizes[_id]; 240 int get shallowSize => _graph._shallowSizes[_id];
238 int get vmCid => _graph._cids[_id]; 241 int get vmCid => _graph._cids[_id];
239 242
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 // object of this set. The other members of the set are found by walking the 296 // object of this set. The other members of the set are found by walking the
294 // mergedDomNext links until finding the sentinel node or a node with a 297 // mergedDomNext links until finding the sentinel node or a node with a
295 // different class. 298 // different class.
296 class MergedObjectVertex { 299 class MergedObjectVertex {
297 final int _id; 300 final int _id;
298 final ObjectGraph _graph; 301 final ObjectGraph _graph;
299 302
300 MergedObjectVertex._(this._id, this._graph); 303 MergedObjectVertex._(this._id, this._graph);
301 304
302 bool get isRoot => ROOT == _id; 305 bool get isRoot => ROOT == _id;
306 bool get isStack => vmCid == _graph._kStackCid;
303 307
304 bool operator ==(other) => _id == other._id && _graph == other._graph; 308 bool operator ==(other) => _id == other._id && _graph == other._graph;
305 int get hashCode => _id; 309 int get hashCode => _id;
306 310
307 int get vmCid => _graph._cids[_id]; 311 int get vmCid => _graph._cids[_id];
308 312
309 int get shallowSize { 313 int get shallowSize {
310 var cids = _graph._cids; 314 var cids = _graph._cids;
311 var size = 0; 315 var size = 0;
312 var sibling = _id; 316 var sibling = _id;
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 494
491 controller.add(["Processed", 100.0]); 495 controller.add(["Processed", 100.0]);
492 controller.close(); 496 controller.close();
493 }()); 497 }());
494 return controller.stream; 498 return controller.stream;
495 } 499 }
496 500
497 List<ByteData> _chunks; 501 List<ByteData> _chunks;
498 502
499 int _kObjectAlignment; 503 int _kObjectAlignment;
500 int _N; 504 int _kStackCid;
501 int _E; 505 int _N; // Objects in the snapshot.
506 int _Nconnected; // Objects reachable from root.
507 int _E; // References in the snapshot.
502 int _size; 508 int _size;
503 509
504 // Indexed by node id, with id 0 representing invalid/uninitialized. 510 // Indexed by node id, with id 0 representing invalid/uninitialized.
505 // From snapshot. 511 // From snapshot.
506 Uint16List _cids; 512 Uint16List _cids;
507 Uint32List _shallowSizes; 513 Uint32List _shallowSizes;
508 Uint32List _firstSuccs; 514 Uint32List _firstSuccs;
509 Uint32List _succs; 515 Uint32List _succs;
510 Uint32List _addressesLow; // No Uint64List in Javascript. 516 Uint32List _addressesLow; // No Uint64List in Javascript.
511 Uint32List _addressesHigh; 517 Uint32List _addressesHigh;
(...skipping 18 matching lines...) Expand all
530 var addrToId = new AddressMapper(N); 536 var addrToId = new AddressMapper(N);
531 537
532 var addressesHigh = new Uint32List(N + 1); 538 var addressesHigh = new Uint32List(N + 1);
533 var addressesLow = new Uint32List(N + 1); 539 var addressesLow = new Uint32List(N + 1);
534 var shallowSizes = new Uint32List(N + 1); 540 var shallowSizes = new Uint32List(N + 1);
535 var cids = new Uint16List(N + 1); 541 var cids = new Uint16List(N + 1);
536 542
537 var stream = new ReadStream(_chunks); 543 var stream = new ReadStream(_chunks);
538 stream.readUnsigned(); 544 stream.readUnsigned();
539 _kObjectAlignment = stream.clampedUint32; 545 _kObjectAlignment = stream.clampedUint32;
546 stream.readUnsigned();
547 _kStackCid = stream.clampedUint32;
540 548
541 var id = ROOT; 549 var id = ROOT;
542 while (stream.pendingBytes > 0) { 550 while (stream.pendingBytes > 0) {
543 stream.readUnsigned(); // addr 551 stream.readUnsigned(); // addr
544 addrToId.put(stream.high, stream.mid, stream.low, id); 552 addrToId.put(stream.high, stream.mid, stream.low, id);
545 addressesHigh[id] = stream.highUint32; 553 addressesHigh[id] = stream.highUint32;
546 addressesLow[id] = stream.lowUint32; 554 addressesLow[id] = stream.lowUint32;
547 stream.readUnsigned(); // shallowSize 555 stream.readUnsigned(); // shallowSize
548 shallowSizes[id] = stream.clampedUint32; 556 shallowSizes[id] = stream.clampedUint32;
549 stream.readUnsigned(); // cid 557 stream.readUnsigned(); // cid
(...skipping 20 matching lines...) Expand all
570 578
571 void _remapEdges() { 579 void _remapEdges() {
572 var N = _N; 580 var N = _N;
573 var E = _E; 581 var E = _E;
574 var addrToId = _addrToId; 582 var addrToId = _addrToId;
575 583
576 var firstSuccs = new Uint32List(N + 2); 584 var firstSuccs = new Uint32List(N + 2);
577 var succs = new Uint32List(E); 585 var succs = new Uint32List(E);
578 586
579 var stream = new ReadStream(_chunks); 587 var stream = new ReadStream(_chunks);
580 stream.skipUnsigned(); // addr alignment 588 stream.skipUnsigned(); // kObjectAlignment
589 stream.skipUnsigned(); // kStackCid
581 590
582 var id = 1, edge = 0; 591 var id = 1, edge = 0;
583 while (stream.pendingBytes > 0) { 592 while (stream.pendingBytes > 0) {
584 stream.skipUnsigned(); // addr 593 stream.skipUnsigned(); // addr
585 stream.skipUnsigned(); // shallowSize 594 stream.skipUnsigned(); // shallowSize
586 stream.skipUnsigned(); // cid 595 stream.skipUnsigned(); // cid
587 596
588 firstSuccs[id] = edge; 597 firstSuccs[id] = edge;
589 598
590 stream.readUnsigned(); 599 stream.readUnsigned();
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 stackTop++; 662 stackTop++;
654 stackNodes[stackTop] = childId; 663 stackNodes[stackTop] = childId;
655 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; 664 stackCurrentEdgePos[stackTop] = firstSuccs[childId];
656 } 665 }
657 } else { 666 } else {
658 // Done with all children. 667 // Done with all children.
659 stackTop--; 668 stackTop--;
660 } 669 }
661 } 670 }
662 671
663 assert(dfsNumber == N); 672 if (dfsNumber != N) {
664 for (var i = ROOT; i <= N; i++) { 673 // This may happen in filtered snapshots.
665 assert(semi[i] != SENTINEL); 674 Logger.root.warning('Heap snapshot contains unreachable nodes.');
666 }
667 assert(parent[ROOT] == SENTINEL);
668 for (var i = ROOT + 1; i <= N; i++) {
669 assert(parent[i] != SENTINEL);
670 } 675 }
671 676
677 assert(() {
678 for (var i = 1; i <= dfsNumber; i++) {
679 var v = vertex[i];
680 assert(semi[v] != SENTINEL);
681 }
682 assert(parent[1] == SENTINEL);
683 for (var i = 2; i <= dfsNumber; i++) {
684 var v = vertex[i];
685 assert(parent[v] != SENTINEL);
686 }
687 return true;
688 });
689
690 if (dfsNumber != N) {
691 // Remove successors of unconnected nodes
692 for (var i = ROOT + 1; i <= N; i++) {
693 if (parent[i] == SENTINEL) {
694 var startSuccIndex = firstSuccs[i];
695 var limitSuccIndex = firstSuccs[i + 1];
696 for (var succIndex = startSuccIndex;
697 succIndex < limitSuccIndex;
698 succIndex++) {
699 succs[succIndex] = SENTINEL;
700 }
701 }
702 }
703 }
704
705 _Nconnected = dfsNumber;
672 _vertex = vertex; 706 _vertex = vertex;
673 _semi = semi; 707 _semi = semi;
674 _parent = parent; 708 _parent = parent;
675 } 709 }
676 710
677 void _buildPredecessors() { 711 void _buildPredecessors() {
678 var N = _N; 712 var N = _N;
713 var Nconnected = _Nconnected;
679 var E = _E; 714 var E = _E;
680 var firstSuccs = _firstSuccs; 715 var firstSuccs = _firstSuccs;
681 var succs = _succs; 716 var succs = _succs;
682 717
683 // This is first filled with the predecessor counts, then reused to hold the 718 // This is first filled with the predecessor counts, then reused to hold the
684 // offset to the first predecessor (see alias below). 719 // offset to the first predecessor (see alias below).
685 // + 1 because 0 is a sentinel 720 // + 1 because 0 is a sentinel
686 // + 1 so the number of predecessors can be found from the difference with 721 // + 1 so the number of predecessors can be found from the difference with
687 // the next node's offset. 722 // the next node's offset.
688 var numPreds = new Uint32List(N + 2); 723 var numPreds = new Uint32List(N + 2);
689 var preds = new Uint32List(E); 724 var preds = new Uint32List(E);
690 725
691 // Count predecessors of each node. 726 // Count predecessors of each node.
692 for (var succIndex = 0; succIndex < E; succIndex++) { 727 for (var succIndex = 0; succIndex < E; succIndex++) {
693 var succId = succs[succIndex]; 728 var succId = succs[succIndex];
694 numPreds[succId]++; 729 if (succId != SENTINEL) {
730 numPreds[succId]++;
731 }
695 } 732 }
696 733
697 // Assign indices into predecessors array. 734 // Assign indices into predecessors array.
698 var firstPreds = numPreds; // Alias. 735 var firstPreds = numPreds; // Alias.
699 var nextPreds = new Uint32List(N + 1); 736 var nextPreds = new Uint32List(N + 1);
700 var predIndex = 0; 737 var predIndex = 0;
701 for (var i = 1; i <= N; i++) { 738 for (var i = 1; i <= N; i++) {
702 var thisPredIndex = predIndex; 739 var thisPredIndex = predIndex;
703 predIndex += numPreds[i]; 740 predIndex += numPreds[i];
704 firstPreds[i] = thisPredIndex; 741 firstPreds[i] = thisPredIndex;
705 nextPreds[i] = thisPredIndex; 742 nextPreds[i] = thisPredIndex;
706 } 743 }
707 assert(predIndex == E); 744 if (N == Nconnected) {
708 firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. 745 assert(predIndex == E);
746 }
747 firstPreds[N + 1] = predIndex; // Extra entry for cheap boundary detection.
709 748
710 // Fill predecessors array. 749 // Fill predecessors array.
711 for (var i = 1; i <= N; i++) { 750 for (var i = 1; i <= N; i++) {
712 var startSuccIndex = firstSuccs[i]; 751 var startSuccIndex = firstSuccs[i];
713 var limitSuccIndex = firstSuccs[i + 1]; 752 var limitSuccIndex = firstSuccs[i + 1];
714 for (var succIndex = startSuccIndex; 753 for (var succIndex = startSuccIndex;
715 succIndex < limitSuccIndex; 754 succIndex < limitSuccIndex;
716 succIndex++) { 755 succIndex++) {
717 var succId = succs[succIndex]; 756 var succId = succs[succIndex];
718 var predIndex = nextPreds[succId]++; 757 if (succId != SENTINEL) {
719 preds[predIndex] = i; 758 var predIndex = nextPreds[succId]++;
759 preds[predIndex] = i;
760 }
720 } 761 }
721 } 762 }
722 763
723 _firstPreds = firstPreds; 764 _firstPreds = firstPreds;
724 _preds = preds; 765 _preds = preds;
725 } 766 }
726 767
727 static int _eval(int v, Uint32List ancestor, Uint32List semi, 768 static int _eval(int v, Uint32List ancestor, Uint32List semi,
728 Uint32List label, Uint32List stackNode, Uint8List stackState) { 769 Uint32List label, Uint32List stackNode, Uint8List stackState) {
729 if (ancestor[v] == SENTINEL) { 770 if (ancestor[v] == SENTINEL) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 while (s != 0) { 836 while (s != 0) {
796 ancestor[s] = v; 837 ancestor[s] = v;
797 s = child[s]; 838 s = child[s];
798 } 839 }
799 } 840 }
800 841
801 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators 842 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators
802 // in a Flowgraph." 843 // in a Flowgraph."
803 void _buildDominators() { 844 void _buildDominators() {
804 var N = _N; 845 var N = _N;
846 var Nconnected = _Nconnected;
805 847
806 var vertex = _vertex; 848 var vertex = _vertex;
807 var semi = _semi; 849 var semi = _semi;
808 var parent = _parent; 850 var parent = _parent;
809 var firstPreds = _firstPreds; 851 var firstPreds = _firstPreds;
810 var preds = _preds; 852 var preds = _preds;
811 853
812 var dom = new Uint32List(N + 1); 854 var dom = new Uint32List(N + 1);
813 855
814 var ancestor = new Uint32List(N + 1); 856 var ancestor = new Uint32List(N + 1);
815 var label = new Uint32List(N + 1); 857 var label = new Uint32List(N + 1);
816 for (var i = 1; i <= N; i++) { 858 for (var i = 1; i <= N; i++) {
817 label[i] = i; 859 label[i] = i;
818 } 860 }
819 var buckets = new List(N + 1); 861 var buckets = new List(N + 1);
820 var child = new Uint32List(N + 1); 862 var child = new Uint32List(N + 1);
821 var size = new Uint32List(N + 1); 863 var size = new Uint32List(N + 1);
822 for (var i = 1; i <= N; i++) { 864 for (var i = 1; i <= N; i++) {
823 size[i] = 1; 865 size[i] = 1;
824 } 866 }
825 var stackNode = new Uint32List(N + 1); 867 var stackNode = new Uint32List(N + 1);
826 var stackState = new Uint8List(N + 1); 868 var stackState = new Uint8List(N + 1);
827 869
828 for (var i = N; i > 1; i--) { 870 for (var i = Nconnected; i > 1; i--) {
829 var w = vertex[i]; 871 var w = vertex[i];
830 assert(w != ROOT); 872 assert(w != ROOT);
831 873
832 // Lengauer & Tarjan Step 2. 874 // Lengauer & Tarjan Step 2.
833 var startPred = firstPreds[w]; 875 var startPred = firstPreds[w];
834 var limitPred = firstPreds[w + 1]; 876 var limitPred = firstPreds[w + 1];
835 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { 877 for (var predIndex = startPred; predIndex < limitPred; predIndex++) {
836 var v = preds[predIndex]; 878 var v = preds[predIndex];
837 var u = _eval(v, ancestor, semi, label, stackNode, stackState); 879 var u = _eval(v, ancestor, semi, label, stackNode, stackState);
838 if (semi[u] < semi[w]) { 880 if (semi[u] < semi[w]) {
(...skipping 18 matching lines...) Expand all
857 for (var v in bucket) { 899 for (var v in bucket) {
858 var u = _eval(v, ancestor, semi, label, stackNode, stackState); 900 var u = _eval(v, ancestor, semi, label, stackNode, stackState);
859 dom[v] = semi[u] < semi[v] ? u : parent[w]; 901 dom[v] = semi[u] < semi[v] ? u : parent[w];
860 } 902 }
861 } 903 }
862 } 904 }
863 for (var i = ROOT; i <= N; i++) { 905 for (var i = ROOT; i <= N; i++) {
864 assert(buckets[i] == null); 906 assert(buckets[i] == null);
865 } 907 }
866 // Lengauer & Tarjan Step 4. 908 // Lengauer & Tarjan Step 4.
867 for (var i = 2; i <= N; i++) { 909 for (var i = 2; i <= Nconnected; i++) {
868 var w = vertex[i]; 910 var w = vertex[i];
869 if (dom[w] != vertex[semi[w]]) { 911 if (dom[w] != vertex[semi[w]]) {
870 dom[w] = dom[dom[w]]; 912 dom[w] = dom[dom[w]];
871 } 913 }
872 } 914 }
873 915
874 _doms = dom; 916 _doms = dom;
875 } 917 }
876 918
877 void _calculateRetainedSizes() { 919 void _calculateRetainedSizes() {
878 var N = _N; 920 var N = _N;
921 var Nconnected = _Nconnected;
879 922
880 var size = 0; 923 var size = 0;
881 var shallowSizes = _shallowSizes; 924 var shallowSizes = _shallowSizes;
882 var vertex = _vertex; 925 var vertex = _vertex;
883 var doms = _doms; 926 var doms = _doms;
884 927
885 // Sum shallow sizes. 928 // Sum shallow sizes.
886 for (var i = ROOT; i < N; i++) { 929 for (var i = 1; i <= Nconnected; i++) {
887 size += shallowSizes[i]; 930 var v = vertex[i];
931 size += shallowSizes[v];
888 } 932 }
889 933
890 // Start with retained size as shallow size. 934 // Start with retained size as shallow size.
891 var retainedSizes = new Uint32List.fromList(shallowSizes); 935 var retainedSizes = new Uint32List.fromList(shallowSizes);
892 936
893 // In post order (bottom up), add retained size to dominator's retained 937 // In post order (bottom up), add retained size to dominator's retained
894 // size, skipping root. 938 // size, skipping root.
895 for (var i = N; i > 1; i--) { 939 for (var i = Nconnected; i > 1; i--) {
896 var v = vertex[i]; 940 var v = vertex[i];
897 assert(v != ROOT); 941 assert(v != ROOT);
898 retainedSizes[doms[i]] += retainedSizes[i]; 942 retainedSizes[doms[v]] += retainedSizes[v];
899 } 943 }
900 944
945 assert(retainedSizes[ROOT] == size); // Root retains everything.
946
901 _retainedSizes = retainedSizes; 947 _retainedSizes = retainedSizes;
902 _size = size; 948 _size = size;
903 } 949 }
904 950
905 // Build linked lists of the children for each node in the dominator tree. 951 // Build linked lists of the children for each node in the dominator tree.
906 void _linkDominatorChildren() { 952 void _linkDominatorChildren() {
907 var N = _N; 953 var N = _N;
908 var doms = _doms; 954 var doms = _doms;
909 var head = new Uint32List(N + 1); 955 var head = new Uint32List(N + 1);
910 var next = new Uint32List(N + 1); 956 var next = new Uint32List(N + 1);
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1056 1102
1057 // From all the siblings between child and after, take their children, 1103 // From all the siblings between child and after, take their children,
1058 // merge them and given to child. 1104 // merge them and given to child.
1059 mergeChildrenAndSort(child, after); 1105 mergeChildrenAndSort(child, after);
1060 1106
1061 child = after; 1107 child = after;
1062 } 1108 }
1063 } 1109 }
1064 } 1110 }
1065 } 1111 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698