[vm] Reduce peak memory usage of --write_v8_snapshot_profile_to.

Remove unnecessary members, reduce field sizes and reduce initial map capacities.

/usr/bin/time -v gen_snapshot --snapshot-kind=app-aot-elf --write-v8-snapshot-profile-to=... dart2js.dill
Maximum resident set size (kbytes): 1347220 -> 902280 (-33.0%)

TEST=ci
Bug: b/196510517
Change-Id: I2d4dd55ac6db8ccbe9f8a834bab9fe906ba1228d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212269
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2021-09-02 21:46:35 +00:00 committed by commit-bot@chromium.org
parent 0317bffb9e
commit 0c07cd6bc7
3 changed files with 87 additions and 63 deletions

View file

@ -15,7 +15,8 @@ namespace dart {
template <typename KeyValueTrait, typename B, typename Allocator = Zone>
class BaseDirectChainedHashMap : public B {
public:
explicit BaseDirectChainedHashMap(Allocator* allocator)
explicit BaseDirectChainedHashMap(Allocator* allocator,
intptr_t initial_size = kInitialSize)
: array_size_(0),
lists_size_(0),
count_(0),
@ -23,8 +24,9 @@ class BaseDirectChainedHashMap : public B {
lists_(NULL),
free_list_head_(kNil),
allocator_(allocator) {
ResizeLists(kInitialSize);
Resize(kInitialSize);
ASSERT(Utils::IsPowerOfTwo(initial_size));
ResizeLists(initial_size);
Resize(initial_size);
}
BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other);
@ -407,9 +409,12 @@ class DirectChainedHashMap
: BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
explicit DirectChainedHashMap(Zone* zone)
explicit DirectChainedHashMap(
Zone* zone,
intptr_t initial_size = DirectChainedHashMap::kInitialSize)
: BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
ASSERT_NOTNULL(zone)) {}
ASSERT_NOTNULL(zone),
initial_size) {}
// There is a current use of the copy constructor in CSEInstructionMap
// (compiler/backend/redundancy_elimination.cc), so work is needed if we
@ -425,9 +430,11 @@ template <typename KeyValueTrait>
class MallocDirectChainedHashMap
: public BaseDirectChainedHashMap<KeyValueTrait, MallocAllocated, Malloc> {
public:
MallocDirectChainedHashMap()
: BaseDirectChainedHashMap<KeyValueTrait, MallocAllocated, Malloc>(NULL) {
}
MallocDirectChainedHashMap(
intptr_t initial_size = MallocDirectChainedHashMap::kInitialSize)
: BaseDirectChainedHashMap<KeyValueTrait, MallocAllocated, Malloc>(
NULL,
initial_size) {}
// The only use of the copy constructor seems to be in hash_map_test.cc.
// Not disallowing it for now just in case there are other users.
@ -446,8 +453,12 @@ class ZoneDirectChainedHashMap
ZoneDirectChainedHashMap()
: BaseDirectChainedHashMap<KeyValueTrait, ZoneAllocated, Zone>(
ThreadState::Current()->zone()) {}
explicit ZoneDirectChainedHashMap(Zone* zone)
: BaseDirectChainedHashMap<KeyValueTrait, ZoneAllocated, Zone>(zone) {}
explicit ZoneDirectChainedHashMap(
Zone* zone,
intptr_t initial_size = ZoneDirectChainedHashMap::kInitialSize)
: BaseDirectChainedHashMap<KeyValueTrait, ZoneAllocated, Zone>(
zone,
initial_size) {}
private:
DISALLOW_COPY_AND_ASSIGN(ZoneDirectChainedHashMap);

View file

@ -16,6 +16,7 @@ const V8SnapshotProfileWriter::ObjectId
V8SnapshotProfileWriter::V8SnapshotProfileWriter(Zone* zone)
: zone_(zone),
nodes_(zone_),
node_types_(zone_),
edge_types_(zone_),
strings_(zone_),
@ -41,7 +42,7 @@ void V8SnapshotProfileWriter::SetObjectTypeAndName(const ObjectId& object_id,
const intptr_t type_index = node_types_.Add(type);
if (info->type != kInvalidString && info->type != type_index) {
FATAL("Attempting to assign mismatching type %s to node %s", type,
info->ToCString(zone_));
info->ToCString(nullptr, zone_));
}
info->type = type_index;
// Don't overwrite any existing name.
@ -103,26 +104,30 @@ V8SnapshotProfileWriter::NodeInfo* V8SnapshotProfileWriter::EnsureId(
return nodes_.Lookup(object_id);
}
const char* V8SnapshotProfileWriter::NodeInfo::ToCString(Zone* zone) const {
const char* V8SnapshotProfileWriter::NodeInfo::ToCString(
V8SnapshotProfileWriter* profile_writer,
Zone* zone) const {
JSONWriter writer;
WriteDebug(&writer);
WriteDebug(profile_writer, &writer);
return OS::SCreate(zone, "%s", writer.buffer()->buffer());
}
void V8SnapshotProfileWriter::NodeInfo::Write(JSONWriter* writer) const {
void V8SnapshotProfileWriter::NodeInfo::Write(
V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer) const {
ASSERT(id.space() != IdSpace::kInvalid);
if (type == kInvalidString) {
FATAL("No type given for node %s", id.ToCString(profile_writer_->zone_));
FATAL("No type given for node %s", id.ToCString(profile_writer->zone_));
}
writer->PrintValue(type);
if (name != kInvalidString) {
writer->PrintValue(name);
} else {
ASSERT(profile_writer_ != nullptr);
ASSERT(profile_writer != nullptr);
// If we don't already have a name for the node, we lazily create a default
// one. This is safe since the strings table is written out after the nodes.
const intptr_t name = profile_writer_->strings_.AddFormatted(
"Unnamed [%s] (nil)", profile_writer_->node_types_.At(type));
const intptr_t name = profile_writer->strings_.AddFormatted(
"Unnamed [%s] (nil)", profile_writer->node_types_.At(type));
writer->PrintValue(name);
}
id.Write(writer);
@ -130,17 +135,19 @@ void V8SnapshotProfileWriter::NodeInfo::Write(JSONWriter* writer) const {
writer->PrintValue64(edges->Length());
}
void V8SnapshotProfileWriter::NodeInfo::WriteDebug(JSONWriter* writer) const {
void V8SnapshotProfileWriter::NodeInfo::WriteDebug(
V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer) const {
writer->OpenObject();
if (type != kInvalidString) {
writer->PrintProperty("type", profile_writer_->node_types_.At(type));
writer->PrintProperty("type", profile_writer->node_types_.At(type));
}
if (name != kInvalidString) {
writer->PrintProperty("name", profile_writer_->strings_.At(name));
writer->PrintProperty("name", profile_writer->strings_.At(name));
}
id.WriteDebug(writer, "id");
writer->PrintProperty("self_size", self_size);
edges->WriteDebug(writer, "edges");
edges->WriteDebug(profile_writer, writer, "edges");
writer->CloseObject();
}
@ -188,45 +195,52 @@ const char* V8SnapshotProfileWriter::ObjectId::IdSpaceToCString(IdSpace space) {
}
}
const char* V8SnapshotProfileWriter::EdgeMap::ToCString(Zone* zone) const {
const char* V8SnapshotProfileWriter::EdgeMap::ToCString(
V8SnapshotProfileWriter* profile_writer,
Zone* zone) const {
JSONWriter writer;
WriteDebug(&writer);
WriteDebug(profile_writer, &writer);
return OS::SCreate(zone, "%s", writer.buffer()->buffer());
}
void V8SnapshotProfileWriter::EdgeMap::WriteDebug(JSONWriter* writer,
const char* property) const {
void V8SnapshotProfileWriter::EdgeMap::WriteDebug(
V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer,
const char* property) const {
writer->OpenArray(property);
auto edge_it = GetIterator();
while (auto const pair = edge_it.Next()) {
pair->edge.WriteDebug(writer, pair->target);
pair->edge.WriteDebug(profile_writer, writer, pair->target);
}
writer->CloseArray();
}
void V8SnapshotProfileWriter::Edge::Write(JSONWriter* writer,
const ObjectId& target_id) const {
void V8SnapshotProfileWriter::Edge::Write(
V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer,
const ObjectId& target_id) const {
ASSERT(type != Type::kInvalid);
writer->PrintValue64(static_cast<intptr_t>(type));
writer->PrintValue64(name_or_offset);
auto const target = profile_writer_->nodes_.LookupValue(target_id);
auto const target = profile_writer->nodes_.LookupValue(target_id);
writer->PrintValue64(target.offset());
}
void V8SnapshotProfileWriter::Edge::WriteDebug(
V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer,
const ObjectId& target_id) const {
writer->OpenObject();
if (type != Type::kInvalid) {
writer->PrintProperty(
"type", profile_writer_->edge_types_.At(static_cast<intptr_t>(type)));
"type", profile_writer->edge_types_.At(static_cast<intptr_t>(type)));
}
if (type == Type::kProperty) {
writer->PrintProperty("name", profile_writer_->strings_.At(name_or_offset));
writer->PrintProperty("name", profile_writer->strings_.At(name_or_offset));
} else {
writer->PrintProperty64("offset", name_or_offset);
}
auto const target = profile_writer_->nodes_.LookupValue(target_id);
auto const target = profile_writer->nodes_.LookupValue(target_id);
target.id.WriteDebug(writer, "target");
writer->CloseObject();
}
@ -349,14 +363,14 @@ void V8SnapshotProfileWriter::Write(JSONWriter* writer) {
ASSERT(root != nullptr);
intptr_t offset = 0;
root->set_offset(offset);
root->Write(writer);
root->Write(this, writer);
offset += kNumNodeFields;
auto nodes_it = nodes_.GetIterator();
for (auto entry = nodes_it.Next(); entry != nullptr;
entry = nodes_it.Next()) {
if (entry->id == kArtificialRootId) continue;
entry->set_offset(offset);
entry->Write(writer);
entry->Write(this, writer);
offset += kNumNodeFields;
}
writer->CloseArray();
@ -366,7 +380,7 @@ void V8SnapshotProfileWriter::Write(JSONWriter* writer) {
auto write_edges = [&](const NodeInfo& info) {
auto edges_it = info.edges->GetIterator();
while (auto const pair = edges_it.Next()) {
pair->edge.Write(writer, pair->target);
pair->edge.Write(this, writer, pair->target);
}
};
writer->OpenArray("edges");

View file

@ -154,7 +154,7 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
static constexpr intptr_t kNumEdgeFields = 3;
struct Edge {
enum class Type : intptr_t {
enum class Type : int32_t {
kInvalid = -1,
kContext = 0,
kElement = 1,
@ -177,24 +177,22 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
Edge(V8SnapshotProfileWriter* profile_writer,
Type type,
intptr_t name_or_offset)
: type(type),
name_or_offset(name_or_offset),
profile_writer_(profile_writer) {}
: type(type), name_or_offset(name_or_offset) {}
inline bool operator!=(const Edge& other) {
return profile_writer_ != other.profile_writer_ || type != other.type ||
name_or_offset != other.name_or_offset;
return type != other.type || name_or_offset != other.name_or_offset;
}
inline bool operator==(const Edge& other) { return !(*this != other); }
void Write(JSONWriter* writer, const ObjectId& target_id) const;
void WriteDebug(JSONWriter* writer, const ObjectId& target_id) const;
void Write(V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer,
const ObjectId& target_id) const;
void WriteDebug(V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer,
const ObjectId& target_id) const;
Type type;
intptr_t name_or_offset;
private:
V8SnapshotProfileWriter* profile_writer_;
int32_t name_or_offset;
};
struct EdgeToObjectIdMapTrait {
@ -219,10 +217,13 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
struct EdgeMap : public ZoneDirectChainedHashMap<EdgeToObjectIdMapTrait> {
explicit EdgeMap(Zone* zone)
: ZoneDirectChainedHashMap<EdgeToObjectIdMapTrait>(zone) {}
: ZoneDirectChainedHashMap<EdgeToObjectIdMapTrait>(zone, 1) {}
const char* ToCString(Zone* zone) const;
void WriteDebug(JSONWriter* writer, const char* property = nullptr) const;
const char* ToCString(V8SnapshotProfileWriter* profile_writer,
Zone* zone) const;
void WriteDebug(V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer,
const char* property = nullptr) const;
};
struct NodeInfo {
@ -232,16 +233,14 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
intptr_t type = kInvalidString,
intptr_t name = kInvalidString)
: id(id),
type(type),
name(name),
edges(new (profile_writer->zone_) EdgeMap(profile_writer->zone_)),
profile_writer_(profile_writer) {}
type(type),
name(name) {}
inline bool operator!=(const NodeInfo& other) {
return id != other.id || type != other.type || name != other.name ||
self_size != other.self_size || edges != other.edges ||
offset_ != other.offset_ ||
profile_writer_ != other.profile_writer_;
offset_ != other.offset_;
}
inline bool operator==(const NodeInfo& other) { return !(*this != other); }
@ -250,9 +249,12 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
}
bool HasEdge(const Edge& edge) { return edges->HasKey(edge); }
const char* ToCString(Zone* zone) const;
void Write(JSONWriter* writer) const;
void WriteDebug(JSONWriter* writer) const;
const char* ToCString(V8SnapshotProfileWriter* profile_writer,
Zone* zone) const;
void Write(V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer) const;
void WriteDebug(V8SnapshotProfileWriter* profile_writer,
JSONWriter* writer) const;
intptr_t offset() const { return offset_; }
void set_offset(intptr_t offset) {
@ -261,19 +263,16 @@ class V8SnapshotProfileWriter : public ZoneAllocated {
}
ObjectId id;
EdgeMap* edges = nullptr;
intptr_t type = kInvalidString;
intptr_t name = kInvalidString;
intptr_t self_size = 0;
EdgeMap* edges = nullptr;
private:
// Populated during serialization.
intptr_t offset_ = -1;
// 'trace_node_id' isn't supported.
// 'edge_count' is computed on-demand.
// Used for debugging prints and creating default names if none given.
V8SnapshotProfileWriter* profile_writer_ = nullptr;
};
NodeInfo* EnsureId(const ObjectId& object_id);