Commit 6ee83453 authored by Joyee Cheung's avatar Joyee Cheung Committed by Commit Bot

[heap-profiler] Allow embedder to specify edge names

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: https://github.com/nodejs/node/pull/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 <ulan@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54412}
parent 9d5822a8
......@@ -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;
};
......
......@@ -1957,6 +1957,7 @@ class EmbedderGraphImpl : public EmbedderGraph {
struct Edge {
Node* from;
Node* to;
const char* name;
};
class V8NodeImpl : public Node {
......@@ -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_; }
......@@ -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 {
......
......@@ -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();
......@@ -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);
......@@ -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;
};
......
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