OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 part of heap_snapshot; | 5 part of heap_snapshot; |
6 | 6 |
7 class HeapSnapshot implements M.HeapSnapshot { | 7 class HeapSnapshot implements M.HeapSnapshot { |
8 ObjectGraph graph; | 8 ObjectGraph graph; |
9 DateTime timestamp; | 9 DateTime timestamp; |
10 int get objects => graph.vertexCount; | 10 int get objects => graph.vertexCount; |
11 int get references => graph.edgeCount; | 11 int get references => graph.edgeCount; |
12 int get size => graph.size; | 12 int get size => graph.size; |
13 HeapSnapshotDominatorNode dominatorTree; | 13 HeapSnapshotDominatorNode dominatorTree; |
14 List<MergedVertex> classReferences; | 14 List<MergedVertex> classReferences; |
15 | 15 |
16 static Future sleep([Duration duration = const Duration(microseconds: 0)]) { | 16 static Future sleep([Duration duration = const Duration(microseconds: 0)]) { |
17 final Completer completer = new Completer(); | 17 final Completer completer = new Completer(); |
18 new Timer(duration, () => completer.complete() ); | 18 new Timer(duration, () => completer.complete()); |
19 return completer.future; | 19 return completer.future; |
20 } | 20 } |
21 | 21 |
22 Stream<List> loadProgress(S.Isolate isolate, S.RawHeapSnapshot raw) { | 22 Stream<List> loadProgress(S.Isolate isolate, S.RawHeapSnapshot raw) { |
23 final progress = new StreamController<List>.broadcast(); | 23 final progress = new StreamController<List>.broadcast(); |
24 progress.add(['', 0.0]); | 24 progress.add(['', 0.0]); |
25 graph = new ObjectGraph(raw.chunks, raw.count); | 25 graph = new ObjectGraph(raw.chunks, raw.count); |
26 var signal = (String description, double p) { | 26 var signal = (String description, double p) { |
27 progress.add([description, p]); | 27 progress.add([description, p]); |
28 return sleep(); | 28 return sleep(); |
29 }; | 29 }; |
30 (() async { | 30 (() async { |
31 timestamp = new DateTime.now(); | 31 timestamp = new DateTime.now(); |
32 final stream = graph.process(); | 32 final stream = graph.process(); |
33 stream.listen((status) { | 33 stream.listen((status) { |
34 status[1] /= 2.0; | 34 status[1] /= 2.0; |
35 progress.add(status); | 35 progress.add(status); |
36 }); | 36 }); |
37 await stream.last; | 37 await stream.last; |
38 dominatorTree = new HeapSnapshotDominatorNode(isolate, graph.root); | 38 dominatorTree = new HeapSnapshotDominatorNode(isolate, graph.root); |
39 classReferences = await buildMergedVertices(isolate, graph, signal); | 39 classReferences = await buildMergedVertices(isolate, graph, signal); |
40 progress.close(); | 40 progress.close(); |
41 }()); | 41 }()); |
42 return progress.stream; | 42 return progress.stream; |
43 } | 43 } |
44 | 44 |
45 Future<List<MergedVertex>> buildMergedVertices(S.Isolate isolate, | 45 Future<List<MergedVertex>> buildMergedVertices( |
46 ObjectGraph graph, | 46 S.Isolate isolate, ObjectGraph graph, signal) async { |
47 signal) async { | |
48 final cidToMergedVertex = {}; | 47 final cidToMergedVertex = {}; |
49 | 48 |
50 int count = 0; | 49 int count = 0; |
51 final Stopwatch watch = new Stopwatch(); | 50 final Stopwatch watch = new Stopwatch(); |
52 watch.start(); | 51 watch.start(); |
53 var needToUpdate = () { | 52 var needToUpdate = () { |
54 count++; | 53 count++; |
55 if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) { | 54 if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) { |
56 watch.reset(); | 55 watch.reset(); |
57 return true; | 56 return true; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 } | 91 } |
93 edge.count++; | 92 edge.count++; |
94 // An over-estimate if there are multiple references to the same object. | 93 // An over-estimate if there are multiple references to the same object. |
95 edge.shallowSize += vertex2.shallowSize ?? 0; | 94 edge.shallowSize += vertex2.shallowSize ?? 0; |
96 } | 95 } |
97 } | 96 } |
98 return cidToMergedVertex.values.toList(); | 97 return cidToMergedVertex.values.toList(); |
99 } | 98 } |
100 | 99 |
101 List<Future<S.ServiceObject>> getMostRetained(S.Isolate isolate, | 100 List<Future<S.ServiceObject>> getMostRetained(S.Isolate isolate, |
102 {int classId, int limit}) { | 101 {int classId, int limit}) { |
103 var result = []; | 102 var result = []; |
104 for (ObjectVertex v in graph.getMostRetained(classId: classId, | 103 for (ObjectVertex v |
105 limit: limit)) { | 104 in graph.getMostRetained(classId: classId, limit: limit)) { |
106 result.add(isolate.getObjectByAddress(v.address) | 105 result.add( |
107 .then((S.ServiceObject obj) { | 106 isolate.getObjectByAddress(v.address).then((S.ServiceObject obj) { |
108 if (obj is S.HeapObject) { | 107 if (obj is S.HeapObject) { |
109 obj.retainedSize = v.retainedSize; | 108 obj.retainedSize = v.retainedSize; |
110 } else { | 109 } else { |
111 print("${obj.runtimeType} should be a HeapObject"); | 110 print("${obj.runtimeType} should be a HeapObject"); |
112 } | 111 } |
113 return obj; | 112 return obj; |
114 })); | 113 })); |
115 } | 114 } |
116 return result; | 115 return result; |
117 } | 116 } |
118 } | 117 } |
119 | 118 |
120 class HeapSnapshotDominatorNode implements M.HeapSnapshotDominatorNode { | 119 class HeapSnapshotDominatorNode implements M.HeapSnapshotDominatorNode { |
121 final ObjectVertex v; | 120 final ObjectVertex v; |
122 final S.Isolate isolate; | 121 final S.Isolate isolate; |
123 S.HeapObject _preloaded; | 122 S.HeapObject _preloaded; |
124 | 123 |
125 Future<S.HeapObject> get object { | 124 Future<S.HeapObject> get object { |
126 if (_preloaded != null) { | 125 if (_preloaded != null) { |
127 return new Future.value(_preloaded); | 126 return new Future.value(_preloaded); |
128 } else { | 127 } else { |
129 return isolate.getObjectByAddress(v.address).then((S.HeapObject obj) { | 128 return isolate.getObjectByAddress(v.address).then((S.HeapObject obj) { |
130 return _preloaded = obj; | 129 return _preloaded = obj; |
131 }); | 130 }); |
132 } | 131 } |
133 } | 132 } |
| 133 |
134 Iterable<HeapSnapshotDominatorNode> _children; | 134 Iterable<HeapSnapshotDominatorNode> _children; |
135 Iterable<HeapSnapshotDominatorNode> get children { | 135 Iterable<HeapSnapshotDominatorNode> get children { |
136 if (_children != null) { | 136 if (_children != null) { |
137 return _children; | 137 return _children; |
138 } else { | 138 } else { |
139 return _children = new List.unmodifiable( | 139 return _children = |
140 v.dominatorTreeChildren().map((v) { | 140 new List.unmodifiable(v.dominatorTreeChildren().map((v) { |
141 return new HeapSnapshotDominatorNode(isolate, v); | 141 return new HeapSnapshotDominatorNode(isolate, v); |
142 }) | 142 })); |
143 ); | |
144 } | 143 } |
145 } | 144 } |
| 145 |
146 int get retainedSize => v.retainedSize; | 146 int get retainedSize => v.retainedSize; |
147 int get shallowSize => v.shallowSize; | 147 int get shallowSize => v.shallowSize; |
148 | 148 |
149 HeapSnapshotDominatorNode(S.Isolate isolate, ObjectVertex vertex) | 149 HeapSnapshotDominatorNode(S.Isolate isolate, ObjectVertex vertex) |
150 : isolate = isolate, | 150 : isolate = isolate, |
151 v = vertex; | 151 v = vertex; |
152 } | 152 } |
153 | 153 |
154 class MergedEdge { | 154 class MergedEdge { |
155 final MergedVertex sourceVertex; | 155 final MergedVertex sourceVertex; |
156 final MergedVertex targetVertex; | 156 final MergedVertex targetVertex; |
157 int count = 0; | 157 int count = 0; |
158 int shallowSize = 0; | 158 int shallowSize = 0; |
159 int retainedSize = 0; | 159 int retainedSize = 0; |
160 | 160 |
161 MergedEdge(this.sourceVertex, this.targetVertex); | 161 MergedEdge(this.sourceVertex, this.targetVertex); |
(...skipping 11 matching lines...) Expand all Loading... |
173 Map<int, MergedEdge> outgoingEdges = new Map<int, MergedEdge>(); | 173 Map<int, MergedEdge> outgoingEdges = new Map<int, MergedEdge>(); |
174 | 174 |
175 Iterable<HeapSnapshotClassInbound> _inbounds; | 175 Iterable<HeapSnapshotClassInbound> _inbounds; |
176 Iterable<HeapSnapshotClassInbound> get inbounds { | 176 Iterable<HeapSnapshotClassInbound> get inbounds { |
177 if (_inbounds != null) { | 177 if (_inbounds != null) { |
178 return _inbounds; | 178 return _inbounds; |
179 } else { | 179 } else { |
180 // It is important to keep the template. | 180 // It is important to keep the template. |
181 // https://github.com/dart-lang/sdk/issues/27144 | 181 // https://github.com/dart-lang/sdk/issues/27144 |
182 return _inbounds = new List<HeapSnapshotClassInbound>.unmodifiable( | 182 return _inbounds = new List<HeapSnapshotClassInbound>.unmodifiable( |
183 incomingEdges.map((edge) { | 183 incomingEdges.map((edge) { |
184 return new HeapSnapshotClassInbound(this, edge); | 184 return new HeapSnapshotClassInbound(this, edge); |
185 }) | 185 })); |
186 ); | |
187 } | 186 } |
188 } | 187 } |
189 | 188 |
190 Iterable<HeapSnapshotClassOutbound> _outbounds; | 189 Iterable<HeapSnapshotClassOutbound> _outbounds; |
191 Iterable<HeapSnapshotClassOutbound> get outbounds { | 190 Iterable<HeapSnapshotClassOutbound> get outbounds { |
192 if (_outbounds != null) { | 191 if (_outbounds != null) { |
193 return _outbounds; | 192 return _outbounds; |
194 } else { | 193 } else { |
195 // It is important to keep the template. | 194 // It is important to keep the template. |
196 // https://github.com/dart-lang/sdk/issues/27144 | 195 // https://github.com/dart-lang/sdk/issues/27144 |
197 return _outbounds = new List<HeapSnapshotClassOutbound>.unmodifiable( | 196 return _outbounds = new List<HeapSnapshotClassOutbound>.unmodifiable( |
198 outgoingEdges.values.map((edge) { | 197 outgoingEdges.values.map((edge) { |
199 return new HeapSnapshotClassOutbound(this, edge); | 198 return new HeapSnapshotClassOutbound(this, edge); |
200 }) | 199 })); |
201 ); | |
202 } | 200 } |
203 } | 201 } |
204 | 202 |
205 MergedVertex(this.isolate, this.cid); | 203 MergedVertex(this.isolate, this.cid); |
206 } | 204 } |
207 | 205 |
208 class HeapSnapshotClassInbound implements M.HeapSnapshotClassInbound { | 206 class HeapSnapshotClassInbound implements M.HeapSnapshotClassInbound { |
209 final MergedVertex vertex; | 207 final MergedVertex vertex; |
210 final MergedEdge edge; | 208 final MergedEdge edge; |
211 S.Class get source => edge.sourceVertex != vertex ? edge.sourceVertex.clazz | 209 S.Class get source => edge.sourceVertex != vertex |
212 : edge.targetVertex.clazz; | 210 ? edge.sourceVertex.clazz |
| 211 : edge.targetVertex.clazz; |
213 int get count => edge.count; | 212 int get count => edge.count; |
214 int get shallowSize => edge.shallowSize; | 213 int get shallowSize => edge.shallowSize; |
215 int get retainedSize => edge.retainedSize; | 214 int get retainedSize => edge.retainedSize; |
216 | 215 |
217 HeapSnapshotClassInbound(this.vertex, this.edge); | 216 HeapSnapshotClassInbound(this.vertex, this.edge); |
218 } | 217 } |
219 | 218 |
220 class HeapSnapshotClassOutbound implements M.HeapSnapshotClassOutbound { | 219 class HeapSnapshotClassOutbound implements M.HeapSnapshotClassOutbound { |
221 final MergedVertex vertex; | 220 final MergedVertex vertex; |
222 final MergedEdge edge; | 221 final MergedEdge edge; |
223 S.Class get target => edge.sourceVertex != vertex ? edge.sourceVertex.clazz | 222 S.Class get target => edge.sourceVertex != vertex |
224 : edge.targetVertex.clazz; | 223 ? edge.sourceVertex.clazz |
| 224 : edge.targetVertex.clazz; |
225 int get count => edge.count; | 225 int get count => edge.count; |
226 int get shallowSize => edge.shallowSize; | 226 int get shallowSize => edge.shallowSize; |
227 int get retainedSize => edge.retainedSize; | 227 int get retainedSize => edge.retainedSize; |
228 | 228 |
229 HeapSnapshotClassOutbound(this.vertex, this.edge); | 229 HeapSnapshotClassOutbound(this.vertex, this.edge); |
230 } | 230 } |
OLD | NEW |