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

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
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 static const int dataBitsPerByte = 7; 212 static const int dataBitsPerByte = 7;
213 static const int byteMask = (1 << dataBitsPerByte) - 1; 213 static const int byteMask = (1 << dataBitsPerByte) - 1;
214 static const int maxUnsignedDataPerByte = byteMask; 214 static const int maxUnsignedDataPerByte = byteMask;
215 } 215 }
216 216
217 // Node indices for the root and sentinel nodes. Note that using 0 as the 217 // Node indices for the root and sentinel nodes. Note that using 0 as the
218 // sentinel means a newly allocated typed array comes initialized with all 218 // sentinel means a newly allocated typed array comes initialized with all
219 // elements as the sentinel. 219 // elements as the sentinel.
220 const ROOT = 1; 220 const ROOT = 1;
221 const SENTINEL = 0; 221 const SENTINEL = 0;
222 // Keep in sync with runtime/vm/object_graph.cc.
223 const kStackCid = 1;
Cutch 2016/11/18 20:40:31 can we get this from the VM over the protocol some
rmacnak 2016/11/18 22:34:02 pushing in the header alongside the object alignme
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 => kStackCid == vmCid;
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 => kStackCid == vmCid;
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 _N; // Objects in the snapshot.
501 int _E; 505 int _Nconnected; // Objects reachable from root.
506 int _E; // References in the snapshot.
502 int _size; 507 int _size;
503 508
504 // Indexed by node id, with id 0 representing invalid/uninitialized. 509 // Indexed by node id, with id 0 representing invalid/uninitialized.
505 // From snapshot. 510 // From snapshot.
506 Uint16List _cids; 511 Uint16List _cids;
507 Uint32List _shallowSizes; 512 Uint32List _shallowSizes;
508 Uint32List _firstSuccs; 513 Uint32List _firstSuccs;
509 Uint32List _succs; 514 Uint32List _succs;
510 Uint32List _addressesLow; // No Uint64List in Javascript. 515 Uint32List _addressesLow; // No Uint64List in Javascript.
511 Uint32List _addressesHigh; 516 Uint32List _addressesHigh;
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 stackTop++; 658 stackTop++;
654 stackNodes[stackTop] = childId; 659 stackNodes[stackTop] = childId;
655 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; 660 stackCurrentEdgePos[stackTop] = firstSuccs[childId];
656 } 661 }
657 } else { 662 } else {
658 // Done with all children. 663 // Done with all children.
659 stackTop--; 664 stackTop--;
660 } 665 }
661 } 666 }
662 667
663 assert(dfsNumber == N); 668 if (dfsNumber != N) {
664 for (var i = ROOT; i <= N; i++) { 669 // This may happen in filtered snapshots.
665 assert(semi[i] != SENTINEL); 670 print("Warning: graph has unconnected nodes");
Cutch 2016/11/18 20:40:31 remove or use the logger?
rmacnak 2016/11/18 22:34:02 Changed to use logger.
666 }
667 assert(parent[ROOT] == SENTINEL);
668 for (var i = ROOT + 1; i <= N; i++) {
669 assert(parent[i] != SENTINEL);
670 } 671 }
671 672
673 for (var i = 1; i <= dfsNumber; i++) {
Cutch 2016/11/18 20:40:31 assert(() { .... });
rmacnak 2016/11/18 22:34:02 Done.
674 var v = vertex[i];
675 assert(semi[v] != SENTINEL);
676 }
677 assert(parent[1] == SENTINEL);
678 for (var i = 2; i <= dfsNumber; i++) {
679 var v = vertex[i];
680 assert(parent[v] != SENTINEL);
681 }
682
683 if (dfsNumber != N) {
684 // Remove successors of unconnected nodes
685 for (var i = ROOT + 1; i <= N; i++) {
Cutch 2016/11/18 20:40:31 how about we add a: const FIRST_OBJECT = ROOT + 1
rmacnak 2016/11/18 22:34:02 ROOT is the first object.
686 if (parent[i] == SENTINEL) {
687 var startSuccIndex = firstSuccs[i];
688 var limitSuccIndex = firstSuccs[i + 1];
689 for (var succIndex = startSuccIndex;
690 succIndex < limitSuccIndex;
691 succIndex++) {
692 succs[succIndex] = SENTINEL;
693 }
694 }
695 }
696 }
697
698 _Nconnected = dfsNumber;
672 _vertex = vertex; 699 _vertex = vertex;
673 _semi = semi; 700 _semi = semi;
674 _parent = parent; 701 _parent = parent;
675 } 702 }
676 703
677 void _buildPredecessors() { 704 void _buildPredecessors() {
678 var N = _N; 705 var N = _N;
706 var Nconnected = _Nconnected;
679 var E = _E; 707 var E = _E;
680 var firstSuccs = _firstSuccs; 708 var firstSuccs = _firstSuccs;
681 var succs = _succs; 709 var succs = _succs;
682 710
683 // This is first filled with the predecessor counts, then reused to hold the 711 // This is first filled with the predecessor counts, then reused to hold the
684 // offset to the first predecessor (see alias below). 712 // offset to the first predecessor (see alias below).
685 // + 1 because 0 is a sentinel 713 // + 1 because 0 is a sentinel
686 // + 1 so the number of predecessors can be found from the difference with 714 // + 1 so the number of predecessors can be found from the difference with
687 // the next node's offset. 715 // the next node's offset.
688 var numPreds = new Uint32List(N + 2); 716 var numPreds = new Uint32List(N + 2);
689 var preds = new Uint32List(E); 717 var preds = new Uint32List(E);
690 718
691 // Count predecessors of each node. 719 // Count predecessors of each node.
692 for (var succIndex = 0; succIndex < E; succIndex++) { 720 for (var succIndex = 0; succIndex < E; succIndex++) {
693 var succId = succs[succIndex]; 721 var succId = succs[succIndex];
694 numPreds[succId]++; 722 if (succId != SENTINEL) {
723 numPreds[succId]++;
724 }
695 } 725 }
696 726
697 // Assign indices into predecessors array. 727 // Assign indices into predecessors array.
698 var firstPreds = numPreds; // Alias. 728 var firstPreds = numPreds; // Alias.
699 var nextPreds = new Uint32List(N + 1); 729 var nextPreds = new Uint32List(N + 1);
700 var predIndex = 0; 730 var predIndex = 0;
701 for (var i = 1; i <= N; i++) { 731 for (var i = 1; i <= N; i++) {
702 var thisPredIndex = predIndex; 732 var thisPredIndex = predIndex;
703 predIndex += numPreds[i]; 733 predIndex += numPreds[i];
704 firstPreds[i] = thisPredIndex; 734 firstPreds[i] = thisPredIndex;
705 nextPreds[i] = thisPredIndex; 735 nextPreds[i] = thisPredIndex;
706 } 736 }
707 assert(predIndex == E); 737 if (N == Nconnected) {
708 firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. 738 assert(predIndex == E);
739 }
740 firstPreds[N + 1] = predIndex; // Extra entry for cheap boundary detection.
709 741
710 // Fill predecessors array. 742 // Fill predecessors array.
711 for (var i = 1; i <= N; i++) { 743 for (var i = 1; i <= N; i++) {
712 var startSuccIndex = firstSuccs[i]; 744 var startSuccIndex = firstSuccs[i];
713 var limitSuccIndex = firstSuccs[i + 1]; 745 var limitSuccIndex = firstSuccs[i + 1];
714 for (var succIndex = startSuccIndex; 746 for (var succIndex = startSuccIndex;
715 succIndex < limitSuccIndex; 747 succIndex < limitSuccIndex;
716 succIndex++) { 748 succIndex++) {
717 var succId = succs[succIndex]; 749 var succId = succs[succIndex];
718 var predIndex = nextPreds[succId]++; 750 if (succId != SENTINEL) {
719 preds[predIndex] = i; 751 var predIndex = nextPreds[succId]++;
752 preds[predIndex] = i;
753 }
720 } 754 }
721 } 755 }
722 756
723 _firstPreds = firstPreds; 757 _firstPreds = firstPreds;
724 _preds = preds; 758 _preds = preds;
725 } 759 }
726 760
727 static int _eval(int v, Uint32List ancestor, Uint32List semi, 761 static int _eval(int v, Uint32List ancestor, Uint32List semi,
728 Uint32List label, Uint32List stackNode, Uint8List stackState) { 762 Uint32List label, Uint32List stackNode, Uint8List stackState) {
729 if (ancestor[v] == SENTINEL) { 763 if (ancestor[v] == SENTINEL) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 while (s != 0) { 829 while (s != 0) {
796 ancestor[s] = v; 830 ancestor[s] = v;
797 s = child[s]; 831 s = child[s];
798 } 832 }
799 } 833 }
800 834
801 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators 835 // T. Lengauer and R. E. Tarjan. "A Fast Algorithm for Finding Dominators
802 // in a Flowgraph." 836 // in a Flowgraph."
803 void _buildDominators() { 837 void _buildDominators() {
804 var N = _N; 838 var N = _N;
839 var Nconnected = _Nconnected;
805 840
806 var vertex = _vertex; 841 var vertex = _vertex;
807 var semi = _semi; 842 var semi = _semi;
808 var parent = _parent; 843 var parent = _parent;
809 var firstPreds = _firstPreds; 844 var firstPreds = _firstPreds;
810 var preds = _preds; 845 var preds = _preds;
811 846
812 var dom = new Uint32List(N + 1); 847 var dom = new Uint32List(N + 1);
813 848
814 var ancestor = new Uint32List(N + 1); 849 var ancestor = new Uint32List(N + 1);
815 var label = new Uint32List(N + 1); 850 var label = new Uint32List(N + 1);
816 for (var i = 1; i <= N; i++) { 851 for (var i = 1; i <= N; i++) {
817 label[i] = i; 852 label[i] = i;
818 } 853 }
819 var buckets = new List(N + 1); 854 var buckets = new List(N + 1);
820 var child = new Uint32List(N + 1); 855 var child = new Uint32List(N + 1);
821 var size = new Uint32List(N + 1); 856 var size = new Uint32List(N + 1);
822 for (var i = 1; i <= N; i++) { 857 for (var i = 1; i <= N; i++) {
823 size[i] = 1; 858 size[i] = 1;
824 } 859 }
825 var stackNode = new Uint32List(N + 1); 860 var stackNode = new Uint32List(N + 1);
826 var stackState = new Uint8List(N + 1); 861 var stackState = new Uint8List(N + 1);
827 862
828 for (var i = N; i > 1; i--) { 863 for (var i = Nconnected; i > 1; i--) {
829 var w = vertex[i]; 864 var w = vertex[i];
830 assert(w != ROOT); 865 assert(w != ROOT);
831 866
832 // Lengauer & Tarjan Step 2. 867 // Lengauer & Tarjan Step 2.
833 var startPred = firstPreds[w]; 868 var startPred = firstPreds[w];
834 var limitPred = firstPreds[w + 1]; 869 var limitPred = firstPreds[w + 1];
835 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { 870 for (var predIndex = startPred; predIndex < limitPred; predIndex++) {
836 var v = preds[predIndex]; 871 var v = preds[predIndex];
837 var u = _eval(v, ancestor, semi, label, stackNode, stackState); 872 var u = _eval(v, ancestor, semi, label, stackNode, stackState);
838 if (semi[u] < semi[w]) { 873 if (semi[u] < semi[w]) {
(...skipping 18 matching lines...) Expand all
857 for (var v in bucket) { 892 for (var v in bucket) {
858 var u = _eval(v, ancestor, semi, label, stackNode, stackState); 893 var u = _eval(v, ancestor, semi, label, stackNode, stackState);
859 dom[v] = semi[u] < semi[v] ? u : parent[w]; 894 dom[v] = semi[u] < semi[v] ? u : parent[w];
860 } 895 }
861 } 896 }
862 } 897 }
863 for (var i = ROOT; i <= N; i++) { 898 for (var i = ROOT; i <= N; i++) {
864 assert(buckets[i] == null); 899 assert(buckets[i] == null);
865 } 900 }
866 // Lengauer & Tarjan Step 4. 901 // Lengauer & Tarjan Step 4.
867 for (var i = 2; i <= N; i++) { 902 for (var i = 2; i <= Nconnected; i++) {
868 var w = vertex[i]; 903 var w = vertex[i];
869 if (dom[w] != vertex[semi[w]]) { 904 if (dom[w] != vertex[semi[w]]) {
870 dom[w] = dom[dom[w]]; 905 dom[w] = dom[dom[w]];
871 } 906 }
872 } 907 }
873 908
874 _doms = dom; 909 _doms = dom;
875 } 910 }
876 911
877 void _calculateRetainedSizes() { 912 void _calculateRetainedSizes() {
878 var N = _N; 913 var N = _N;
914 var Nconnected = _Nconnected;
879 915
880 var size = 0; 916 var size = 0;
881 var shallowSizes = _shallowSizes; 917 var shallowSizes = _shallowSizes;
882 var vertex = _vertex; 918 var vertex = _vertex;
883 var doms = _doms; 919 var doms = _doms;
884 920
885 // Sum shallow sizes. 921 // Sum shallow sizes.
886 for (var i = ROOT; i < N; i++) { 922 for (var i = 1; i <= Nconnected; i++) {
Cutch 2016/11/18 20:40:31 FIRST_OBJECT
rmacnak 2016/11/18 22:34:02 1 here is a DFS number, not a node index.
887 size += shallowSizes[i]; 923 var v = vertex[i];
924 size += shallowSizes[v];
888 } 925 }
889 926
890 // Start with retained size as shallow size. 927 // Start with retained size as shallow size.
891 var retainedSizes = new Uint32List.fromList(shallowSizes); 928 var retainedSizes = new Uint32List.fromList(shallowSizes);
892 929
893 // In post order (bottom up), add retained size to dominator's retained 930 // In post order (bottom up), add retained size to dominator's retained
894 // size, skipping root. 931 // size, skipping root.
895 for (var i = N; i > 1; i--) { 932 for (var i = Nconnected; i > 1; i--) {
896 var v = vertex[i]; 933 var v = vertex[i];
897 assert(v != ROOT); 934 assert(v != ROOT);
898 retainedSizes[doms[i]] += retainedSizes[i]; 935 retainedSizes[doms[v]] += retainedSizes[v];
899 } 936 }
900 937
938 assert(retainedSizes[ROOT] == size); // Root retains everything.
939
901 _retainedSizes = retainedSizes; 940 _retainedSizes = retainedSizes;
902 _size = size; 941 _size = size;
903 } 942 }
904 943
905 // Build linked lists of the children for each node in the dominator tree. 944 // Build linked lists of the children for each node in the dominator tree.
906 void _linkDominatorChildren() { 945 void _linkDominatorChildren() {
907 var N = _N; 946 var N = _N;
908 var doms = _doms; 947 var doms = _doms;
909 var head = new Uint32List(N + 1); 948 var head = new Uint32List(N + 1);
910 var next = new Uint32List(N + 1); 949 var next = new Uint32List(N + 1);
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1056 1095
1057 // From all the siblings between child and after, take their children, 1096 // From all the siblings between child and after, take their children,
1058 // merge them and given to child. 1097 // merge them and given to child.
1059 mergeChildrenAndSort(child, after); 1098 mergeChildrenAndSort(child, after);
1060 1099
1061 child = after; 1100 child = after;
1062 } 1101 }
1063 } 1102 }
1064 } 1103 }
1065 } 1104 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698