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
This commit is contained in:
parent
1cf0439ca7
commit
dde48831be
10
SConstruct
10
SConstruct
@ -1,4 +1,4 @@
|
||||
# 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());
|
||||
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());
|
||||
|
||||
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*>* 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
|
||||
|
Loading…
Reference in New Issue
Block a user