Commit ecae80cd authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[cpu-profiler] Add a new profiling mode with a more detailed call tree.

The current profiling mode (called kLeafNodeLineNumbers in this CL)
produces a tree, with each node representing a stack frame that is seen
in one or more samples taken during profiling. These nodes refer to a
particular function in a stack trace, but not to a particular line or
callsite within that function.

This CL adds a new more (called kCallerLineNumbers) which produces a
different profile tree, where each stack trace seen during profiling,
including the line number, has a unique path in the tree.

The profile tree was previously keyed on CodeEntry*. Now it is keyed on
the pair of CodeEntry* and line_number, meaning it has distinct nodes
for those combinations which exist, and each distinct stack trace that
was sampled is represented in the tree.

For optimized code where we have inline frames, there are no line
numbers for the inline frames in the stack trace, causing duplicate
branches in the tree with kNoLineNumberInfo as the reported line number.
This will be addressed in follow-ups.

Bug: v8:7018
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I512e221508f5b50ec028306d212263b514a9fb24
Reviewed-on: https://chromium-review.googlesource.com/1013493
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53298}
parent 2ecd52ff
...@@ -277,6 +277,16 @@ class V8_EXPORT CpuProfile { ...@@ -277,6 +277,16 @@ class V8_EXPORT CpuProfile {
void Delete(); void Delete();
}; };
enum CpuProfilingMode {
// In the resulting CpuProfile tree, intermediate nodes in a stack trace
// (from the root to a leaf) will have line numbers that point to the start
// line of the function, rather than the line of the callsite of the child.
kLeafNodeLineNumbers,
// In the resulting CpuProfile tree, nodes are separated based on the line
// number of their callsite in their parent.
kCallerLineNumbers,
};
/** /**
* Interface for controlling CPU profiling. Instance of the * Interface for controlling CPU profiling. Instance of the
* profiler can be created using v8::CpuProfiler::New method. * profiler can be created using v8::CpuProfiler::New method.
...@@ -320,6 +330,13 @@ class V8_EXPORT CpuProfiler { ...@@ -320,6 +330,13 @@ class V8_EXPORT CpuProfiler {
* |record_samples| parameter controls whether individual samples should * |record_samples| parameter controls whether individual samples should
* be recorded in addition to the aggregated tree. * be recorded in addition to the aggregated tree.
*/ */
void StartProfiling(Local<String> title, CpuProfilingMode mode,
bool record_samples = false);
/**
* The same as StartProfiling above, but the CpuProfilingMode defaults to
* kLeafNodeLineNumbers mode, which was the previous default behavior of the
* profiler.
*/
void StartProfiling(Local<String> title, bool record_samples = false); void StartProfiling(Local<String> title, bool record_samples = false);
/** /**
......
...@@ -9949,7 +9949,7 @@ const char* CpuProfileNode::GetScriptResourceNameStr() const { ...@@ -9949,7 +9949,7 @@ const char* CpuProfileNode::GetScriptResourceNameStr() const {
} }
int CpuProfileNode::GetLineNumber() const { int CpuProfileNode::GetLineNumber() const {
return reinterpret_cast<const i::ProfileNode*>(this)->entry()->line_number(); return reinterpret_cast<const i::ProfileNode*>(this)->line_number();
} }
...@@ -10087,9 +10087,14 @@ void CpuProfiler::CollectSample() { ...@@ -10087,9 +10087,14 @@ void CpuProfiler::CollectSample() {
void CpuProfiler::StartProfiling(Local<String> title, bool record_samples) { void CpuProfiler::StartProfiling(Local<String> title, bool record_samples) {
reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling( reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
*Utils::OpenHandle(*title), record_samples); *Utils::OpenHandle(*title), record_samples, kLeafNodeLineNumbers);
} }
void CpuProfiler::StartProfiling(Local<String> title, CpuProfilingMode mode,
bool record_samples) {
reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
*Utils::OpenHandle(*title), record_samples, mode);
}
CpuProfile* CpuProfiler::StopProfiling(Local<String> title) { CpuProfile* CpuProfiler::StopProfiling(Local<String> title) {
return reinterpret_cast<CpuProfile*>( return reinterpret_cast<CpuProfile*>(
......
...@@ -345,20 +345,20 @@ void CpuProfiler::CollectSample() { ...@@ -345,20 +345,20 @@ void CpuProfiler::CollectSample() {
} }
} }
void CpuProfiler::StartProfiling(const char* title, bool record_samples) { void CpuProfiler::StartProfiling(const char* title, bool record_samples,
if (profiles_->StartProfiling(title, record_samples)) { ProfilingMode mode) {
if (profiles_->StartProfiling(title, record_samples, mode)) {
TRACE_EVENT0("v8", "CpuProfiler::StartProfiling"); TRACE_EVENT0("v8", "CpuProfiler::StartProfiling");
StartProcessorIfNotStarted(); StartProcessorIfNotStarted();
} }
} }
void CpuProfiler::StartProfiling(String* title, bool record_samples,
void CpuProfiler::StartProfiling(String* title, bool record_samples) { ProfilingMode mode) {
StartProfiling(profiles_->GetName(title), record_samples); StartProfiling(profiles_->GetName(title), record_samples, mode);
isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler); isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler);
} }
void CpuProfiler::StartProcessorIfNotStarted() { void CpuProfiler::StartProcessorIfNotStarted() {
if (processor_) { if (processor_) {
processor_->AddCurrentStack(isolate_); processor_->AddCurrentStack(isolate_);
......
...@@ -197,10 +197,13 @@ class CpuProfiler : public CodeEventObserver { ...@@ -197,10 +197,13 @@ class CpuProfiler : public CodeEventObserver {
static void CollectSample(Isolate* isolate); static void CollectSample(Isolate* isolate);
typedef v8::CpuProfilingMode ProfilingMode;
void set_sampling_interval(base::TimeDelta value); void set_sampling_interval(base::TimeDelta value);
void CollectSample(); void CollectSample();
void StartProfiling(const char* title, bool record_samples = false); void StartProfiling(const char* title, bool record_samples = false,
void StartProfiling(String* title, bool record_samples); ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
void StartProfiling(String* title, bool record_samples, ProfilingMode mode);
CpuProfile* StopProfiling(const char* title); CpuProfile* StopProfiling(const char* title);
CpuProfile* StopProfiling(String* title); CpuProfile* StopProfiling(String* title);
int GetProfilesCount(); int GetProfilesCount();
......
...@@ -33,10 +33,11 @@ inline CodeEntry* ProfileGenerator::FindEntry(Address address) { ...@@ -33,10 +33,11 @@ inline CodeEntry* ProfileGenerator::FindEntry(Address address) {
} }
ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry,
ProfileNode* parent) ProfileNode* parent, int line_number)
: tree_(tree), : tree_(tree),
entry_(entry), entry_(entry),
self_ticks_(0), self_ticks_(0),
line_number_(line_number),
parent_(parent), parent_(parent),
id_(tree->next_node_id()) { id_(tree->next_node_id()) {
tree_->EnqueueNode(this); tree_->EnqueueNode(this);
......
This diff is collapsed.
...@@ -189,15 +189,24 @@ class CodeEntry { ...@@ -189,15 +189,24 @@ class CodeEntry {
DISALLOW_COPY_AND_ASSIGN(CodeEntry); DISALLOW_COPY_AND_ASSIGN(CodeEntry);
}; };
struct CodeEntryAndLineNumber {
CodeEntry* code_entry;
int line_number;
};
typedef std::vector<CodeEntryAndLineNumber> ProfileStackTrace;
class ProfileTree; class ProfileTree;
class ProfileNode { class ProfileNode {
public: public:
inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent); inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent,
int line_number = 0);
ProfileNode* FindChild(CodeEntry* entry); ProfileNode* FindChild(
ProfileNode* FindOrAddChild(CodeEntry* entry); CodeEntry* entry,
int line_number = v8::CpuProfileNode::kNoLineNumberInfo);
ProfileNode* FindOrAddChild(CodeEntry* entry, int line_number = 0);
void IncrementSelfTicks() { ++self_ticks_; } void IncrementSelfTicks() { ++self_ticks_; }
void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; } void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
void IncrementLineTicks(int src_line); void IncrementLineTicks(int src_line);
...@@ -208,6 +217,10 @@ class ProfileNode { ...@@ -208,6 +217,10 @@ class ProfileNode {
unsigned id() const { return id_; } unsigned id() const { return id_; }
unsigned function_id() const; unsigned function_id() const;
ProfileNode* parent() const { return parent_; } ProfileNode* parent() const { return parent_; }
int line_number() const {
return line_number_ != 0 ? line_number_ : entry_->line_number();
}
unsigned int GetHitLineCount() const { unsigned int GetHitLineCount() const {
return static_cast<unsigned int>(line_ticks_.size()); return static_cast<unsigned int>(line_ticks_.size());
} }
...@@ -222,20 +235,25 @@ class ProfileNode { ...@@ -222,20 +235,25 @@ class ProfileNode {
void Print(int indent); void Print(int indent);
private: private:
struct CodeEntryEqual { struct Equals {
bool operator()(CodeEntry* entry1, CodeEntry* entry2) const { bool operator()(CodeEntryAndLineNumber lhs,
return entry1 == entry2 || entry1->IsSameFunctionAs(entry2); CodeEntryAndLineNumber rhs) const {
return lhs.code_entry->IsSameFunctionAs(rhs.code_entry) &&
lhs.line_number == rhs.line_number;
} }
}; };
struct CodeEntryHash { struct Hasher {
std::size_t operator()(CodeEntry* entry) const { return entry->GetHash(); } std::size_t operator()(CodeEntryAndLineNumber pair) const {
return pair.code_entry->GetHash() ^ ComputeIntegerHash(pair.line_number);
}
}; };
ProfileTree* tree_; ProfileTree* tree_;
CodeEntry* entry_; CodeEntry* entry_;
unsigned self_ticks_; unsigned self_ticks_;
std::unordered_map<CodeEntry*, ProfileNode*, CodeEntryHash, CodeEntryEqual> std::unordered_map<CodeEntryAndLineNumber, ProfileNode*, Hasher, Equals>
children_; children_;
int line_number_;
std::vector<ProfileNode*> children_list_; std::vector<ProfileNode*> children_list_;
ProfileNode* parent_; ProfileNode* parent_;
unsigned id_; unsigned id_;
...@@ -253,10 +271,17 @@ class ProfileTree { ...@@ -253,10 +271,17 @@ class ProfileTree {
explicit ProfileTree(Isolate* isolate); explicit ProfileTree(Isolate* isolate);
~ProfileTree(); ~ProfileTree();
typedef v8::CpuProfilingMode ProfilingMode;
ProfileNode* AddPathFromEnd( ProfileNode* AddPathFromEnd(
const std::vector<CodeEntry*>& path, const std::vector<CodeEntry*>& path,
int src_line = v8::CpuProfileNode::kNoLineNumberInfo, int src_line = v8::CpuProfileNode::kNoLineNumberInfo,
bool update_stats = true); bool update_stats = true);
ProfileNode* AddPathFromEnd(
const ProfileStackTrace& path,
int src_line = v8::CpuProfileNode::kNoLineNumberInfo,
bool update_stats = true,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
ProfileNode* root() const { return root_; } ProfileNode* root() const { return root_; }
unsigned next_node_id() { return next_node_id_++; } unsigned next_node_id() { return next_node_id_++; }
unsigned GetFunctionId(const ProfileNode* node); unsigned GetFunctionId(const ProfileNode* node);
...@@ -293,10 +318,13 @@ class ProfileTree { ...@@ -293,10 +318,13 @@ class ProfileTree {
class CpuProfile { class CpuProfile {
public: public:
CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples); typedef v8::CpuProfilingMode ProfilingMode;
CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples,
ProfilingMode mode);
// Add pc -> ... -> main() call path to the profile. // Add pc -> ... -> main() call path to the profile.
void AddPath(base::TimeTicks timestamp, const std::vector<CodeEntry*>& path, void AddPath(base::TimeTicks timestamp, const ProfileStackTrace& path,
int src_line, bool update_stats); int src_line, bool update_stats);
void FinishProfile(); void FinishProfile();
...@@ -322,6 +350,7 @@ class CpuProfile { ...@@ -322,6 +350,7 @@ class CpuProfile {
const char* title_; const char* title_;
bool record_samples_; bool record_samples_;
ProfilingMode mode_;
base::TimeTicks start_time_; base::TimeTicks start_time_;
base::TimeTicks end_time_; base::TimeTicks end_time_;
std::vector<ProfileNode*> samples_; std::vector<ProfileNode*> samples_;
...@@ -361,8 +390,11 @@ class CpuProfilesCollection { ...@@ -361,8 +390,11 @@ class CpuProfilesCollection {
public: public:
explicit CpuProfilesCollection(Isolate* isolate); explicit CpuProfilesCollection(Isolate* isolate);
typedef v8::CpuProfilingMode ProfilingMode;
void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; } void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; }
bool StartProfiling(const char* title, bool record_samples); bool StartProfiling(const char* title, bool record_samples,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
CpuProfile* StopProfiling(const char* title); CpuProfile* StopProfiling(const char* title);
std::vector<std::unique_ptr<CpuProfile>>* profiles() { std::vector<std::unique_ptr<CpuProfile>>* profiles() {
return &finished_profiles_; return &finished_profiles_;
...@@ -373,8 +405,8 @@ class CpuProfilesCollection { ...@@ -373,8 +405,8 @@ class CpuProfilesCollection {
// Called from profile generator thread. // Called from profile generator thread.
void AddPathToCurrentProfiles(base::TimeTicks timestamp, void AddPathToCurrentProfiles(base::TimeTicks timestamp,
const std::vector<CodeEntry*>& path, const ProfileStackTrace& path, int src_line,
int src_line, bool update_stats); bool update_stats);
// Limits the number of profiles that can be simultaneously collected. // Limits the number of profiles that can be simultaneously collected.
static const int kMaxSimultaneousProfiles = 100; static const int kMaxSimultaneousProfiles = 100;
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
# BUG(5193). The cpu profiler tests are notoriously flaky. # BUG(5193). The cpu profiler tests are notoriously flaky.
'test-profile-generator/RecordStackTraceAtStartProfiling': [SKIP], 'test-profile-generator/RecordStackTraceAtStartProfiling': [SKIP],
'test-cpu-profiler/CollectCpuProfile': [SKIP], 'test-cpu-profiler/CollectCpuProfile': [SKIP],
'test-cpu-profiler/CollectCpuProfileCallerLineNumbers': [FAIL, PASS],
'test-cpu-profiler/CollectCpuProfileSamples': [SKIP], 'test-cpu-profiler/CollectCpuProfileSamples': [SKIP],
'test-cpu-profiler/CollectDeoptEvents': [SKIP], 'test-cpu-profiler/CollectDeoptEvents': [SKIP],
'test-cpu-profiler/CpuProfileDeepStack': [SKIP], 'test-cpu-profiler/CpuProfileDeepStack': [SKIP],
......
...@@ -428,11 +428,14 @@ class ProfilerHelper { ...@@ -428,11 +428,14 @@ class ProfilerHelper {
profiler_->Dispose(); profiler_->Dispose();
} }
typedef v8::CpuProfilingMode ProfilingMode;
v8::CpuProfile* Run(v8::Local<v8::Function> function, v8::CpuProfile* Run(v8::Local<v8::Function> function,
v8::Local<v8::Value> argv[], int argc, v8::Local<v8::Value> argv[], int argc,
unsigned min_js_samples = 0, unsigned min_js_samples = 0,
unsigned min_external_samples = 0, unsigned min_external_samples = 0,
bool collect_samples = false); bool collect_samples = false,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
v8::CpuProfiler* profiler() { return profiler_; } v8::CpuProfiler* profiler() { return profiler_; }
...@@ -445,11 +448,11 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function, ...@@ -445,11 +448,11 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
v8::Local<v8::Value> argv[], int argc, v8::Local<v8::Value> argv[], int argc,
unsigned min_js_samples, unsigned min_js_samples,
unsigned min_external_samples, unsigned min_external_samples,
bool collect_samples) { bool collect_samples, ProfilingMode mode) {
v8::Local<v8::String> profile_name = v8_str("my_profile"); v8::Local<v8::String> profile_name = v8_str("my_profile");
profiler_->SetSamplingInterval(100); profiler_->SetSamplingInterval(100);
profiler_->StartProfiling(profile_name, collect_samples); profiler_->StartProfiling(profile_name, mode, collect_samples);
v8::internal::CpuProfiler* iprofiler = v8::internal::CpuProfiler* iprofiler =
reinterpret_cast<v8::internal::CpuProfiler*>(profiler_); reinterpret_cast<v8::internal::CpuProfiler*>(profiler_);
...@@ -509,7 +512,6 @@ static const v8::CpuProfileNode* GetChild(v8::Local<v8::Context> context, ...@@ -509,7 +512,6 @@ static const v8::CpuProfileNode* GetChild(v8::Local<v8::Context> context,
return result; return result;
} }
static void CheckSimpleBranch(v8::Local<v8::Context> context, static void CheckSimpleBranch(v8::Local<v8::Context> context,
const v8::CpuProfileNode* node, const v8::CpuProfileNode* node,
const char* names[], int length) { const char* names[], int length) {
...@@ -519,7 +521,6 @@ static void CheckSimpleBranch(v8::Local<v8::Context> context, ...@@ -519,7 +521,6 @@ static void CheckSimpleBranch(v8::Local<v8::Context> context,
} }
} }
static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context, static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context,
v8::CpuProfile* profile, v8::CpuProfile* profile,
const char* names[], int length) { const char* names[], int length) {
...@@ -530,6 +531,41 @@ static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context, ...@@ -530,6 +531,41 @@ static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context,
return reinterpret_cast<const ProfileNode*>(node); return reinterpret_cast<const ProfileNode*>(node);
} }
struct NameLinePair {
const char* name;
int line_number;
};
static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
NameLinePair pair) {
for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
const v8::CpuProfileNode* child = node->GetChild(i);
// The name and line number must match, or if the requested line number was
// -1, then match any function of the same name.
if (strcmp(child->GetFunctionNameStr(), pair.name) == 0 &&
(child->GetLineNumber() == pair.line_number ||
pair.line_number == -1)) {
return child;
}
}
return nullptr;
}
static const v8::CpuProfileNode* GetChild(const v8::CpuProfileNode* node,
NameLinePair pair) {
const v8::CpuProfileNode* result = FindChild(node, pair);
if (!result) FATAL("Failed to GetChild: %s:%d", pair.name, pair.line_number);
return result;
}
static void CheckBranch(const v8::CpuProfileNode* node, NameLinePair path[],
int length) {
for (int i = 0; i < length; i++) {
NameLinePair pair = path[i];
node = GetChild(node, pair);
}
}
static const char* cpu_profiler_test_source = static const char* cpu_profiler_test_source =
"%NeverOptimizeFunction(loop);\n" "%NeverOptimizeFunction(loop);\n"
"%NeverOptimizeFunction(delay);\n" "%NeverOptimizeFunction(delay);\n"
...@@ -610,6 +646,40 @@ TEST(CollectCpuProfile) { ...@@ -610,6 +646,40 @@ TEST(CollectCpuProfile) {
profile->Delete(); profile->Delete();
} }
TEST(CollectCpuProfileCallerLineNumbers) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
CompileRun(cpu_profiler_test_source);
v8::Local<v8::Function> function = GetFunction(env.local(), "start");
int32_t profiling_interval_ms = 200;
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
ProfilerHelper helper(env.local());
helper.Run(function, args, arraysize(args), 1000, 0, false,
v8::CpuProfilingMode::kCallerLineNumbers);
v8::CpuProfile* profile =
helper.Run(function, args, arraysize(args), 1000, 0, false,
v8::CpuProfilingMode::kCallerLineNumbers);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* start_node = GetChild(root, {"start", 27});
const v8::CpuProfileNode* foo_node = GetChild(start_node, {"foo", 30});
NameLinePair bar_branch[] = {{"bar", 23}, {"delay", 19}, {"loop", 18}};
CheckBranch(foo_node, bar_branch, arraysize(bar_branch));
NameLinePair baz_branch[] = {{"baz", 25}, {"delay", 20}, {"loop", 18}};
CheckBranch(foo_node, baz_branch, arraysize(baz_branch));
NameLinePair delay_at22_branch[] = {{"delay", 22}, {"loop", 18}};
CheckBranch(foo_node, delay_at22_branch, arraysize(delay_at22_branch));
NameLinePair delay_at24_branch[] = {{"delay", 24}, {"loop", 18}};
CheckBranch(foo_node, delay_at24_branch, arraysize(delay_at24_branch));
profile->Delete();
}
static const char* hot_deopt_no_frame_entry_test_source = static const char* hot_deopt_no_frame_entry_test_source =
"%NeverOptimizeFunction(foo);\n" "%NeverOptimizeFunction(foo);\n"
"%NeverOptimizeFunction(start);\n" "%NeverOptimizeFunction(start);\n"
......
...@@ -64,6 +64,25 @@ TEST(ProfileNodeFindOrAddChild) { ...@@ -64,6 +64,25 @@ TEST(ProfileNodeFindOrAddChild) {
CHECK_EQ(childNode3, node->FindOrAddChild(&entry3)); CHECK_EQ(childNode3, node->FindOrAddChild(&entry3));
} }
TEST(ProfileNodeFindOrAddChildWithLineNumber) {
CcTest::InitializeVM();
ProfileTree tree(CcTest::i_isolate());
ProfileNode* root = tree.root();
CodeEntry a(i::CodeEventListener::FUNCTION_TAG, "a");
ProfileNode* a_node = root->FindOrAddChild(&a, -1);
// a --(22)--> child1
// --(23)--> child1
CodeEntry child1(i::CodeEventListener::FUNCTION_TAG, "child1");
ProfileNode* child1_node = a_node->FindOrAddChild(&child1, 22);
CHECK(child1_node);
CHECK_EQ(child1_node, a_node->FindOrAddChild(&child1, 22));
ProfileNode* child2_node = a_node->FindOrAddChild(&child1, 23);
CHECK(child2_node);
CHECK_NE(child1_node, child2_node);
}
TEST(ProfileNodeFindOrAddChildForSameFunction) { TEST(ProfileNodeFindOrAddChildForSameFunction) {
CcTest::InitializeVM(); CcTest::InitializeVM();
...@@ -172,6 +191,29 @@ TEST(ProfileTreeAddPathFromEnd) { ...@@ -172,6 +191,29 @@ TEST(ProfileTreeAddPathFromEnd) {
CHECK_EQ(1u, node4->self_ticks()); CHECK_EQ(1u, node4->self_ticks());
} }
TEST(ProfileTreeAddPathFromEndWithLineNumbers) {
CcTest::InitializeVM();
CodeEntry a(i::CodeEventListener::FUNCTION_TAG, "a");
CodeEntry b(i::CodeEventListener::FUNCTION_TAG, "b");
CodeEntry c(i::CodeEventListener::FUNCTION_TAG, "c");
ProfileTree tree(CcTest::i_isolate());
ProfileTreeTestHelper helper(&tree);
ProfileStackTrace path = {{&c, 5}, {&b, 3}, {&a, 1}};
tree.AddPathFromEnd(path, v8::CpuProfileNode::kNoLineNumberInfo, true,
v8::CpuProfilingMode::kCallerLineNumbers);
ProfileNode* a_node =
tree.root()->FindChild(&a, v8::CpuProfileNode::kNoLineNumberInfo);
tree.Print();
CHECK(a_node);
ProfileNode* b_node = a_node->FindChild(&b, 1);
CHECK(b_node);
ProfileNode* c_node = b_node->FindChild(&c, 3);
CHECK(c_node);
}
TEST(ProfileTreeCalculateTotalTicks) { TEST(ProfileTreeCalculateTotalTicks) {
CcTest::InitializeVM(); CcTest::InitializeVM();
......
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