Commit b00fc8be authored by ulan's avatar ulan Committed by Commit bot

Use std::deque for storing edges and children in heap snapshot.

This patch fixes OOM crash that happens for large heap where
the total size of edges exceeds 2GB, which is the hard limit
for v8::internal::List allocated using tcmalloc.

BUG=chromium:675911

Review-Url: https://codereview.chromium.org/2595003002
Cr-Commit-Position: refs/heads/master@{#42004}
parent a93aab37
...@@ -9549,13 +9549,12 @@ size_t HeapGraphNode::GetShallowSize() const { ...@@ -9549,13 +9549,12 @@ size_t HeapGraphNode::GetShallowSize() const {
int HeapGraphNode::GetChildrenCount() const { int HeapGraphNode::GetChildrenCount() const {
return ToInternal(this)->children().length(); return ToInternal(this)->children_count();
} }
const HeapGraphEdge* HeapGraphNode::GetChild(int index) const { const HeapGraphEdge* HeapGraphNode::GetChild(int index) const {
return reinterpret_cast<const HeapGraphEdge*>( return reinterpret_cast<const HeapGraphEdge*>(ToInternal(this)->child(index));
ToInternal(this)->children()[index]);
} }
......
...@@ -38,13 +38,17 @@ int HeapEntry::set_children_index(int index) { ...@@ -38,13 +38,17 @@ int HeapEntry::set_children_index(int index) {
return next_index; return next_index;
} }
std::deque<HeapGraphEdge*>::iterator HeapEntry::children_begin() {
HeapGraphEdge** HeapEntry::children_arr() {
DCHECK(children_index_ >= 0); DCHECK(children_index_ >= 0);
SLOW_DCHECK(children_index_ < snapshot_->children().length() || SLOW_DCHECK(
(children_index_ == snapshot_->children().length() && children_index_ < static_cast<int>(snapshot_->children().size()) ||
(children_index_ == static_cast<int>(snapshot_->children().size()) &&
children_count_ == 0)); children_count_ == 0));
return &snapshot_->children().first() + children_index_; return snapshot_->children().begin() + children_index_;
}
std::deque<HeapGraphEdge*>::iterator HeapEntry::children_end() {
return children_begin() + children_count_;
} }
......
...@@ -63,7 +63,7 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, ...@@ -63,7 +63,7 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
const char* name, const char* name,
HeapEntry* entry) { HeapEntry* entry) {
HeapGraphEdge edge(type, name, this->index(), entry->index()); HeapGraphEdge edge(type, name, this->index(), entry->index());
snapshot_->edges().Add(edge); snapshot_->edges().push_back(edge);
++children_count_; ++children_count_;
} }
...@@ -72,7 +72,7 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, ...@@ -72,7 +72,7 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
int index, int index,
HeapEntry* entry) { HeapEntry* entry) {
HeapGraphEdge edge(type, index, this->index(), entry->index()); HeapGraphEdge edge(type, index, this->index(), entry->index());
snapshot_->edges().Add(edge); snapshot_->edges().push_back(edge);
++children_count_; ++children_count_;
} }
...@@ -97,9 +97,8 @@ void HeapEntry::Print( ...@@ -97,9 +97,8 @@ void HeapEntry::Print(
base::OS::Print("\"\n"); base::OS::Print("\"\n");
} }
if (--max_depth == 0) return; if (--max_depth == 0) return;
Vector<HeapGraphEdge*> ch = children(); for (auto i = children_begin(); i != children_end(); ++i) {
for (int i = 0; i < ch.length(); ++i) { HeapGraphEdge& edge = **i;
HeapGraphEdge& edge = *ch[i];
const char* edge_prefix = ""; const char* edge_prefix = "";
EmbeddedVector<char, 64> index; EmbeddedVector<char, 64> index;
const char* edge_name = index.start(); const char* edge_name = index.start();
...@@ -270,15 +269,15 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, ...@@ -270,15 +269,15 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
void HeapSnapshot::FillChildren() { void HeapSnapshot::FillChildren() {
DCHECK(children().is_empty()); DCHECK(children().empty());
children().Allocate(edges().length()); children().resize(edges().size());
int children_index = 0; int children_index = 0;
for (int i = 0; i < entries().length(); ++i) { for (int i = 0; i < entries().length(); ++i) {
HeapEntry* entry = &entries()[i]; HeapEntry* entry = &entries()[i];
children_index = entry->set_children_index(children_index); children_index = entry->set_children_index(children_index);
} }
DCHECK(edges().length() == children_index); DCHECK_EQ(edges().size(), static_cast<size_t>(children_index));
for (int i = 0; i < edges().length(); ++i) { for (size_t i = 0; i < edges().size(); ++i) {
HeapGraphEdge* edge = &edges()[i]; HeapGraphEdge* edge = &edges()[i];
edge->ReplaceToIndexWithEntry(this); edge->ReplaceToIndexWithEntry(this);
edge->from()->add_child(edge); edge->from()->add_child(edge);
...@@ -335,12 +334,10 @@ void HeapSnapshot::Print(int max_depth) { ...@@ -335,12 +334,10 @@ void HeapSnapshot::Print(int max_depth) {
size_t HeapSnapshot::RawSnapshotSize() const { size_t HeapSnapshot::RawSnapshotSize() const {
return return sizeof(*this) + GetMemoryUsedByList(entries_) +
sizeof(*this) + edges_.size() * sizeof(decltype(edges_)::value_type) +
GetMemoryUsedByList(entries_) + children_.size() * sizeof(decltype(children_)::value_type) +
GetMemoryUsedByList(edges_) + GetMemoryUsedByList(sorted_entries_);
GetMemoryUsedByList(children_) +
GetMemoryUsedByList(sorted_entries_);
} }
...@@ -2797,8 +2794,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, ...@@ -2797,8 +2794,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
void HeapSnapshotJSONSerializer::SerializeEdges() { void HeapSnapshotJSONSerializer::SerializeEdges() {
List<HeapGraphEdge*>& edges = snapshot_->children(); std::deque<HeapGraphEdge*>& edges = snapshot_->children();
for (int i = 0; i < edges.length(); ++i) { for (size_t i = 0; i < edges.size(); ++i) {
DCHECK(i == 0 || DCHECK(i == 0 ||
edges[i - 1]->from()->index() <= edges[i]->from()->index()); edges[i - 1]->from()->index() <= edges[i]->from()->index());
SerializeEdge(edges[i], i == 0); SerializeEdge(edges[i], i == 0);
...@@ -2916,7 +2913,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { ...@@ -2916,7 +2913,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
writer_->AddString(",\"node_count\":"); writer_->AddString(",\"node_count\":");
writer_->AddNumber(snapshot_->entries().length()); writer_->AddNumber(snapshot_->entries().length());
writer_->AddString(",\"edge_count\":"); writer_->AddString(",\"edge_count\":");
writer_->AddNumber(snapshot_->edges().length()); writer_->AddNumber(static_cast<double>(snapshot_->edges().size()));
writer_->AddString(",\"trace_function_count\":"); writer_->AddString(",\"trace_function_count\":");
uint32_t count = 0; uint32_t count = 0;
AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker(); AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_ #ifndef V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
#define V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_ #define V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
#include <deque>
#include <unordered_map> #include <unordered_map>
#include "include/v8-profiler.h" #include "include/v8-profiler.h"
...@@ -115,10 +116,9 @@ class HeapEntry BASE_EMBEDDED { ...@@ -115,10 +116,9 @@ class HeapEntry BASE_EMBEDDED {
int children_count() const { return children_count_; } int children_count() const { return children_count_; }
INLINE(int set_children_index(int index)); INLINE(int set_children_index(int index));
void add_child(HeapGraphEdge* edge) { void add_child(HeapGraphEdge* edge) {
children_arr()[children_count_++] = edge; *(children_begin() + children_count_++) = edge;
} }
Vector<HeapGraphEdge*> children() { HeapGraphEdge* child(int i) { return *(children_begin() + i); }
return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
INLINE(Isolate* isolate() const); INLINE(Isolate* isolate() const);
void SetIndexedReference( void SetIndexedReference(
...@@ -130,7 +130,8 @@ class HeapEntry BASE_EMBEDDED { ...@@ -130,7 +130,8 @@ class HeapEntry BASE_EMBEDDED {
const char* prefix, const char* edge_name, int max_depth, int indent); const char* prefix, const char* edge_name, int max_depth, int indent);
private: private:
INLINE(HeapGraphEdge** children_arr()); INLINE(std::deque<HeapGraphEdge*>::iterator children_begin());
INLINE(std::deque<HeapGraphEdge*>::iterator children_end());
const char* TypeAsString(); const char* TypeAsString();
unsigned type_: 4; unsigned type_: 4;
...@@ -163,8 +164,8 @@ class HeapSnapshot { ...@@ -163,8 +164,8 @@ class HeapSnapshot {
return &entries_[gc_subroot_indexes_[index]]; return &entries_[gc_subroot_indexes_[index]];
} }
List<HeapEntry>& entries() { return entries_; } List<HeapEntry>& entries() { return entries_; }
List<HeapGraphEdge>& edges() { return edges_; } std::deque<HeapGraphEdge>& edges() { return edges_; }
List<HeapGraphEdge*>& children() { return children_; } std::deque<HeapGraphEdge*>& children() { return children_; }
void RememberLastJSObjectId(); void RememberLastJSObjectId();
SnapshotObjectId max_snapshot_js_object_id() const { SnapshotObjectId max_snapshot_js_object_id() const {
return max_snapshot_js_object_id_; return max_snapshot_js_object_id_;
...@@ -192,8 +193,8 @@ class HeapSnapshot { ...@@ -192,8 +193,8 @@ class HeapSnapshot {
int gc_roots_index_; int gc_roots_index_;
int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags]; int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
List<HeapEntry> entries_; List<HeapEntry> entries_;
List<HeapGraphEdge> edges_; std::deque<HeapGraphEdge> edges_;
List<HeapGraphEdge*> children_; std::deque<HeapGraphEdge*> children_;
List<HeapEntry*> sorted_entries_; List<HeapEntry*> sorted_entries_;
SnapshotObjectId max_snapshot_js_object_id_; SnapshotObjectId max_snapshot_js_object_id_;
......
...@@ -69,10 +69,10 @@ class NamedEntriesDetector { ...@@ -69,10 +69,10 @@ class NamedEntriesDetector {
CheckEntry(root); CheckEntry(root);
while (!list.is_empty()) { while (!list.is_empty()) {
i::HeapEntry* entry = list.RemoveLast(); i::HeapEntry* entry = list.RemoveLast();
i::Vector<i::HeapGraphEdge*> children = entry->children(); for (int i = 0; i < entry->children_count(); ++i) {
for (int i = 0; i < children.length(); ++i) { i::HeapGraphEdge* edge = entry->child(i);
if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue; if (edge->type() == i::HeapGraphEdge::kShortcut) continue;
i::HeapEntry* child = children[i]->to(); i::HeapEntry* child = edge->to();
v8::base::HashMap::Entry* entry = visited.LookupOrInsert( v8::base::HashMap::Entry* entry = visited.LookupOrInsert(
reinterpret_cast<void*>(child), reinterpret_cast<void*>(child),
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child))); static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child)));
...@@ -137,8 +137,8 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) { ...@@ -137,8 +137,8 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) {
reinterpret_cast<const i::HeapSnapshot*>(snapshot)); reinterpret_cast<const i::HeapSnapshot*>(snapshot));
v8::base::HashMap visited; v8::base::HashMap visited;
i::List<i::HeapGraphEdge>& edges = heap_snapshot->edges(); std::deque<i::HeapGraphEdge>& edges = heap_snapshot->edges();
for (int i = 0; i < edges.length(); ++i) { for (size_t i = 0; i < edges.size(); ++i) {
v8::base::HashMap::Entry* entry = visited.LookupOrInsert( v8::base::HashMap::Entry* entry = visited.LookupOrInsert(
reinterpret_cast<void*>(edges[i].to()), reinterpret_cast<void*>(edges[i].to()),
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(edges[i].to()))); static_cast<uint32_t>(reinterpret_cast<uintptr_t>(edges[i].to())));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment