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

View file

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

View file

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