f3d587f890
Change-Id: I8144478175e1de103fcf5dc67deafe067ed72570 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/351301 Commit-Queue: Polina Cherkasova <polinach@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com>
207 lines
6.6 KiB
Dart
207 lines
6.6 KiB
Dart
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'package:collection/collection.dart';
|
|
import 'package:test/expect.dart';
|
|
import 'package:test/test.dart';
|
|
import 'package:vm_service/vm_service.dart';
|
|
|
|
import 'common/test_helper.dart';
|
|
|
|
class Foo {
|
|
@pragma('vm:entry-point')
|
|
dynamic left;
|
|
@pragma('vm:entry-point')
|
|
dynamic right;
|
|
}
|
|
|
|
late Foo r;
|
|
|
|
late List lst;
|
|
|
|
Function deepEquality = const DeepCollectionEquality().equals;
|
|
|
|
void script() {
|
|
// Create 3 instances of Foo, with out-degrees
|
|
// 0 (for b), 1 (for a), and 2 (for staticFoo).
|
|
r = Foo();
|
|
final a = Foo();
|
|
final b = Foo();
|
|
r.left = a;
|
|
r.right = b;
|
|
a.left = b;
|
|
|
|
lst = List.filled(2, null);
|
|
lst[0] = lst; // Self-loop.
|
|
// Larger than any other fixed-size list in a fresh heap.
|
|
lst[1] = List.filled(1234569, null);
|
|
}
|
|
|
|
final tests = <IsolateTest>[
|
|
(VmService service, IsolateRef isolate) async {
|
|
// HeapSnapshotGraph serializes.
|
|
final graph = await HeapSnapshotGraph.getSnapshot(service, isolate);
|
|
_verifySerialization(graph);
|
|
},
|
|
(VmService service, IsolateRef isolate) async {
|
|
// Snap shot serializes with opted out information.
|
|
final graph = await HeapSnapshotGraph.getSnapshot(
|
|
service,
|
|
isolate,
|
|
calculateReferrers: true,
|
|
decodeExternalProperties: false,
|
|
decodeIdentityHashCodes: false,
|
|
decodeObjectData: false,
|
|
);
|
|
expect(graph.objects[10].data, isA<HeapSnapshotObjectNoData>());
|
|
expect(graph.objects[10].identityHashCode, 0);
|
|
expect(graph.externalProperties, isEmpty);
|
|
expect(graph.objects[10].referrers, isNotNull);
|
|
_verifySerialization(graph);
|
|
},
|
|
(VmService service, IsolateRef isolate) async {
|
|
// Referrers are calculated by default.
|
|
final snapshotGraph = await HeapSnapshotGraph.getSnapshot(service, isolate);
|
|
expect(snapshotGraph.objects[10].referrers, isNotNull);
|
|
},
|
|
(VmService service, IsolateRef isolate) async {
|
|
// Referrers are not calculated if opted out.
|
|
final snapshotGraph = await HeapSnapshotGraph.getSnapshot(
|
|
service,
|
|
isolate,
|
|
calculateReferrers: false,
|
|
);
|
|
final object = snapshotGraph.objects[10];
|
|
expect(() => object.referrers, throwsStateError);
|
|
},
|
|
(VmService service, IsolateRef isolate) async {
|
|
final snapshotGraph = await HeapSnapshotGraph.getSnapshot(service, isolate);
|
|
|
|
expect(snapshotGraph.name, 'main');
|
|
expect(snapshotGraph.flags, isNotNull);
|
|
expect(snapshotGraph.objects, isNotNull);
|
|
expect(snapshotGraph.objects, isNotEmpty);
|
|
|
|
int actualShallowSize = 0;
|
|
int actualRefCount = 0;
|
|
for (final o in snapshotGraph.objects) {
|
|
// -1 is the CID used by the sentinel.
|
|
expect(o.classId >= -1, isTrue);
|
|
expect(o.data, isNotNull);
|
|
expect(o.references, isNotNull);
|
|
actualShallowSize += o.shallowSize;
|
|
actualRefCount += o.references.length;
|
|
}
|
|
|
|
// Some accounting differences in the VM result in the global shallow size
|
|
// often being greater than the sum of the object shallow sizes.
|
|
expect(snapshotGraph.shallowSize >= actualShallowSize, isTrue);
|
|
expect(snapshotGraph.shallowSize <= snapshotGraph.capacity, isTrue);
|
|
expect(snapshotGraph.referenceCount >= actualRefCount, isTrue);
|
|
|
|
int actualExternalSize = 0;
|
|
expect(snapshotGraph.externalProperties, isNotEmpty);
|
|
for (var e in snapshotGraph.externalProperties) {
|
|
actualExternalSize += e.externalSize;
|
|
expect(e.object >= 0, isTrue);
|
|
expect(e.name, isNotNull);
|
|
}
|
|
expect(snapshotGraph.externalSize, actualExternalSize);
|
|
|
|
expect(snapshotGraph.classes, isNotEmpty);
|
|
for (var c in snapshotGraph.classes) {
|
|
expect(c.name, isNotNull);
|
|
expect(c.libraryName, isNotNull);
|
|
expect(c.libraryUri, isNotNull);
|
|
expect(c.fields, isNotNull);
|
|
}
|
|
|
|
// We have the class "Foo".
|
|
int foosFound = 0;
|
|
int fooClassId = -1;
|
|
for (int i = 0; i < snapshotGraph.classes.length; i++) {
|
|
final HeapSnapshotClass c = snapshotGraph.classes[i];
|
|
if (c.name == 'Foo' &&
|
|
c.libraryUri.toString().endsWith('heap_snapshot_graph_test.dart')) {
|
|
foosFound++;
|
|
fooClassId = i;
|
|
}
|
|
}
|
|
expect(foosFound, equals(1));
|
|
|
|
// It knows about "Foo" objects.
|
|
foosFound = 0;
|
|
for (final o in snapshotGraph.objects) {
|
|
if (o.classId == 0) continue;
|
|
if (o.classId == fooClassId) {
|
|
foosFound++;
|
|
}
|
|
}
|
|
expect(foosFound, equals(3));
|
|
|
|
// Check that we can get another snapshot.
|
|
final snapshotGraph2 =
|
|
await HeapSnapshotGraph.getSnapshot(service, isolate);
|
|
expect(snapshotGraph2.name, 'main');
|
|
},
|
|
];
|
|
|
|
void _verifySerialization(HeapSnapshotGraph graph) {
|
|
final chunks = graph.toChunks();
|
|
final graphCopy = HeapSnapshotGraph.fromChunks(chunks);
|
|
|
|
expect(graphCopy.name, graph.name);
|
|
expect(graphCopy.flags.bitLength, graph.flags.bitLength);
|
|
expect(graphCopy.objects.length, graph.objects.length);
|
|
expect(graphCopy.classes.length, graph.classes.length);
|
|
expect(
|
|
graphCopy.externalProperties.length,
|
|
graph.externalProperties.length,
|
|
);
|
|
expect(graphCopy.externalSize, graph.externalSize);
|
|
expect(graphCopy.shallowSize, graph.shallowSize);
|
|
expect(graphCopy.capacity, graph.capacity);
|
|
expect(graphCopy.referenceCount, graph.referenceCount);
|
|
|
|
for (var i = 0; i < graph.objects.length; i++) {
|
|
_verifyObjectsAreEqual(graph.objects[i], graphCopy.objects[i]);
|
|
}
|
|
|
|
for (var i = 0; i < graph.classes.length; i++) {
|
|
_verifyClassesAreEqual(graph.classes[i], graphCopy.classes[i]);
|
|
}
|
|
}
|
|
|
|
void _verifyObjectsAreEqual(HeapSnapshotObject a, HeapSnapshotObject b) {
|
|
expect(a.classId, b.classId);
|
|
expect(a.shallowSize, b.shallowSize);
|
|
expect(a.data.runtimeType, b.data.runtimeType);
|
|
expect(a.identityHashCode, b.identityHashCode);
|
|
expect(deepEquality(a.references, b.references), true);
|
|
expect(deepEquality(a.referrers, b.referrers), true);
|
|
}
|
|
|
|
void _verifyClassesAreEqual(HeapSnapshotClass a, HeapSnapshotClass b) {
|
|
expect(a.name, b.name);
|
|
expect(a.libraryName, b.libraryName);
|
|
expect(a.libraryUri, b.libraryUri);
|
|
expect(a.fields, hasLength(b.fields.length));
|
|
for (var i = 0; i < a.fields.length; i++) {
|
|
_verifyFieldsAreEqual(a.fields[i], b.fields[i]);
|
|
}
|
|
}
|
|
|
|
void _verifyFieldsAreEqual(HeapSnapshotField a, HeapSnapshotField b) {
|
|
expect(a.name, b.name);
|
|
expect(a.index, b.index);
|
|
expect(a.toString(), b.toString());
|
|
}
|
|
|
|
void main([args = const <String>[]]) => runIsolateTests(
|
|
args,
|
|
tests,
|
|
'heap_snapshot_graph_test.dart',
|
|
testeeBefore: script,
|
|
);
|