Skip to content

Commit

Permalink
[heap-profiler] Allow embedder to specify edge names
Browse files Browse the repository at this point in the history
This patch adds a variant of EmbedderGraph::AddEdge() which
allows the embedder to specify the name of an edge. The edges
added without name are element edges with auto-incremented indexes
while the edges added with names will be internal edges with
the specified names for more meaningful output in the heap
snapshot.

Refs: nodejs/node#21741
Bug: v8:7938
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I8feefa2cf6911743e24b3b2024e0e849b0c65cd3
Reviewed-on: https://chromium-review.googlesource.com/1133299
Commit-Queue: Ulan Degenbaev <[email protected]>
Reviewed-by: Ulan Degenbaev <[email protected]>
Cr-Commit-Position: refs/heads/master@{#54412}
  • Loading branch information
joyeecheung authored and Commit Bot committed Jul 12, 2018
1 parent 9d5822a commit 6ee8345
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 6 deletions.
9 changes: 6 additions & 3 deletions include/v8-profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,11 +703,14 @@ class V8_EXPORT EmbedderGraph {
virtual Node* AddNode(std::unique_ptr<Node> node) = 0;

/**
* Adds an edge that represents a strong reference from the given node
* |from| to the given node |to|. The nodes must be added to the graph
* Adds an edge that represents a strong reference from the given
* node |from| to the given node |to|. The nodes must be added to the graph
* before calling this function.
*
* If name is nullptr, the edge will have auto-increment indexes, otherwise
* it will be named accordingly.
*/
virtual void AddEdge(Node* from, Node* to) = 0;
virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0;

virtual ~EmbedderGraph() = default;
};
Expand Down
14 changes: 11 additions & 3 deletions src/profiler/heap-snapshot-generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,7 @@ class EmbedderGraphImpl : public EmbedderGraph {
struct Edge {
Node* from;
Node* to;
const char* name;
};

class V8NodeImpl : public Node {
Expand Down Expand Up @@ -1993,7 +1994,9 @@ class EmbedderGraphImpl : public EmbedderGraph {
return result;
}

void AddEdge(Node* from, Node* to) final { edges_.push_back({from, to}); }
void AddEdge(Node* from, Node* to, const char* name) final {
edges_.push_back({from, to, name});
}

const std::vector<std::unique_ptr<Node>>& nodes() { return nodes_; }
const std::vector<Edge>& edges() { return edges_; }
Expand Down Expand Up @@ -2286,8 +2289,13 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
int from_index = from->index();
HeapEntry* to = EntryForEmbedderGraphNode(edge.to);
if (to) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
from_index, to);
if (edge.name == nullptr) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
from_index, to);
} else {
filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index,
edge.name, to);
}
}
}
} else {
Expand Down
83 changes: 83 additions & 0 deletions test/cctest/test-heap-profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ static const char* GetName(const v8::HeapGraphNode* node) {
->name();
}

static const char* GetName(const v8::HeapGraphEdge* edge) {
return const_cast<i::HeapGraphEdge*>(
reinterpret_cast<const i::HeapGraphEdge*>(edge))
->name();
}

static size_t GetSize(const v8::HeapGraphNode* node) {
return const_cast<i::HeapEntry*>(reinterpret_cast<const i::HeapEntry*>(node))
->self_size();
Expand All @@ -128,6 +134,18 @@ static const v8::HeapGraphNode* GetChildByName(const v8::HeapGraphNode* node,
return nullptr;
}

static const v8::HeapGraphEdge* GetEdgeByChildName(
const v8::HeapGraphNode* node, const char* name) {
for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
const v8::HeapGraphEdge* edge = node->GetChild(i);
const v8::HeapGraphNode* child = edge->GetToNode();
if (!strcmp(name, GetName(child))) {
return edge;
}
}
return nullptr;
}

static const v8::HeapGraphNode* GetRootChild(const v8::HeapSnapshot* snapshot,
const char* name) {
return GetChildByName(snapshot->GetRoot(), name);
Expand Down Expand Up @@ -2957,6 +2975,71 @@ TEST(EmbedderGraph) {
CheckEmbedderGraphSnapshot(env->GetIsolate(), snapshot);
}

void BuildEmbedderGraphWithNamedEdges(v8::Isolate* v8_isolate,
v8::EmbedderGraph* graph, void* data) {
using Node = v8::EmbedderGraph::Node;
Node* global_node = graph->V8Node(*global_object_pointer);
Node* embedder_node_A = graph->AddNode(
std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeA", 10)));
Node* embedder_node_B = graph->AddNode(
std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeB", 20)));
Node* embedder_node_C = graph->AddNode(
std::unique_ptr<Node>(new EmbedderNode("EmbedderNodeC", 30)));
graph->AddEdge(global_node, embedder_node_A, "global_to_a");
graph->AddEdge(embedder_node_A, embedder_node_B, "a_to_b");
graph->AddEdge(embedder_node_B, embedder_node_C);
}

void CheckEmbedderGraphWithNamedEdges(v8::Isolate* isolate,
const v8::HeapSnapshot* snapshot) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphEdge* global_to_a =
GetEdgeByChildName(global, "EmbedderNodeA");
CHECK(global_to_a);
CHECK_EQ(v8::HeapGraphEdge::kInternal, global_to_a->GetType());
CHECK(global_to_a->GetName()->IsString());
CHECK_EQ(0, strcmp("global_to_a", GetName(global_to_a)));
const v8::HeapGraphNode* embedder_node_A = global_to_a->GetToNode();
CHECK_EQ(0, strcmp("EmbedderNodeA", GetName(embedder_node_A)));
CHECK_EQ(10, GetSize(embedder_node_A));

const v8::HeapGraphEdge* a_to_b =
GetEdgeByChildName(embedder_node_A, "EmbedderNodeB");
CHECK(a_to_b);
CHECK(a_to_b->GetName()->IsString());
CHECK_EQ(0, strcmp("a_to_b", GetName(a_to_b)));
CHECK_EQ(v8::HeapGraphEdge::kInternal, a_to_b->GetType());
const v8::HeapGraphNode* embedder_node_B = a_to_b->GetToNode();
CHECK_EQ(0, strcmp("EmbedderNodeB", GetName(embedder_node_B)));
CHECK_EQ(20, GetSize(embedder_node_B));

const v8::HeapGraphEdge* b_to_c =
GetEdgeByChildName(embedder_node_B, "EmbedderNodeC");
CHECK(b_to_c);
CHECK(b_to_c->GetName()->IsNumber());
CHECK_EQ(v8::HeapGraphEdge::kElement, b_to_c->GetType());
const v8::HeapGraphNode* embedder_node_C = b_to_c->GetToNode();
CHECK_EQ(0, strcmp("EmbedderNodeC", GetName(embedder_node_C)));
CHECK_EQ(30, GetSize(embedder_node_C));
}

TEST(EmbedderGraphWithNamedEdges) {
i::FLAG_heap_profiler_use_embedder_graph = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
v8::Local<v8::Value> global_object =
v8::Utils::ToLocal(i::Handle<i::JSObject>(
(isolate->context()->native_context()->global_object()), isolate));
global_object_pointer = &global_object;
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
heap_profiler->AddBuildEmbedderGraphCallback(BuildEmbedderGraphWithNamedEdges,
nullptr);
const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
CHECK(ValidateSnapshot(snapshot));
CheckEmbedderGraphWithNamedEdges(env->GetIsolate(), snapshot);
}

struct GraphBuildingContext {
int counter = 0;
};
Expand Down

0 comments on commit 6ee8345

Please sign in to comment.