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 {
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.) */
Local<String> GetFunctionName() const;
......@@ -200,6 +214,11 @@ class V8_EXPORT CpuProfileNode {
/** Returns id of the node. The id is unique within the tree */
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. */
int GetChildrenCount() const;
......
......@@ -10037,6 +10037,9 @@ unsigned CpuProfileNode::GetNodeId() const {
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 {
return static_cast<int>(
......
......@@ -48,6 +48,48 @@ inline unsigned ProfileNode::function_id() const {
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(); }
} // namespace internal
......
......@@ -73,6 +73,7 @@ const char* const CodeEntry::kProgramEntryName = "(program)";
const char* const CodeEntry::kIdleEntryName = "(idle)";
const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)";
const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)";
const char* const CodeEntry::kRootEntryName = "(root)";
base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type
CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
......@@ -87,6 +88,9 @@ base::LazyDynamicInstance<CodeEntry,
CodeEntry::UnresolvedEntryCreateTrait>::type
CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
base::LazyDynamicInstance<CodeEntry, CodeEntry::RootEntryCreateTrait>::type
CodeEntry::kRootEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() {
return new CodeEntry(CodeEventListener::FUNCTION_TAG,
CodeEntry::kProgramEntryName);
......@@ -107,6 +111,11 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
CodeEntry::kUnresolvedFunctionName);
}
CodeEntry* CodeEntry::RootEntryCreateTrait::Create() {
return new CodeEntry(CodeEventListener::FUNCTION_TAG,
CodeEntry::kRootEntryName);
}
uint32_t CodeEntry::GetHash() const {
uint32_t hash = ComputeUnseededHash(tag());
if (script_id_ != v8::UnboundScript::kNoScriptId) {
......@@ -313,8 +322,9 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
void ProfileNode::Print(int indent) {
int line_number = line_number_ != 0 ? line_number_ : entry_->line_number();
base::OS::Print("%5u %*s %s:%d %d #%d", self_ticks_, indent, "",
entry_->name(), line_number, entry_->script_id(), id());
base::OS::Print("%5u %*s %s:%d %d %d #%d", self_ticks_, indent, "",
entry_->name(), line_number, source_type(),
entry_->script_id(), id());
if (entry_->resource_name()[0] != '\0')
base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
base::OS::Print("\n");
......@@ -355,9 +365,8 @@ class DeleteNodesCallback {
};
ProfileTree::ProfileTree(Isolate* isolate)
: root_entry_(CodeEventListener::FUNCTION_TAG, "(root)"),
next_node_id_(1),
root_(new ProfileNode(this, &root_entry_, nullptr)),
: next_node_id_(1),
root_(new ProfileNode(this, CodeEntry::root_entry(), nullptr)),
isolate_(isolate),
next_function_id_(1) {}
......
......@@ -154,6 +154,7 @@ class CodeEntry {
// Used to represent frames for which we have no reliable way to
// detect function.
V8_EXPORT_PRIVATE static const char* const kUnresolvedFunctionName;
V8_EXPORT_PRIVATE static const char* const kRootEntryName;
V8_INLINE static CodeEntry* program_entry() {
return kProgramEntry.Pointer();
......@@ -163,6 +164,7 @@ class CodeEntry {
V8_INLINE static CodeEntry* unresolved_entry() {
return kUnresolvedEntry.Pointer();
}
V8_INLINE static CodeEntry* root_entry() { return kRootEntry.Pointer(); }
void print() const;
......@@ -191,6 +193,9 @@ class CodeEntry {
struct UnresolvedEntryCreateTrait {
static CodeEntry* Create();
};
struct RootEntryCreateTrait {
static CodeEntry* Create();
};
static base::LazyDynamicInstance<CodeEntry, ProgramEntryCreateTrait>::type
kProgramEntry;
......@@ -200,6 +205,8 @@ class CodeEntry {
kGCEntry;
static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type
kUnresolvedEntry;
static base::LazyDynamicInstance<CodeEntry, RootEntryCreateTrait>::type
kRootEntry;
using TagField = BitField<CodeEventListener::LogEventsAndTags, 0, 8>;
using BuiltinIdField = BitField<Builtins::Name, 8, 22>;
......@@ -253,6 +260,7 @@ class V8_EXPORT_PRIVATE ProfileNode {
int line_number() const {
return line_number_ != 0 ? line_number_ : entry_->line_number();
}
CpuProfileNode::SourceType source_type() const;
unsigned int GetHitLineCount() const {
return static_cast<unsigned int>(line_ticks_.size());
......@@ -336,7 +344,6 @@ class V8_EXPORT_PRIVATE ProfileTree {
std::vector<const ProfileNode*> pending_nodes_;
CodeEntry root_entry_;
unsigned next_node_id_;
ProfileNode* root_;
Isolate* isolate_;
......
......@@ -1898,6 +1898,7 @@ static void CheckFunctionDetails(v8::Isolate* isolate,
CHECK_EQ(line, node->GetLineNumber());
CHECK_EQ(column, node->GetColumnNumber());
CHECK_EQ(parent, node->GetParent());
CHECK_EQ(v8::CpuProfileNode::kScript, node->GetSourceType());
}
TEST(FunctionDetails) {
......
......@@ -758,6 +758,65 @@ TEST(BailoutReason) {
#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 internal
} // 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