mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[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:
parent
0317bffb9e
commit
0c07cd6bc7
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue