C++ profiles processor: put under #ifdef and fix issues.

Review URL: http://codereview.chromium.org/1514006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4317 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1cf0439c
# Copyright 2008 the V8 project authors. All rights reserved.
# Copyright 2010 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
......@@ -105,6 +105,9 @@ LIBRARY_FLAGS = {
'profilingsupport:on': {
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'],
},
'cppprofilesprocessor:on': {
'CPPDEFINES': ['ENABLE_CPP_PROFILES_PROCESSOR'],
},
'debuggersupport:on': {
'CPPDEFINES': ['ENABLE_DEBUGGER_SUPPORT'],
}
......@@ -674,6 +677,11 @@ SIMPLE_OPTIONS = {
'default': 'on',
'help': 'enable profiling of JavaScript code'
},
'cppprofilesprocessor': {
'values': ['on', 'off'],
'default': 'off',
'help': 'enable C++ profiles processor'
},
'debuggersupport': {
'values': ['on', 'off'],
'default': 'on',
......
......@@ -119,6 +119,8 @@ class SamplingCircularQueue {
byte* positions_;
ProducerPosition* producer_pos_;
ConsumerPosition* consumer_pos_;
DISALLOW_COPY_AND_ASSIGN(SamplingCircularQueue);
};
......
......@@ -28,6 +28,8 @@
#ifndef V8_CPU_PROFILER_INL_H_
#define V8_CPU_PROFILER_INL_H_
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "circular-queue-inl.h"
#include "profile-generator-inl.h"
......@@ -36,15 +38,15 @@
namespace v8 {
namespace internal {
TickSample* ProfilerEventsProcessor::TickSampleEvent() {
TickSampleEventRecord* evt =
reinterpret_cast<TickSampleEventRecord*>(ticks_buffer_.Enqueue());
TickSampleEventRecord::cast(ticks_buffer_.Enqueue());
evt->order = enqueue_order_; // No increment!
return &evt->sample;
}
} } // namespace v8::internal
#endif // ENABLE_CPP_PROFILES_PROCESSOR
#endif // V8_CPU_PROFILER_INL_H_
......@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "v8.h"
#include "cpu-profiler-inl.h"
......@@ -32,7 +34,6 @@
namespace v8 {
namespace internal {
static const int kEventsBufferSize = 256*KB;
static const int kTickSamplesBufferChunkSize = 64*KB;
static const int kTickSamplesBufferChunksCount = 16;
......@@ -163,7 +164,7 @@ bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
while (true) {
const TickSampleEventRecord* rec =
reinterpret_cast<TickSampleEventRecord*>(ticks_buffer_.StartDequeue());
TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
if (rec == NULL) return false;
if (rec->order == dequeue_order) {
generator_->RecordTickSample(rec->sample);
......@@ -195,5 +196,6 @@ void ProfilerEventsProcessor::Run() {
while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
}
} } // namespace v8::internal
#endif // ENABLE_CPP_PROFILES_PROCESSOR
......@@ -28,13 +28,14 @@
#ifndef V8_CPU_PROFILER_H_
#define V8_CPU_PROFILER_H_
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "circular-queue.h"
#include "profile-generator.h"
namespace v8 {
namespace internal {
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
V(CODE_MOVE, CodeMoveEventRecord) \
......@@ -101,7 +102,7 @@ class CodeAliasEventRecord : public CodeEventRecord {
};
class TickSampleEventRecord {
class TickSampleEventRecord BASE_EMBEDDED {
public:
// In memory, the first machine word of a TickSampleEventRecord will be the
// first entry of TickSample, that is -- a program counter field.
......@@ -110,18 +111,12 @@ class TickSampleEventRecord {
TickSample sample;
unsigned order;
#if defined(__GNUC__) && (__GNUC__ < 4)
// Added to avoid 'all member functions in class are private' warning.
INLINE(unsigned get_order() const) { return order; }
// Added to avoid 'class only defines private constructors and
// has no friends' warning.
friend class TickSampleEventRecordFriend;
#endif
private:
// Disable instantiation.
TickSampleEventRecord();
static TickSampleEventRecord* cast(void* value) {
return reinterpret_cast<TickSampleEventRecord*>(value);
}
DISALLOW_COPY_AND_ASSIGN(TickSampleEventRecord);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(TickSampleEventRecord);
};
......@@ -179,7 +174,8 @@ class ProfilerEventsProcessor : public Thread {
unsigned enqueue_order_;
};
} } // namespace v8::internal
#endif // ENABLE_CPP_PROFILES_PROCESSOR
#endif // V8_CPU_PROFILER_H_
......@@ -28,12 +28,13 @@
#ifndef V8_PROFILE_GENERATOR_INL_H_
#define V8_PROFILE_GENERATOR_INL_H_
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "profile-generator.h"
namespace v8 {
namespace internal {
CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
const char* name,
const char* resource_name,
......@@ -76,6 +77,14 @@ void CodeMap::DeleteCode(Address addr) {
}
bool CpuProfilesCollection::is_last_profile() {
// Called from VM thread, and only it can mutate the list,
// so no locking is needed here.
return current_profiles_.length() == 1;
}
} } // namespace v8::internal
#endif // ENABLE_CPP_PROFILES_PROCESSOR
#endif // V8_PROFILE_GENERATOR_INL_H_
......@@ -25,15 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "v8.h"
#include "profile-generator-inl.h"
namespace v8 {
namespace internal {
ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
HashMap::Entry* map_entry =
children_.Lookup(entry, CodeEntryHash(entry), false);
......@@ -47,23 +47,16 @@ ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
children_.Lookup(entry, CodeEntryHash(entry), true);
if (map_entry->value == NULL) {
// New node added.
map_entry->value = new ProfileNode(entry);
ProfileNode* new_node = new ProfileNode(entry);
map_entry->value = new_node;
children_list_.Add(new_node);
}
return reinterpret_cast<ProfileNode*>(map_entry->value);
}
void ProfileNode::GetChildren(List<ProfileNode*>* children) {
for (HashMap::Entry* p = children_.Start();
p != NULL;
p = children_.Next(p)) {
children->Add(reinterpret_cast<ProfileNode*>(p->value));
}
}
void ProfileNode::Print(int indent) {
OS::Print("%4u %4u %*c %s\n",
OS::Print("%5u %5u %*c %s\n",
total_ticks_, self_ticks_,
indent, ' ',
entry_ != NULL ? entry_->name() : "");
......@@ -123,39 +116,46 @@ void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) {
namespace {
struct Position {
Position(ProfileNode* a_node, HashMap::Entry* a_p)
: node(a_node), p(a_p) { }
class Position {
public:
explicit Position(ProfileNode* node)
: node(node), child_idx_(0) { }
INLINE(ProfileNode* current_child()) {
return reinterpret_cast<ProfileNode*>(p->value);
return node->children()->at(child_idx_);
}
INLINE(bool has_current_child()) {
return child_idx_ < node->children()->length();
}
INLINE(void next_child()) { ++child_idx_; }
ProfileNode* node;
HashMap::Entry* p;
private:
int child_idx_;
};
} // namespace
// Non-recursive implementation of breadth-first post-order tree traversal.
template <typename Callback>
void ProfileTree::TraverseBreadthFirstPostOrder(Callback* callback) {
List<Position> stack(10);
stack.Add(Position(root_, root_->children_.Start()));
stack.Add(Position(root_));
do {
Position& current = stack.last();
if (current.p != NULL) {
stack.Add(Position(current.current_child(),
current.current_child()->children_.Start()));
if (current.has_current_child()) {
stack.Add(Position(current.current_child()));
} else {
callback->AfterAllChildrenTraversed(current.node);
if (stack.length() > 1) {
Position& parent = stack[stack.length() - 2];
callback->AfterChildTraversed(parent.node, current.node);
parent.p = parent.node->children_.Next(parent.p);
parent.next_child();
// Remove child from the stack.
stack.RemoveLast();
}
}
} while (stack.length() > 1 || stack.last().p != NULL);
} while (stack.length() > 1 || stack.last().has_current_child());
}
......@@ -175,7 +175,6 @@ class CalculateTotalTicksCallback {
} // namespace
// Non-recursive implementation of breadth-first tree traversal.
void ProfileTree::CalculateTotalTicks() {
CalculateTotalTicksCallback cb;
TraverseBreadthFirstPostOrder(&cb);
......@@ -242,8 +241,22 @@ CodeEntry* CodeMap::FindEntry(Address addr) {
}
void CodeMap::CodeTreePrinter::Call(
const Address& key, const CodeMap::CodeEntryInfo& value) {
OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
}
void CodeMap::Print() {
CodeTreePrinter printer;
tree_.ForEach(&printer);
}
CpuProfilesCollection::CpuProfilesCollection()
: function_and_resource_names_(StringsMatch) {
: function_and_resource_names_(StringsMatch),
profiles_uids_(CpuProfilesMatch),
current_profiles_semaphore_(OS::CreateSemaphore(1)) {
}
......@@ -262,6 +275,8 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) {
CpuProfilesCollection::~CpuProfilesCollection() {
delete current_profiles_semaphore_;
current_profiles_.Iterate(DeleteCpuProfile);
profiles_.Iterate(DeleteCpuProfile);
code_entries_.Iterate(DeleteCodeEntry);
args_count_names_.Iterate(DeleteArgsCountName);
......@@ -273,8 +288,63 @@ CpuProfilesCollection::~CpuProfilesCollection() {
}
void CpuProfilesCollection::AddProfile(unsigned uid) {
profiles_.Add(new CpuProfile());
bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid) {
ASSERT(uid > 0);
current_profiles_semaphore_->Wait();
for (int i = 0; i < current_profiles_.length(); ++i) {
if (strcmp(current_profiles_[i]->title(), title) == 0) {
// Ignore attempts to start profile with the same title.
current_profiles_semaphore_->Signal();
return false;
}
}
current_profiles_.Add(new CpuProfile(title, uid));
current_profiles_semaphore_->Signal();
return true;
}
bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) {
return StartProfiling(GetName(title), uid);
}
CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
const int title_len = strlen(title);
CpuProfile* profile = NULL;
current_profiles_semaphore_->Wait();
for (int i = current_profiles_.length() - 1; i >= 0; --i) {
if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) {
profile = current_profiles_.Remove(i);
break;
}
}
current_profiles_semaphore_->Signal();
if (profile != NULL) {
profile->CalculateTotalTicks();
profiles_.Add(profile);
HashMap::Entry* entry =
profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()),
static_cast<uint32_t>(profile->uid()),
true);
ASSERT(entry->value == NULL);
entry->value = profile;
}
return profile;
}
CpuProfile* CpuProfilesCollection::StopProfiling(String* title) {
return StopProfiling(GetName(title));
}
CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) {
HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
static_cast<uint32_t>(uid),
false);
return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL;
}
......@@ -293,7 +363,10 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
const char* name) {
CodeEntry* entry = new CodeEntry(tag, name, "", 0);
CodeEntry* entry = new CodeEntry(tag,
name,
"",
kNoLineNumberInfo);
code_entries_.Add(entry);
return entry;
}
......@@ -301,7 +374,10 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
int args_count) {
CodeEntry* entry = new CodeEntry(tag, GetName(args_count), "", 0);
CodeEntry* entry = new CodeEntry(tag,
GetName(args_count),
"",
kNoLineNumberInfo);
code_entries_.Add(entry);
return entry;
}
......@@ -345,6 +421,19 @@ const char* CpuProfilesCollection::GetName(int args_count) {
}
void CpuProfilesCollection::AddPathToCurrentProfiles(
const Vector<CodeEntry*>& path) {
// As starting / stopping profiles is rare relatively to this
// method, we don't bother minimizing the duration of lock holding,
// e.g. copying contents of the list to a local vector.
current_profiles_semaphore_->Wait();
for (int i = 0; i < current_profiles_.length(); ++i) {
current_profiles_[i]->AddPath(path);
}
current_profiles_semaphore_->Signal();
}
ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
: profiles_(profiles) {
}
......@@ -377,8 +466,9 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
*entry++ = code_map_.FindEntry(*stack_pos);
}
profile()->AddPath(entries);
profiles_->AddPathToCurrentProfiles(entries);
}
} } // namespace v8::internal
#endif // ENABLE_CPP_PROFILES_PROCESSOR
......@@ -28,12 +28,13 @@
#ifndef V8_PROFILE_GENERATOR_H_
#define V8_PROFILE_GENERATOR_H_
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "hashmap.h"
namespace v8 {
namespace internal {
class CodeEntry {
public:
// CodeEntry doesn't own name strings, just references them.
......@@ -44,6 +45,8 @@ class CodeEntry {
INLINE(bool is_js_function());
INLINE(const char* name()) { return name_; }
INLINE(const char* resource_name()) { return name_; }
INLINE(int line_number()) { return line_number_; }
private:
Logger::LogEventsAndTags tag_;
......@@ -67,7 +70,7 @@ class ProfileNode {
INLINE(CodeEntry* entry() const) { return entry_; }
INLINE(unsigned total_ticks() const) { return total_ticks_; }
INLINE(unsigned self_ticks() const) { return self_ticks_; }
void GetChildren(List<ProfileNode*>* children);
INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
void Print(int indent);
......@@ -85,14 +88,13 @@ class ProfileNode {
unsigned self_ticks_;
// CodeEntry* -> ProfileNode*
HashMap children_;
friend class ProfileTree;
List<ProfileNode*> children_list_;
DISALLOW_COPY_AND_ASSIGN(ProfileNode);
};
class ProfileTree BASE_EMBEDDED {
class ProfileTree {
public:
ProfileTree() : root_(new ProfileNode(NULL)) { }
~ProfileTree();
......@@ -101,7 +103,7 @@ class ProfileTree BASE_EMBEDDED {
void AddPathFromStart(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
ProfileNode* root() { return root_; }
ProfileNode* root() const { return root_; }
void ShortPrint();
void Print() {
......@@ -120,18 +122,24 @@ class ProfileTree BASE_EMBEDDED {
class CpuProfile {
public:
CpuProfile() { }
CpuProfile(const char* title, unsigned uid)
: title_(title), uid_(uid) { }
// Add pc -> ... -> main() call path to the profile.
void AddPath(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
INLINE(ProfileTree* top_down()) { return &top_down_; }
INLINE(ProfileTree* bottom_up()) { return &bottom_up_; }
INLINE(const char* title() const) { return title_; }
INLINE(unsigned uid() const) { return uid_; }
INLINE(const ProfileTree* top_down() const) { return &top_down_; }
INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
void ShortPrint();
void Print();
private:
const char* title_;
unsigned uid_;
ProfileTree top_down_;
ProfileTree bottom_up_;
......@@ -139,7 +147,7 @@ class CpuProfile {
};
class CodeMap BASE_EMBEDDED {
class CodeMap {
public:
CodeMap() { }
INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
......@@ -148,6 +156,8 @@ class CodeMap BASE_EMBEDDED {
void AddAlias(Address alias, Address addr);
CodeEntry* FindEntry(Address addr);
void Print();
private:
struct CodeEntryInfo {
CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
......@@ -167,6 +177,11 @@ class CodeMap BASE_EMBEDDED {
};
typedef SplayTree<CodeTreeConfig> CodeTree;
class CodeTreePrinter {
public:
void Call(const Address& key, const CodeEntryInfo& value);
};
CodeTree tree_;
DISALLOW_COPY_AND_ASSIGN(CodeMap);
......@@ -178,14 +193,24 @@ class CpuProfilesCollection {
CpuProfilesCollection();
~CpuProfilesCollection();
void AddProfile(unsigned uid);
bool StartProfiling(const char* title, unsigned uid);
bool StartProfiling(String* title, unsigned uid);
CpuProfile* StopProfiling(const char* title);
CpuProfile* StopProfiling(String* title);
INLINE(List<CpuProfile*>* profiles()) { return &profiles_; }
CpuProfile* GetProfile(unsigned uid);
inline bool is_last_profile();
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
String* name, String* resource_name, int line_number);
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
INLINE(CpuProfile* profile()) { return profiles_.last(); }
// Called from profile generator thread.
void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
// This will be moved to V8 API.
static const int kNoLineNumberInfo = -1;
private:
const char* GetName(String* name);
......@@ -196,12 +221,22 @@ class CpuProfilesCollection {
reinterpret_cast<char*>(key2)) == 0;
}
INLINE(static bool CpuProfilesMatch(void* key1, void* key2)) {
return key1 == key2;
}
// String::Hash -> const char*
HashMap function_and_resource_names_;
// args_count -> char*
List<char*> args_count_names_;
List<CodeEntry*> code_entries_;
List<CpuProfile*> profiles_;
// uid -> CpuProfile*
HashMap profiles_uids_;
// Accessed by VM thread and profile generator thread.
List<CpuProfile*> current_profiles_;
Semaphore* current_profiles_semaphore_;
DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
};
......@@ -233,15 +268,14 @@ class ProfileGenerator {
INLINE(CodeMap* code_map()) { return &code_map_; }
private:
INLINE(CpuProfile* profile()) { return profiles_->profile(); }
CpuProfilesCollection* profiles_;
CodeMap code_map_;
DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
};
} } // namespace v8::internal
#endif // ENABLE_CPP_PROFILES_PROCESSOR
#endif // V8_PROFILE_GENERATOR_H_
......@@ -2,6 +2,8 @@
//
// Tests of profiles generator and utilities.
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "v8.h"
#include "cpu-profiler-inl.h"
#include "cctest.h"
......@@ -9,6 +11,7 @@
namespace i = v8::internal;
using i::CodeEntry;
using i::CpuProfile;
using i::CpuProfilesCollection;
using i::ProfileGenerator;
using i::ProfileNode;
......@@ -60,7 +63,7 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
TEST(CodeEvents) {
InitializeVM();
CpuProfilesCollection profiles;
profiles.AddProfile(0);
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator);
processor.Start();
......@@ -126,7 +129,7 @@ static int CompareProfileNodes(const T* p1, const T* p2) {
TEST(TickEvents) {
CpuProfilesCollection profiles;
profiles.AddProfile(0);
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator);
processor.Start();
......@@ -152,45 +155,50 @@ TEST(TickEvents) {
processor.Stop();
processor.Join();
CpuProfile* profile = profiles.StopProfiling("");
CHECK_NE(NULL, profile);
// Check call trees.
i::List<ProfileNode*> top_down_root_children;
profiles.profile()->top_down()->root()->GetChildren(&top_down_root_children);
CHECK_EQ(1, top_down_root_children.length());
CHECK_EQ("bbb", top_down_root_children.last()->entry()->name());
i::List<ProfileNode*> top_down_bbb_children;
top_down_root_children.last()->GetChildren(&top_down_bbb_children);
CHECK_EQ(1, top_down_bbb_children.length());
CHECK_EQ("args_count: 5", top_down_bbb_children.last()->entry()->name());
i::List<ProfileNode*> top_down_stub_children;
top_down_bbb_children.last()->GetChildren(&top_down_stub_children);
CHECK_EQ(1, top_down_stub_children.length());
CHECK_EQ("ddd", top_down_stub_children.last()->entry()->name());
i::List<ProfileNode*> top_down_ddd_children;
top_down_stub_children.last()->GetChildren(&top_down_ddd_children);
CHECK_EQ(0, top_down_ddd_children.length());
i::List<ProfileNode*> bottom_up_root_children;
profiles.profile()->bottom_up()->root()->GetChildren(
&bottom_up_root_children);
CHECK_EQ(3, bottom_up_root_children.length());
const i::List<ProfileNode*>* top_down_root_children =
profile->top_down()->root()->children();
CHECK_EQ(1, top_down_root_children->length());
CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
const i::List<ProfileNode*>* top_down_bbb_children =
top_down_root_children->last()->children();
CHECK_EQ(1, top_down_bbb_children->length());
CHECK_EQ("args_count: 5", top_down_bbb_children->last()->entry()->name());
const i::List<ProfileNode*>* top_down_stub_children =
top_down_bbb_children->last()->children();
CHECK_EQ(1, top_down_stub_children->length());
CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
const i::List<ProfileNode*>* top_down_ddd_children =
top_down_stub_children->last()->children();
CHECK_EQ(0, top_down_ddd_children->length());
const i::List<ProfileNode*>* bottom_up_root_children_unsorted =
profile->bottom_up()->root()->children();
CHECK_EQ(3, bottom_up_root_children_unsorted->length());
i::List<ProfileNode*> bottom_up_root_children(3);
bottom_up_root_children.AddAll(*bottom_up_root_children_unsorted);
bottom_up_root_children.Sort(&CompareProfileNodes);
CHECK_EQ("args_count: 5", bottom_up_root_children[0]->entry()->name());
CHECK_EQ("bbb", bottom_up_root_children[1]->entry()->name());
CHECK_EQ("ddd", bottom_up_root_children[2]->entry()->name());
i::List<ProfileNode*> bottom_up_stub_children;
bottom_up_root_children[0]->GetChildren(&bottom_up_stub_children);
CHECK_EQ(1, bottom_up_stub_children.length());
CHECK_EQ("bbb", bottom_up_stub_children.last()->entry()->name());
i::List<ProfileNode*> bottom_up_bbb_children;
bottom_up_root_children[1]->GetChildren(&bottom_up_bbb_children);
CHECK_EQ(0, bottom_up_bbb_children.length());
i::List<ProfileNode*> bottom_up_ddd_children;
bottom_up_root_children[2]->GetChildren(&bottom_up_ddd_children);
CHECK_EQ(1, bottom_up_ddd_children.length());
CHECK_EQ("args_count: 5", bottom_up_ddd_children.last()->entry()->name());
i::List<ProfileNode*> bottom_up_ddd_stub_children;
bottom_up_ddd_children.last()->GetChildren(&bottom_up_ddd_stub_children);
CHECK_EQ(1, bottom_up_ddd_stub_children.length());
CHECK_EQ("bbb", bottom_up_ddd_stub_children.last()->entry()->name());
const i::List<ProfileNode*>* bottom_up_stub_children =
bottom_up_root_children[0]->children();
CHECK_EQ(1, bottom_up_stub_children->length());
CHECK_EQ("bbb", bottom_up_stub_children->last()->entry()->name());
const i::List<ProfileNode*>* bottom_up_bbb_children =
bottom_up_root_children[1]->children();
CHECK_EQ(0, bottom_up_bbb_children->length());
const i::List<ProfileNode*>* bottom_up_ddd_children =
bottom_up_root_children[2]->children();
CHECK_EQ(1, bottom_up_ddd_children->length());
CHECK_EQ("args_count: 5", bottom_up_ddd_children->last()->entry()->name());
const i::List<ProfileNode*>* bottom_up_ddd_stub_children =
bottom_up_ddd_children->last()->children();
CHECK_EQ(1, bottom_up_ddd_stub_children->length());
CHECK_EQ("bbb", bottom_up_ddd_stub_children->last()->entry()->name());
}
#endif // ENABLE_CPP_PROFILES_PROCESSOR
......@@ -2,6 +2,8 @@
//
// Tests of profiles generator and utilities.
#ifdef ENABLE_CPP_PROFILES_PROCESSOR
#include "v8.h"
#include "profile-generator-inl.h"
#include "cctest.h"
......@@ -10,6 +12,7 @@ namespace i = v8::internal;
using i::CodeEntry;
using i::CodeMap;
using i::CpuProfile;
using i::CpuProfilesCollection;
using i::ProfileNode;
using i::ProfileTree;
......@@ -45,7 +48,7 @@ namespace {
class ProfileTreeTestHelper {
public:
explicit ProfileTreeTestHelper(ProfileTree* tree)
explicit ProfileTreeTestHelper(const ProfileTree* tree)
: tree_(tree) { }
ProfileNode* Walk(CodeEntry* entry1,
......@@ -65,7 +68,7 @@ class ProfileTreeTestHelper {
}
private:
ProfileTree* tree_;
const ProfileTree* tree_;
};
} // namespace
......@@ -366,7 +369,7 @@ TEST(CodeMapMoveAndDeleteCode) {
TEST(RecordTickSample) {
CpuProfilesCollection profiles;
profiles.AddProfile(0);
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
CodeEntry* entry1 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = generator.NewCodeEntry(i::Logger::FUNCTION_TAG, "bbb");
......@@ -375,11 +378,6 @@ TEST(RecordTickSample) {
generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
ProfileTreeTestHelper top_down_test_helper(profiles.profile()->top_down());
CHECK_EQ(NULL, top_down_test_helper.Walk(entry1));
CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
// We are building the following calls tree:
// -> aaa - sample1
// aaa -> bbb -> ccc - sample2
......@@ -406,6 +404,11 @@ TEST(RecordTickSample) {
sample3.frames_count = 2;
generator.RecordTickSample(sample3);
CpuProfile* profile = profiles.StopProfiling("");
CHECK_NE(NULL, profile);
ProfileTreeTestHelper top_down_test_helper(profile->top_down());
CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
CHECK_EQ(NULL, top_down_test_helper.Walk(entry3));
ProfileNode* node1 = top_down_test_helper.Walk(entry1);
CHECK_NE(NULL, node1);
CHECK_EQ(entry1, node1->entry());
......@@ -419,3 +422,5 @@ TEST(RecordTickSample) {
CHECK_NE(NULL, node4);
CHECK_EQ(entry1, node4->entry());
}
#endif // ENABLE_CPP_PROFILES_PROCESSOR
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