From 6ee834532d6f924f6057584085fa79b4777c396a Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 12 Jul 2018 15:52:20 +0800 Subject: [PATCH] [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 Reviewed-by: Ulan Degenbaev Cr-Commit-Position: refs/heads/master@{#54412} --- include/v8-profiler.h | 9 ++- src/profiler/heap-snapshot-generator.cc | 14 ++++- test/cctest/test-heap-profiler.cc | 83 +++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/include/v8-profiler.h b/include/v8-profiler.h index a8a9b4833360..b486683c279f 100644 --- a/include/v8-profiler.h +++ b/include/v8-profiler.h @@ -703,11 +703,14 @@ class V8_EXPORT EmbedderGraph { virtual Node* AddNode(std::unique_ptr 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; }; diff --git a/src/profiler/heap-snapshot-generator.cc b/src/profiler/heap-snapshot-generator.cc index a0ef74953243..b51ea0de7e42 100644 --- a/src/profiler/heap-snapshot-generator.cc +++ b/src/profiler/heap-snapshot-generator.cc @@ -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>& nodes() { return nodes_; } const std::vector& 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 { diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index 0f02b0dc1c2b..18203c7725ce 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -112,6 +112,12 @@ static const char* GetName(const v8::HeapGraphNode* node) { ->name(); } +static const char* GetName(const v8::HeapGraphEdge* edge) { + return const_cast( + reinterpret_cast(edge)) + ->name(); +} + static size_t GetSize(const v8::HeapGraphNode* node) { return const_cast(reinterpret_cast(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(new EmbedderNode("EmbedderNodeA", 10))); + Node* embedder_node_B = graph->AddNode( + std::unique_ptr(new EmbedderNode("EmbedderNodeB", 20))); + Node* embedder_node_C = graph->AddNode( + std::unique_ptr(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(env->GetIsolate()); + v8::Local global_object = + v8::Utils::ToLocal(i::Handle( + (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; };