Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index 7f020c5bb5b4f8a543b84eb09fe6cbcfe15e7ffc..2852dfd5c1c201c85055db18c3c4377d4c470688 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -29,10 +29,10 @@ |
#include "profile-generator-inl.h" |
- |
namespace v8 { |
namespace internal { |
+#ifdef ENABLE_CPP_PROFILES_PROCESSOR |
ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
HashMap::Entry* map_entry = |
@@ -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); |
} |
+#endif // ENABLE_CPP_PROFILES_PROCESSOR |
} } // namespace v8::internal |