Skip to content

Commit 5a45050

Browse files
rmacnak-googlecommit-bot@chromium.org
authored andcommitted
[observatory] Flatten the heap snapshot before loading.
This improves the time to deserialize a snapshot. It also doubles the memory needed to receive the snapshot buffer, but the memory high water mark is still computing the dominators. Change-Id: Ib93015cd6cb366dd2ff750da09ddaa3b37159f68 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115010 Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 75374b8 commit 5a45050

File tree

7 files changed

+41
-35
lines changed

7 files changed

+41
-35
lines changed

runtime/observatory/lib/object_graph.dart

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,12 @@ import 'dart:typed_data';
1212
import 'package:logging/logging.dart';
1313

1414
class _ReadStream {
15-
final List<ByteData> _chunks;
16-
int _chunkIndex = 0;
17-
int _byteIndex = 0;
15+
final Uint8List _buffer;
16+
int _position = 0;
1817

19-
_ReadStream(this._chunks);
18+
_ReadStream(this._buffer);
2019

21-
int readByte() {
22-
while (_byteIndex >= _chunks[_chunkIndex].lengthInBytes) {
23-
_chunkIndex++;
24-
_byteIndex = 0;
25-
}
26-
return _chunks[_chunkIndex].getUint8(_byteIndex++);
27-
}
20+
int readByte() => _buffer[_position++];
2821

2922
/// Read one ULEB128 number.
3023
int readUnsigned() {
@@ -420,7 +413,7 @@ abstract class SnapshotGraph {
420413
Iterable<SnapshotClass> get classes;
421414
Iterable<SnapshotObject> get objects;
422415

423-
factory SnapshotGraph(List<ByteData> chunks) => new _SnapshotGraph(chunks);
416+
factory SnapshotGraph(Uint8List encoded) => new _SnapshotGraph(encoded);
424417
Stream<String> process();
425418
}
426419

@@ -439,7 +432,7 @@ const kRootName = "Root";
439432
const kUnknownFieldName = "<unknown>";
440433

441434
class _SnapshotGraph implements SnapshotGraph {
442-
_SnapshotGraph(List<ByteData> chunks) : this._chunks = chunks;
435+
_SnapshotGraph(Uint8List encoded) : this._encoded = encoded;
443436

444437
int get size => _liveShallowSize + _liveExternalSize;
445438
int get shallowSize => _liveShallowSize;
@@ -502,8 +495,8 @@ class _SnapshotGraph implements SnapshotGraph {
502495
(() async {
503496
// We build futures here instead of marking the steps as async to avoid the
504497
// heavy lifting being inside a transformed method.
505-
var stream = new _ReadStream(_chunks);
506-
_chunks = null;
498+
var stream = new _ReadStream(_encoded);
499+
_encoded = null;
507500

508501
controller.add("Loading classes...");
509502
await new Future(() => _readClasses(stream));
@@ -556,7 +549,7 @@ class _SnapshotGraph implements SnapshotGraph {
556549
return controller.stream;
557550
}
558551

559-
List<ByteData> _chunks;
552+
Uint8List _encoded;
560553

561554
int _kStackCid;
562555
int _kFieldCid;

runtime/observatory/lib/service_common.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ abstract class CommonWebSocketVM extends VM {
205205
var dataLength = bytes.lengthInBytes - dataOffset;
206206
var metadata = _utf8Decoder.convert(new Uint8List.view(
207207
bytes.buffer, bytes.offsetInBytes + metadataOffset, metadataLength));
208-
var data = new ByteData.view(
208+
var data = new Uint8List.view(
209209
bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
210210
var map = _parseJSON(metadata);
211211
if (map == null || map['method'] != 'streamNotify') {

runtime/observatory/lib/src/elements/heap_snapshot.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ class HeapSnapshotElement extends CustomElement implements Renderable {
284284
}
285285

286286
_save() async {
287-
var blob = new Blob(_snapshot.chunks, 'application/octet-stream');
287+
var blob = new Blob([_snapshot.encoded], 'application/octet-stream');
288288
var blobUrl = Url.createObjectUrl(blob);
289289
var link = new AnchorElement();
290290
link.href = blobUrl;
@@ -301,10 +301,9 @@ class HeapSnapshotElement extends CustomElement implements Renderable {
301301
var file = input.files[0];
302302
var reader = new FileReader();
303303
reader.onLoad.listen((event) async {
304-
Uint8List blob = reader.result;
305-
var chunks = [new ByteData.view(blob.buffer)];
304+
Uint8List encoded = reader.result;
306305
var snapshot = new S.HeapSnapshot();
307-
await snapshot.loadProgress(null, chunks).last;
306+
await snapshot.loadProgress(null, encoded).last;
308307
_snapshot = snapshot;
309308
selection = null;
310309
mergedSelection = null;

runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ class HeapSnapshot implements M.HeapSnapshot {
1515
HeapSnapshotMergedDominatorNode mergedDominatorTree;
1616
List<SnapshotClass> classes;
1717
SnapshotObject get root => graph.root;
18-
List<ByteData> chunks;
18+
Uint8List encoded;
1919

20-
Stream<String> loadProgress(S.Isolate isolate, List<ByteData> chunks) {
20+
Stream<String> loadProgress(S.Isolate isolate, Uint8List encoded) {
2121
final progress = new StreamController<String>.broadcast();
2222
progress.add('Loading...');
23-
this.chunks = chunks;
24-
graph = new SnapshotGraph(chunks);
23+
this.encoded = encoded;
24+
graph = new SnapshotGraph(encoded);
2525
(() async {
2626
timestamp = new DateTime.now();
2727
final stream = graph.process();

runtime/observatory/lib/src/models/objects/heap_snapshot.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ abstract class HeapSnapshot {
1010
SnapshotObject get root;
1111
HeapSnapshotMergedDominatorNode get mergedDominatorTree;
1212
Iterable<SnapshotClass> get classes;
13-
List<ByteData> get chunks;
13+
Uint8List get encoded;
1414
}
1515

1616
abstract class HeapSnapshotMergedDominatorNode {

runtime/observatory/lib/src/service/object.dart

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
693693
updateFromServiceMap({'name': 'vm', 'type': '@VM'});
694694
}
695695

696-
void postServiceEvent(String streamId, Map response, ByteData data) {
696+
void postServiceEvent(String streamId, Map response, Uint8List data) {
697697
var map = response;
698698
assert(!map.containsKey('_data'));
699699
if (data != null) {
@@ -1461,7 +1461,7 @@ class Isolate extends ServiceObjectOwner implements M.Isolate {
14611461
DartError error;
14621462
StreamController _snapshotFetch;
14631463

1464-
List<ByteData> _chunksInProgress;
1464+
List<Uint8List> _chunksInProgress;
14651465

14661466
List<Thread> get threads => _threads;
14671467
final List<Thread> _threads = new List<Thread>();
@@ -1475,6 +1475,20 @@ class Isolate extends ServiceObjectOwner implements M.Isolate {
14751475
int get numScopedHandles => _numScopedHandles;
14761476
int _numScopedHandles;
14771477

1478+
static Uint8List _flatten(List<Uint8List> chunks) {
1479+
var length = 0;
1480+
for (var chunk in chunks) {
1481+
length += chunk.length;
1482+
}
1483+
var flattened = new Uint8List(length);
1484+
var position = 0;
1485+
for (var chunk in chunks) {
1486+
flattened.setRange(position, position + chunk.length, chunk);
1487+
position += chunk.length;
1488+
}
1489+
return flattened;
1490+
}
1491+
14781492
void _loadHeapSnapshot(ServiceEvent event) {
14791493
if (_snapshotFetch == null || _snapshotFetch.isClosed) {
14801494
// No outstanding snapshot request. Presumably another client asked for a
@@ -1494,11 +1508,11 @@ class Isolate extends ServiceObjectOwner implements M.Isolate {
14941508
return;
14951509
}
14961510

1497-
var loadedChunks = _chunksInProgress;
1498-
_chunksInProgress = null;
1511+
var flattened = _flatten(_chunksInProgress);
1512+
_chunksInProgress = null; // Make chunks GC'able.
14991513

15001514
if (_snapshotFetch != null) {
1501-
_snapshotFetch.add(loadedChunks);
1515+
_snapshotFetch.add(flattened);
15021516
_snapshotFetch.close();
15031517
}
15041518
}
@@ -2091,7 +2105,7 @@ class ServiceEvent extends ServiceObject {
20912105
DartError reloadError;
20922106
bool atAsyncSuspension;
20932107
Instance inspectee;
2094-
ByteData data;
2108+
Uint8List data;
20952109
int count;
20962110
String reason;
20972111
String exceptions;

runtime/observatory/tests/service/echo_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ var tests = <IsolateTest>[
2525
subscription = stream.listen((ServiceEvent event) {
2626
assert(event.kind == '_Echo');
2727
expect(event.data.lengthInBytes, equals(3));
28-
expect(event.data.getUint8(0), equals(0));
29-
expect(event.data.getUint8(1), equals(128));
30-
expect(event.data.getUint8(2), equals(255));
28+
expect(event.data[0], equals(0));
29+
expect(event.data[1], equals(128));
30+
expect(event.data[2], equals(255));
3131
subscription.cancel();
3232
completer.complete();
3333
});

0 commit comments

Comments
 (0)