[vm/aot] Update serializer for V8's "snapshot profile" format

Fixes https://github.com/dart-lang/sdk/issues/37183
Addresses https://github.com/dart-lang/sdk/issues/37126

Change-Id: I1c1e516ac2bcc45e46059f4439f16aaee6d824fe
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105302
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Samir Jindel
2019-06-06 19:54:12 +00:00
parent c130384c71
commit c4541e63f8
5 changed files with 68 additions and 12 deletions
+30 -1
View File
@@ -85,9 +85,37 @@ class V8SnapshotProfile extends Graph<int> {
Expect.equals(snapshot["node_count"], _parseNodes(top["nodes"]));
Expect.equals(snapshot["edge_count"], _parseEdges(top["edges"]));
_verifyRoot();
_calculateFromEdges();
}
void _verifyRoot() {
// HeapSnapshotWorker.HeapSnapshot.calculateDistances (from HeapSnapshot.js)
// assumes that the root does not have more than one edge to any other node
// (most likely an oversight).
final Set<int> roots = <int>{};
for (final edge in _toEdges[root]) {
final int to = edge.nodeOffset;
Expect.isTrue(!roots.contains(to));
roots.add(to);
}
// Check that all nodes are reachable from the root (offset 0).
final Set<int> enqueued = {root};
final dfs = <int>[root];
while (!dfs.isEmpty) {
final next = dfs.removeLast();
for (final edge in _toEdges[next]) {
if (!enqueued.contains(edge.nodeOffset)) {
enqueued.add(edge.nodeOffset);
dfs.add(edge.nodeOffset);
}
}
}
Expect.equals(enqueued.length, nodeCount);
}
void _parseMetadata(Map meta) {
final List nodeFields = meta["node_fields"];
nodeFields.forEach(_nodeFields.add);
@@ -160,7 +188,8 @@ class V8SnapshotProfile extends Graph<int> {
final int nameOrIndex = edges[edgeOffset + nameOrIndexIndex];
if (_edgeTypes[type] == "property") {
Expect.isTrue(0 <= nameOrIndex && nameOrIndex < _strings.length);
} else if (_edgeTypes[type] == "element") {
} else if (_edgeTypes[type] == "element" ||
_edgeTypes[type] == "context") {
Expect.isTrue(nameOrIndex >= 0);
}
@@ -149,6 +149,11 @@ testMacros(String sdkRoot) async {
match = matchComplete(field, line);
if (match != null && currentClass != null) {
if (fields[currentClass] == null) {
hasMissingFields = true;
print("$currentClass is missing entirely.");
continue;
}
if (!fields[currentClass].contains(match.group(2))) {
hasMissingFields = true;
print("$currentClass is missing ${match.group(2)}.");
+8 -1
View File
@@ -109,6 +109,7 @@ namespace dart {
F(Bytecode, function_) \
F(Bytecode, exception_handlers_) \
F(Bytecode, pc_descriptors_) \
F(Bytecode, closures_) \
F(ExceptionHandlers, handled_types_data_) \
F(Context, parent_) \
F(SingleTargetCache, target_) \
@@ -191,7 +192,13 @@ namespace dart {
F(Pointer, type_arguments_) \
F(Pointer, c_memory_address_) \
F(DynamicLibrary, handle_) \
F(FfiTrampolineData, signature_type_)
F(FfiTrampolineData, signature_type_) \
F(FfiTrampolineData, c_signature_) \
F(FfiTrampolineData, callback_target_) \
F(TypedDataBase, data_) \
F(TypedDataBase, length_) \
F(TypedDataView, typed_data_) \
F(TypedDataView, offset_in_bytes_)
OffsetsTable::OffsetsTable(Zone* zone) : cached_offsets_(zone) {
for (intptr_t i = 0; offsets_table[i].class_id != -1; ++i) {
+18 -9
View File
@@ -23,7 +23,7 @@ V8SnapshotProfileWriter::V8SnapshotProfileWriter(Zone* zone)
node_types_(zone_),
edge_types_(zone_),
strings_(zone),
roots_(zone_, 100) {
roots_(zone_) {
node_types_.Insert({"Unknown", kUnknown});
node_types_.Insert({"ArtificialRoot", kArtificialRoot});
@@ -128,7 +128,7 @@ void V8SnapshotProfileWriter::WriteNodeInfo(JSONWriter* writer,
// The artificial root has 'nullptr' edges, it actually points to all the
// roots.
writer->PrintValue64(info.edges != nullptr ? info.edges->length()
: roots_.length());
: roots_.Size());
writer->PrintNewline();
}
@@ -142,7 +142,15 @@ void V8SnapshotProfileWriter::WriteEdgeInfo(JSONWriter* writer,
void V8SnapshotProfileWriter::AddRoot(ObjectId object_id) {
EnsureId(object_id);
roots_.Add(object_id);
// HeapSnapshotWorker.HeapSnapshot.calculateDistances (from HeapSnapshot.js)
// assumes that the root does not have more than one edge to any other node
// (most likely an oversight).
if (roots_.HasKey(object_id)) return;
ObjectIdToNodeInfoTraits::Pair pair;
pair.key = object_id;
pair.value = NodeInfo{0, 0, object_id, 0, nullptr, 0};
roots_.Insert(pair);
}
void V8SnapshotProfileWriter::WriteStringsTable(
@@ -210,7 +218,7 @@ void V8SnapshotProfileWriter::Write(JSONWriter* writer) {
writer->PrintProperty64("node_count",
nodes_.Size() + 1 /* artificial root */);
writer->PrintProperty64("edge_count", edge_count_ + roots_.length());
writer->PrintProperty64("edge_count", edge_count_ + roots_.Size());
}
writer->CloseObject();
@@ -234,13 +242,14 @@ void V8SnapshotProfileWriter::Write(JSONWriter* writer) {
writer->OpenArray("edges");
// Write references from the artificial root to the actual roots.
for (intptr_t i = 0; i < roots_.length(); ++i) {
WriteEdgeInfo(writer, {kElement, i, roots_[i]});
ObjectIdToNodeInfoTraits::Pair* entry = nullptr;
auto roots_it = roots_.GetIterator();
for (int i = 0; (entry = roots_it.Next()) != nullptr; ++i) {
WriteEdgeInfo(writer, {kElement, i, entry->key});
}
ObjectIdToNodeInfoTraits::Pair* entry = nullptr;
auto it = nodes_.GetIterator();
while ((entry = it.Next()) != nullptr) {
auto nodes_it = nodes_.GetIterator();
while ((entry = nodes_it.Next()) != nullptr) {
for (intptr_t i = 0; i < entry->value.edges->length(); ++i) {
WriteEdgeInfo(writer, entry->value.edges->At(i));
}
+7 -1
View File
@@ -10,6 +10,7 @@
#include "platform/assert.h"
#include "vm/allocation.h"
#include "vm/hash_map.h"
#include "vm/hash_table.h"
#include "vm/json_writer.h"
#include "vm/object.h"
@@ -201,7 +202,12 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
DirectChainedHashMap<StringToIntMapTraits> node_types_;
DirectChainedHashMap<StringToIntMapTraits> edge_types_;
DirectChainedHashMap<StringToIntMapTraits> strings_;
ZoneGrowableArray<ObjectId> roots_;
// We don't have a zone-allocated hash set, so we just re-use the type for
// nodes_ even though we don't need to access the node info (and fill it with
// dummy values).
DirectChainedHashMap<ObjectIdToNodeInfoTraits> roots_;
size_t edge_count_ = 0;
#endif
};