Commit 8bedd291 authored by Andrew Comminos's avatar Andrew Comminos Committed by Commit Bot

[cpu-profiler] Add SourceType field to CpuProfileNode

Adds the notion of a "source type" to CpuProfileNode instances, hinting
at the underlying source of the function or state that resulted in the
generation of the node.

Bug: v8:9001
Change-Id: Ie14c54d41b99eb02f54b423fa5d939e9d7f63785
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1510576
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarAlexei Filippov <alph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60590}
parent 6116c6b2
...@@ -129,6 +129,20 @@ class V8_EXPORT CpuProfileNode { ...@@ -129,6 +129,20 @@ class V8_EXPORT CpuProfileNode {
unsigned int hit_count; unsigned int hit_count;
}; };
// An annotation hinting at the source of a CpuProfileNode.
enum SourceType {
// User-supplied script with associated resource information.
kScript = 0,
// Native scripts and provided builtins.
kBuiltin = 1,
// Callbacks into native code.
kCallback = 2,
// VM-internal functions or state.
kInternal = 3,
// A node that failed to symbolize.
kUnresolved = 4,
};
/** Returns function name (empty string for anonymous functions.) */ /** Returns function name (empty string for anonymous functions.) */
Local<String> GetFunctionName() const; Local<String> GetFunctionName() const;
...@@ -200,6 +214,11 @@ class V8_EXPORT CpuProfileNode { ...@@ -200,6 +214,11 @@ class V8_EXPORT CpuProfileNode {
/** Returns id of the node. The id is unique within the tree */ /** Returns id of the node. The id is unique within the tree */
unsigned GetNodeId() const; unsigned GetNodeId() const;
/**
* Gets the type of the source which the node was captured from.
*/
SourceType GetSourceType() const;
/** Returns child nodes count of the node. */ /** Returns child nodes count of the node. */
int GetChildrenCount() const; int GetChildrenCount() const;
......
...@@ -10037,6 +10037,9 @@ unsigned CpuProfileNode::GetNodeId() const { ...@@ -10037,6 +10037,9 @@ unsigned CpuProfileNode::GetNodeId() const {
return reinterpret_cast<const i::ProfileNode*>(this)->id(); return reinterpret_cast<const i::ProfileNode*>(this)->id();
} }
CpuProfileNode::SourceType CpuProfileNode::GetSourceType() const {
return reinterpret_cast<const i::ProfileNode*>(this)->source_type();
}
int CpuProfileNode::GetChildrenCount() const { int CpuProfileNode::GetChildrenCount() const {
return static_cast<int>( return static_cast<int>(
......
...@@ -48,6 +48,48 @@ inline unsigned ProfileNode::function_id() const { ...@@ -48,6 +48,48 @@ inline unsigned ProfileNode::function_id() const {
return tree_->GetFunctionId(this); return tree_->GetFunctionId(this);
} }
inline CpuProfileNode::SourceType ProfileNode::source_type() const {
// Handle metadata and VM state code entry types.
if (entry_ == CodeEntry::program_entry() ||
entry_ == CodeEntry::idle_entry() || entry_ == CodeEntry::gc_entry() ||
entry_ == CodeEntry::root_entry()) {
return CpuProfileNode::kInternal;
}
if (entry_ == CodeEntry::unresolved_entry())
return CpuProfileNode::kUnresolved;
// Otherwise, resolve based on logger tag.
switch (entry_->tag()) {
case CodeEventListener::EVAL_TAG:
case CodeEventListener::SCRIPT_TAG:
case CodeEventListener::LAZY_COMPILE_TAG:
case CodeEventListener::FUNCTION_TAG:
case CodeEventListener::INTERPRETED_FUNCTION_TAG:
return CpuProfileNode::kScript;
case CodeEventListener::BUILTIN_TAG:
case CodeEventListener::HANDLER_TAG:
case CodeEventListener::BYTECODE_HANDLER_TAG:
case CodeEventListener::NATIVE_FUNCTION_TAG:
case CodeEventListener::NATIVE_SCRIPT_TAG:
case CodeEventListener::NATIVE_LAZY_COMPILE_TAG:
return CpuProfileNode::kBuiltin;
case CodeEventListener::CALLBACK_TAG:
return CpuProfileNode::kCallback;
case CodeEventListener::REG_EXP_TAG:
case CodeEventListener::STUB_TAG:
case CodeEventListener::CODE_CREATION_EVENT:
case CodeEventListener::CODE_DISABLE_OPT_EVENT:
case CodeEventListener::CODE_MOVE_EVENT:
case CodeEventListener::CODE_DELETE_EVENT:
case CodeEventListener::CODE_MOVING_GC:
case CodeEventListener::SHARED_FUNC_MOVE_EVENT:
case CodeEventListener::SNAPSHOT_CODE_NAME_EVENT:
case CodeEventListener::TICK_EVENT:
case CodeEventListener::NUMBER_OF_LOG_EVENTS:
return CpuProfileNode::kInternal;
}
} // namespace internal
inline Isolate* ProfileNode::isolate() const { return tree_->isolate(); } inline Isolate* ProfileNode::isolate() const { return tree_->isolate(); }
} // namespace internal } // namespace internal
......
...@@ -73,6 +73,7 @@ const char* const CodeEntry::kProgramEntryName = "(program)"; ...@@ -73,6 +73,7 @@ const char* const CodeEntry::kProgramEntryName = "(program)";
const char* const CodeEntry::kIdleEntryName = "(idle)"; const char* const CodeEntry::kIdleEntryName = "(idle)";
const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)"; const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)";
const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)"; const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)";
const char* const CodeEntry::kRootEntryName = "(root)";
base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type
CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
...@@ -87,6 +88,9 @@ base::LazyDynamicInstance<CodeEntry, ...@@ -87,6 +88,9 @@ base::LazyDynamicInstance<CodeEntry,
CodeEntry::UnresolvedEntryCreateTrait>::type CodeEntry::UnresolvedEntryCreateTrait>::type
CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
base::LazyDynamicInstance<CodeEntry, CodeEntry::RootEntryCreateTrait>::type
CodeEntry::kRootEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() { CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() {
return new CodeEntry(CodeEventListener::FUNCTION_TAG, return new CodeEntry(CodeEventListener::FUNCTION_TAG,
CodeEntry::kProgramEntryName); CodeEntry::kProgramEntryName);
...@@ -107,6 +111,11 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() { ...@@ -107,6 +111,11 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
CodeEntry::kUnresolvedFunctionName); CodeEntry::kUnresolvedFunctionName);
} }
CodeEntry* CodeEntry::RootEntryCreateTrait::Create() {
return new CodeEntry(CodeEventListener::FUNCTION_TAG,
CodeEntry::kRootEntryName);
}
uint32_t CodeEntry::GetHash() const { uint32_t CodeEntry::GetHash() const {
uint32_t hash = ComputeUnseededHash(tag()); uint32_t hash = ComputeUnseededHash(tag());
if (script_id_ != v8::UnboundScript::kNoScriptId) { if (script_id_ != v8::UnboundScript::kNoScriptId) {
...@@ -313,8 +322,9 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries, ...@@ -313,8 +322,9 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
void ProfileNode::Print(int indent) { void ProfileNode::Print(int indent) {
int line_number = line_number_ != 0 ? line_number_ : entry_->line_number(); int line_number = line_number_ != 0 ? line_number_ : entry_->line_number();
base::OS::Print("%5u %*s %s:%d %d #%d", self_ticks_, indent, "", base::OS::Print("%5u %*s %s:%d %d %d #%d", self_ticks_, indent, "",
entry_->name(), line_number, entry_->script_id(), id()); entry_->name(), line_number, source_type(),
entry_->script_id(), id());
if (entry_->resource_name()[0] != '\0') if (entry_->resource_name()[0] != '\0')
base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
base::OS::Print("\n"); base::OS::Print("\n");
...@@ -355,9 +365,8 @@ class DeleteNodesCallback { ...@@ -355,9 +365,8 @@ class DeleteNodesCallback {
}; };
ProfileTree::ProfileTree(Isolate* isolate) ProfileTree::ProfileTree(Isolate* isolate)
: root_entry_(CodeEventListener::FUNCTION_TAG, "(root)"), : next_node_id_(1),
next_node_id_(1), root_(new ProfileNode(this, CodeEntry::root_entry(), nullptr)),
root_(new ProfileNode(this, &root_entry_, nullptr)),
isolate_(isolate), isolate_(isolate),
next_function_id_(1) {} next_function_id_(1) {}
......
...@@ -154,6 +154,7 @@ class CodeEntry { ...@@ -154,6 +154,7 @@ class CodeEntry {
// Used to represent frames for which we have no reliable way to // Used to represent frames for which we have no reliable way to
// detect function. // detect function.
V8_EXPORT_PRIVATE static const char* const kUnresolvedFunctionName; V8_EXPORT_PRIVATE static const char* const kUnresolvedFunctionName;
V8_EXPORT_PRIVATE static const char* const kRootEntryName;
V8_INLINE static CodeEntry* program_entry() { V8_INLINE static CodeEntry* program_entry() {
return kProgramEntry.Pointer(); return kProgramEntry.Pointer();
...@@ -163,6 +164,7 @@ class CodeEntry { ...@@ -163,6 +164,7 @@ class CodeEntry {
V8_INLINE static CodeEntry* unresolved_entry() { V8_INLINE static CodeEntry* unresolved_entry() {
return kUnresolvedEntry.Pointer(); return kUnresolvedEntry.Pointer();
} }
V8_INLINE static CodeEntry* root_entry() { return kRootEntry.Pointer(); }
void print() const; void print() const;
...@@ -191,6 +193,9 @@ class CodeEntry { ...@@ -191,6 +193,9 @@ class CodeEntry {
struct UnresolvedEntryCreateTrait { struct UnresolvedEntryCreateTrait {
static CodeEntry* Create(); static CodeEntry* Create();
}; };
struct RootEntryCreateTrait {
static CodeEntry* Create();
};
static base::LazyDynamicInstance<CodeEntry, ProgramEntryCreateTrait>::type static base::LazyDynamicInstance<CodeEntry, ProgramEntryCreateTrait>::type
kProgramEntry; kProgramEntry;
...@@ -200,6 +205,8 @@ class CodeEntry { ...@@ -200,6 +205,8 @@ class CodeEntry {
kGCEntry; kGCEntry;
static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type
kUnresolvedEntry; kUnresolvedEntry;
static base::LazyDynamicInstance<CodeEntry, RootEntryCreateTrait>::type
kRootEntry;
using TagField = BitField<CodeEventListener::LogEventsAndTags, 0, 8>; using TagField = BitField<CodeEventListener::LogEventsAndTags, 0, 8>;
using BuiltinIdField = BitField<Builtins::Name, 8, 22>; using BuiltinIdField = BitField<Builtins::Name, 8, 22>;
...@@ -253,6 +260,7 @@ class V8_EXPORT_PRIVATE ProfileNode { ...@@ -253,6 +260,7 @@ class V8_EXPORT_PRIVATE ProfileNode {
int line_number() const { int line_number() const {
return line_number_ != 0 ? line_number_ : entry_->line_number(); return line_number_ != 0 ? line_number_ : entry_->line_number();
} }
CpuProfileNode::SourceType source_type() const;
unsigned int GetHitLineCount() const { unsigned int GetHitLineCount() const {
return static_cast<unsigned int>(line_ticks_.size()); return static_cast<unsigned int>(line_ticks_.size());
...@@ -336,7 +344,6 @@ class V8_EXPORT_PRIVATE ProfileTree { ...@@ -336,7 +344,6 @@ class V8_EXPORT_PRIVATE ProfileTree {
std::vector<const ProfileNode*> pending_nodes_; std::vector<const ProfileNode*> pending_nodes_;
CodeEntry root_entry_;
unsigned next_node_id_; unsigned next_node_id_;
ProfileNode* root_; ProfileNode* root_;
Isolate* isolate_; Isolate* isolate_;
......
...@@ -1898,6 +1898,7 @@ static void CheckFunctionDetails(v8::Isolate* isolate, ...@@ -1898,6 +1898,7 @@ static void CheckFunctionDetails(v8::Isolate* isolate,
CHECK_EQ(line, node->GetLineNumber()); CHECK_EQ(line, node->GetLineNumber());
CHECK_EQ(column, node->GetColumnNumber()); CHECK_EQ(column, node->GetColumnNumber());
CHECK_EQ(parent, node->GetParent()); CHECK_EQ(parent, node->GetParent());
CHECK_EQ(v8::CpuProfileNode::kScript, node->GetSourceType());
} }
TEST(FunctionDetails) { TEST(FunctionDetails) {
......
...@@ -758,6 +758,65 @@ TEST(BailoutReason) { ...@@ -758,6 +758,65 @@ TEST(BailoutReason) {
#endif // V8_LITE_MODE #endif // V8_LITE_MODE
} }
TEST(NodeSourceTypes) {
ProfileTree tree(CcTest::i_isolate());
CodeEntry function_entry(CodeEventListener::FUNCTION_TAG, "function");
tree.AddPathFromEnd({&function_entry});
CodeEntry builtin_entry(CodeEventListener::BUILTIN_TAG, "builtin");
tree.AddPathFromEnd({&builtin_entry});
CodeEntry callback_entry(CodeEventListener::CALLBACK_TAG, "callback");
tree.AddPathFromEnd({&callback_entry});
CodeEntry regex_entry(CodeEventListener::REG_EXP_TAG, "regex");
tree.AddPathFromEnd({&regex_entry});
CodeEntry stub_entry(CodeEventListener::STUB_TAG, "stub");
tree.AddPathFromEnd({&stub_entry});
tree.AddPathFromEnd({CodeEntry::gc_entry()});
tree.AddPathFromEnd({CodeEntry::idle_entry()});
tree.AddPathFromEnd({CodeEntry::program_entry()});
tree.AddPathFromEnd({CodeEntry::unresolved_entry()});
auto* root = tree.root();
CHECK(root);
CHECK_EQ(root->source_type(), v8::CpuProfileNode::kInternal);
auto* function_node = PickChild(root, "function");
CHECK(function_node);
CHECK_EQ(function_node->source_type(), v8::CpuProfileNode::kScript);
auto* builtin_node = PickChild(root, "builtin");
CHECK(builtin_node);
CHECK_EQ(builtin_node->source_type(), v8::CpuProfileNode::kBuiltin);
auto* callback_node = PickChild(root, "callback");
CHECK(callback_node);
CHECK_EQ(callback_node->source_type(), v8::CpuProfileNode::kCallback);
auto* regex_node = PickChild(root, "regex");
CHECK(regex_node);
CHECK_EQ(regex_node->source_type(), v8::CpuProfileNode::kInternal);
auto* stub_node = PickChild(root, "stub");
CHECK(stub_node);
CHECK_EQ(stub_node->source_type(), v8::CpuProfileNode::kInternal);
auto* gc_node = PickChild(root, "(garbage collector)");
CHECK(gc_node);
CHECK_EQ(gc_node->source_type(), v8::CpuProfileNode::kInternal);
auto* idle_node = PickChild(root, "(idle)");
CHECK(idle_node);
CHECK_EQ(idle_node->source_type(), v8::CpuProfileNode::kInternal);
auto* program_node = PickChild(root, "(program)");
CHECK(program_node);
CHECK_EQ(program_node->source_type(), v8::CpuProfileNode::kInternal);
auto* unresolved_node = PickChild(root, "(unresolved function)");
CHECK(unresolved_node);
CHECK_EQ(unresolved_node->source_type(), v8::CpuProfileNode::kUnresolved);
}
} // namespace test_profile_generator } // namespace test_profile_generator
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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