OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 part of heap_snapshot; |
| 6 |
| 7 class HeapSnapshot implements M.HeapSnapshot { |
| 8 ObjectGraph graph; |
| 9 DateTime timestamp; |
| 10 int get objects => graph.vertexCount; |
| 11 int get references => graph.edgeCount; |
| 12 int get size => graph.size; |
| 13 HeapSnapshotDominatorNode dominatorTree; |
| 14 List<MergedVertex> classReferences; |
| 15 |
| 16 static Future sleep([Duration duration = const Duration(microseconds: 0)]) { |
| 17 final Completer completer = new Completer(); |
| 18 new Timer(duration, () => completer.complete() ); |
| 19 return completer.future; |
| 20 } |
| 21 |
| 22 Stream<double> loadProgress(S.Isolate isolate, S.RawHeapSnapshot raw) { |
| 23 final progress = new StreamController<double>.broadcast(); |
| 24 progress.add(0.0); |
| 25 graph = new ObjectGraph(raw.chunks, raw.count); |
| 26 var signal = (double p) { |
| 27 progress.add(p); |
| 28 return sleep(); |
| 29 }; |
| 30 (() async { |
| 31 timestamp = new DateTime.now(); |
| 32 await graph.process(new StreamController.broadcast()); |
| 33 dominatorTree = new HeapSnapshotDominatorNode(isolate, graph.root); |
| 34 progress.add(0.5); |
| 35 classReferences = await buildMergedVertices(isolate, graph, signal); |
| 36 progress.close(); |
| 37 }()); |
| 38 return progress.stream; |
| 39 } |
| 40 |
| 41 Future<List<MergedVertex>> buildMergedVertices(S.Isolate isolate, |
| 42 ObjectGraph graph, |
| 43 signal) async { |
| 44 final cidToMergedVertex = {}; |
| 45 |
| 46 int count = 0; |
| 47 final Stopwatch watch = new Stopwatch(); |
| 48 watch.start(); |
| 49 var needToUpdate = () { |
| 50 count++; |
| 51 if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) { |
| 52 watch.reset(); |
| 53 return true; |
| 54 } |
| 55 return false; |
| 56 }; |
| 57 final length = graph.vertices.length; |
| 58 for (final vertex in graph.vertices) { |
| 59 count++; |
| 60 if (vertex.vmCid == 0) { |
| 61 continue; |
| 62 } |
| 63 if (needToUpdate()) { |
| 64 await signal(count * 100.0 / length); |
| 65 } |
| 66 final cid = vertex.vmCid; |
| 67 MergedVertex source = cidToMergedVertex[cid]; |
| 68 if (source == null) { |
| 69 cidToMergedVertex[cid] = source = new MergedVertex(isolate, cid); |
| 70 } |
| 71 |
| 72 source.instances++; |
| 73 source.shallowSize += vertex.shallowSize ?? 0; |
| 74 |
| 75 for (final vertex2 in vertex.successors) { |
| 76 if (vertex2.vmCid == 0) { |
| 77 continue; |
| 78 } |
| 79 final cid2 = vertex2.vmCid; |
| 80 MergedEdge edge = source.outgoingEdges[cid2]; |
| 81 if (edge == null) { |
| 82 MergedVertex target = cidToMergedVertex[cid2]; |
| 83 if (target == null) { |
| 84 cidToMergedVertex[cid2] = target = new MergedVertex(isolate, cid2); |
| 85 } |
| 86 edge = new MergedEdge(source, target); |
| 87 source.outgoingEdges[cid2] = edge; |
| 88 target.incomingEdges.add(edge); |
| 89 } |
| 90 edge.count++; |
| 91 // An over-estimate if there are multiple references to the same object. |
| 92 edge.shallowSize += vertex2.shallowSize ?? 0; |
| 93 } |
| 94 } |
| 95 return cidToMergedVertex.values.toList(); |
| 96 } |
| 97 |
| 98 List<Future<S.ServiceObject>> getMostRetained(S.Isolate isolate, |
| 99 {int classId, int limit}) { |
| 100 var result = []; |
| 101 for (ObjectVertex v in graph.getMostRetained(classId: classId, |
| 102 limit: limit)) { |
| 103 result.add(isolate.getObjectByAddress(v.address) |
| 104 .then((S.ServiceObject obj) { |
| 105 if (obj is S.HeapObject) { |
| 106 obj.retainedSize = v.retainedSize; |
| 107 } else { |
| 108 print("${obj.runtimeType} should be a HeapObject"); |
| 109 } |
| 110 return obj; |
| 111 })); |
| 112 } |
| 113 return result; |
| 114 } |
| 115 } |
| 116 |
| 117 class HeapSnapshotDominatorNode implements M.HeapSnapshotDominatorNode { |
| 118 final ObjectVertex v; |
| 119 final S.Isolate isolate; |
| 120 S.HeapObject _preloaded; |
| 121 |
| 122 Future<S.HeapObject> get object { |
| 123 if (_preloaded != null) { |
| 124 return new Future.value(_preloaded); |
| 125 } else { |
| 126 return isolate.getObjectByAddress(v.address).then((S.HeapObject obj) { |
| 127 return _preloaded = obj; |
| 128 }); |
| 129 } |
| 130 } |
| 131 Iterable<HeapSnapshotDominatorNode> _children; |
| 132 Iterable<HeapSnapshotDominatorNode> get children { |
| 133 if (_children != null) { |
| 134 return _children; |
| 135 } else { |
| 136 return _children = new List.unmodifiable( |
| 137 v.dominatorTreeChildren().map((v) { |
| 138 return new HeapSnapshotDominatorNode(isolate, v); |
| 139 }) |
| 140 ); |
| 141 } |
| 142 } |
| 143 int get retainedSize => v.retainedSize; |
| 144 int get shallowSize => v.shallowSize; |
| 145 |
| 146 HeapSnapshotDominatorNode(S.Isolate isolate, ObjectVertex vertex) |
| 147 : isolate = isolate, |
| 148 v = vertex; |
| 149 } |
| 150 |
| 151 class MergedEdge { |
| 152 final MergedVertex sourceVertex; |
| 153 final MergedVertex targetVertex; |
| 154 int count = 0; |
| 155 int shallowSize = 0; |
| 156 int retainedSize = 0; |
| 157 |
| 158 MergedEdge(this.sourceVertex, this.targetVertex); |
| 159 } |
| 160 |
| 161 class MergedVertex implements M.HeapSnapshotClassReferences { |
| 162 final int cid; |
| 163 final S.Isolate isolate; |
| 164 S.Class get clazz => isolate.getClassByCid(cid); |
| 165 int instances = 0; |
| 166 int shallowSize = 0; |
| 167 int retainedSize = 0; |
| 168 |
| 169 List<MergedEdge> incomingEdges = new List<MergedEdge>(); |
| 170 Map<int, MergedEdge> outgoingEdges = new Map<int, MergedEdge>(); |
| 171 |
| 172 Iterable<HeapSnapshotClassInbound> _inbounds; |
| 173 Iterable<HeapSnapshotClassInbound> get inbounds { |
| 174 if (_inbounds != null) { |
| 175 return _inbounds; |
| 176 } else { |
| 177 return _inbounds = new List.unmodifiable( |
| 178 incomingEdges.map((edge) { |
| 179 return new HeapSnapshotClassInbound(this, edge); |
| 180 }) |
| 181 ); |
| 182 } |
| 183 } |
| 184 |
| 185 Iterable<HeapSnapshotClassOutbound> _outbounds; |
| 186 Iterable<HeapSnapshotClassOutbound> get outbounds { |
| 187 if (_outbounds != null) { |
| 188 return _outbounds; |
| 189 } else { |
| 190 return _outbounds = new List.unmodifiable( |
| 191 outgoingEdges.values.map((edge) { |
| 192 return new HeapSnapshotClassInbound(this, edge); |
| 193 }) |
| 194 ); |
| 195 } |
| 196 } |
| 197 |
| 198 MergedVertex(this.isolate, this.cid); |
| 199 } |
| 200 |
| 201 class HeapSnapshotClassInbound implements M.HeapSnapshotClassInbound { |
| 202 final MergedVertex vertex; |
| 203 final MergedEdge edge; |
| 204 S.Class get source => edge.sourceVertex != vertex ? edge.sourceVertex.clazz |
| 205 : edge.targetVertex.clazz; |
| 206 int get count => edge.count; |
| 207 int get shallowSize => edge.shallowSize; |
| 208 int get retainedSize => edge.retainedSize; |
| 209 |
| 210 HeapSnapshotClassInbound(this.vertex, this.edge); |
| 211 } |
| 212 |
| 213 class HeapSnapshotClassOutbound implements M.HeapSnapshotClassOutbound { |
| 214 final MergedVertex vertex; |
| 215 final MergedEdge edge; |
| 216 S.Class get target => edge.sourceVertex != vertex ? edge.sourceVertex.clazz |
| 217 : edge.targetVertex.clazz; |
| 218 int get count => edge.count; |
| 219 int get shallowSize => edge.shallowSize; |
| 220 int get retainedSize => edge.retainedSize; |
| 221 |
| 222 HeapSnapshotClassOutbound(this.vertex, this.edge); |
| 223 } |
OLD | NEW |