| Index: src/profile-generator.cc
|
| ===================================================================
|
| --- src/profile-generator.cc (revision 4699)
|
| +++ src/profile-generator.cc (working copy)
|
| @@ -28,6 +28,7 @@
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
|
|
| #include "v8.h"
|
| +#include "global-handles.h"
|
|
|
| #include "profile-generator-inl.h"
|
|
|
| @@ -37,10 +38,68 @@
|
| namespace internal {
|
|
|
|
|
| +TokenEnumerator::TokenEnumerator()
|
| + : token_locations_(4),
|
| + token_removed_(4) {
|
| +}
|
| +
|
| +
|
| +TokenEnumerator::~TokenEnumerator() {
|
| + for (int i = 0; i < token_locations_.length(); ++i) {
|
| + if (!token_removed_[i]) {
|
| + GlobalHandles::ClearWeakness(token_locations_[i]);
|
| + GlobalHandles::Destroy(token_locations_[i]);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +int TokenEnumerator::GetTokenId(Object* token) {
|
| + if (token == NULL) return CodeEntry::kNoSecurityToken;
|
| + for (int i = 0; i < token_locations_.length(); ++i) {
|
| + if (*token_locations_[i] == token && !token_removed_[i]) return i;
|
| + }
|
| + Handle<Object> handle = GlobalHandles::Create(token);
|
| + // handle.location() points to a memory cell holding a pointer
|
| + // to a token object in the V8's heap.
|
| + GlobalHandles::MakeWeak(handle.location(), this, TokenRemovedCallback);
|
| + token_locations_.Add(handle.location());
|
| + token_removed_.Add(false);
|
| + return token_locations_.length() - 1;
|
| +}
|
| +
|
| +
|
| +void TokenEnumerator::TokenRemovedCallback(v8::Persistent<v8::Value> handle,
|
| + void* parameter) {
|
| + reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved(
|
| + Utils::OpenHandle(*handle).location());
|
| +}
|
| +
|
| +
|
| +void TokenEnumerator::TokenRemoved(Object** token_location) {
|
| + for (int i = 0; i < token_locations_.length(); ++i) {
|
| + if (token_locations_[i] == token_location && !token_removed_[i]) {
|
| + token_removed_[i] = true;
|
| + return;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| const char* CodeEntry::kEmptyNamePrefix = "";
|
| unsigned CodeEntry::next_call_uid_ = 1;
|
|
|
|
|
| +void CodeEntry::CopyData(const CodeEntry& source) {
|
| + call_uid_ = source.call_uid_;
|
| + tag_ = source.tag_;
|
| + name_prefix_ = source.name_prefix_;
|
| + name_ = source.name_;
|
| + resource_name_ = source.resource_name_;
|
| + line_number_ = source.line_number_;
|
| +}
|
| +
|
| +
|
| ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
|
| HashMap::Entry* map_entry =
|
| children_.Lookup(entry, CodeEntryHash(entry), false);
|
| @@ -73,11 +132,12 @@
|
|
|
|
|
| void ProfileNode::Print(int indent) {
|
| - OS::Print("%5u %5u %*c %s%s",
|
| + OS::Print("%5u %5u %*c %s%s [%d]",
|
| total_ticks_, self_ticks_,
|
| indent, ' ',
|
| entry_->name_prefix(),
|
| - entry_->name());
|
| + entry_->name(),
|
| + entry_->security_token_id());
|
| if (entry_->resource_name()[0] != '\0')
|
| OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
|
| OS::Print("\n");
|
| @@ -93,6 +153,8 @@
|
|
|
| class DeleteNodesCallback {
|
| public:
|
| + void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
|
| +
|
| void AfterAllChildrenTraversed(ProfileNode* node) {
|
| delete node;
|
| }
|
| @@ -104,14 +166,19 @@
|
|
|
|
|
| ProfileTree::ProfileTree()
|
| - : root_entry_(Logger::FUNCTION_TAG, "", "(root)", "", 0),
|
| + : root_entry_(Logger::FUNCTION_TAG,
|
| + "",
|
| + "(root)",
|
| + "",
|
| + 0,
|
| + CodeEntry::kNoSecurityToken),
|
| root_(new ProfileNode(this, &root_entry_)) {
|
| }
|
|
|
|
|
| ProfileTree::~ProfileTree() {
|
| DeleteNodesCallback cb;
|
| - TraverseDepthFirstPostOrder(&cb);
|
| + TraverseDepthFirst(&cb);
|
| }
|
|
|
|
|
| @@ -141,6 +208,70 @@
|
| }
|
|
|
|
|
| +namespace {
|
| +
|
| +struct NodesPair {
|
| + NodesPair(ProfileNode* src, ProfileNode* dst)
|
| + : src(src), dst(dst) { }
|
| + ProfileNode* src;
|
| + ProfileNode* dst;
|
| +};
|
| +
|
| +
|
| +class FilteredCloneCallback {
|
| + public:
|
| + explicit FilteredCloneCallback(ProfileNode* dst_root, int security_token_id)
|
| + : stack_(10),
|
| + security_token_id_(security_token_id) {
|
| + stack_.Add(NodesPair(NULL, dst_root));
|
| + }
|
| +
|
| + void BeforeTraversingChild(ProfileNode* parent, ProfileNode* child) {
|
| + if (IsTokenAcceptable(child->entry()->security_token_id(),
|
| + parent->entry()->security_token_id())) {
|
| + ProfileNode* clone = stack_.last().dst->FindOrAddChild(child->entry());
|
| + clone->IncreaseSelfTicks(child->self_ticks());
|
| + stack_.Add(NodesPair(child, clone));
|
| + } else {
|
| + // Attribute ticks to parent node.
|
| + stack_.last().dst->IncreaseSelfTicks(child->self_ticks());
|
| + }
|
| + }
|
| +
|
| + void AfterAllChildrenTraversed(ProfileNode* parent) { }
|
| +
|
| + void AfterChildTraversed(ProfileNode*, ProfileNode* child) {
|
| + if (stack_.last().src == child) {
|
| + stack_.RemoveLast();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + bool IsTokenAcceptable(int token, int parent_token) {
|
| + if (token == CodeEntry::kNoSecurityToken
|
| + || token == security_token_id_) return true;
|
| + if (token == CodeEntry::kInheritsSecurityToken) {
|
| + ASSERT(parent_token != CodeEntry::kInheritsSecurityToken);
|
| + return parent_token == CodeEntry::kNoSecurityToken
|
| + || parent_token == security_token_id_;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + List<NodesPair> stack_;
|
| + int security_token_id_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) {
|
| + ms_to_ticks_scale_ = src->ms_to_ticks_scale_;
|
| + FilteredCloneCallback cb(root_, security_token_id);
|
| + src->TraverseDepthFirst(&cb);
|
| + CalculateTotalTicks();
|
| +}
|
| +
|
| +
|
| void ProfileTree::SetTickRatePerMs(double ticks_per_ms) {
|
| ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0;
|
| }
|
| @@ -170,12 +301,13 @@
|
|
|
| // Non-recursive implementation of a depth-first post-order tree traversal.
|
| template <typename Callback>
|
| -void ProfileTree::TraverseDepthFirstPostOrder(Callback* callback) {
|
| +void ProfileTree::TraverseDepthFirst(Callback* callback) {
|
| List<Position> stack(10);
|
| stack.Add(Position(root_));
|
| - do {
|
| + while (stack.length() > 0) {
|
| Position& current = stack.last();
|
| if (current.has_current_child()) {
|
| + callback->BeforeTraversingChild(current.node, current.current_child());
|
| stack.Add(Position(current.current_child()));
|
| } else {
|
| callback->AfterAllChildrenTraversed(current.node);
|
| @@ -183,11 +315,11 @@
|
| Position& parent = stack[stack.length() - 2];
|
| callback->AfterChildTraversed(parent.node, current.node);
|
| parent.next_child();
|
| - // Remove child from the stack.
|
| - stack.RemoveLast();
|
| }
|
| + // Remove child from the stack.
|
| + stack.RemoveLast();
|
| }
|
| - } while (stack.length() > 1 || stack.last().has_current_child());
|
| + }
|
| }
|
|
|
|
|
| @@ -195,6 +327,8 @@
|
|
|
| class CalculateTotalTicksCallback {
|
| public:
|
| + void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
|
| +
|
| void AfterAllChildrenTraversed(ProfileNode* node) {
|
| node->IncreaseTotalTicks(node->self_ticks());
|
| }
|
| @@ -209,7 +343,7 @@
|
|
|
| void ProfileTree::CalculateTotalTicks() {
|
| CalculateTotalTicksCallback cb;
|
| - TraverseDepthFirstPostOrder(&cb);
|
| + TraverseDepthFirst(&cb);
|
| }
|
|
|
|
|
| @@ -238,6 +372,15 @@
|
| }
|
|
|
|
|
| +CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
|
| + ASSERT(security_token_id != CodeEntry::kNoSecurityToken);
|
| + CpuProfile* clone = new CpuProfile(title_, uid_);
|
| + clone->top_down_.FilteredClone(&top_down_, security_token_id);
|
| + clone->bottom_up_.FilteredClone(&bottom_up_, security_token_id);
|
| + return clone;
|
| +}
|
| +
|
| +
|
| void CpuProfile::ShortPrint() {
|
| OS::Print("top down ");
|
| top_down_.ShortPrint();
|
| @@ -259,12 +402,13 @@
|
| CodeMap::CodeEntryInfo(NULL, 0);
|
|
|
|
|
| -void CodeMap::AddAlias(Address alias, Address addr) {
|
| +void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) {
|
| CodeTree::Locator locator;
|
| - if (tree_.Find(addr, &locator)) {
|
| - const CodeEntryInfo& entry_info = locator.value();
|
| - tree_.Insert(alias, &locator);
|
| - locator.set_value(entry_info);
|
| + if (tree_.Find(code_start, &locator)) {
|
| + const CodeEntryInfo& code_info = locator.value();
|
| + entry->CopyData(*code_info.entry);
|
| + tree_.Insert(start, &locator);
|
| + locator.set_value(CodeEntryInfo(entry, code_info.size));
|
| }
|
| }
|
|
|
| @@ -295,8 +439,10 @@
|
|
|
| CpuProfilesCollection::CpuProfilesCollection()
|
| : function_and_resource_names_(StringsMatch),
|
| - profiles_uids_(CpuProfilesMatch),
|
| + profiles_uids_(UidsMatch),
|
| current_profiles_semaphore_(OS::CreateSemaphore(1)) {
|
| + // Create list of unabridged profiles.
|
| + profiles_by_token_.Add(new List<CpuProfile*>());
|
| }
|
|
|
|
|
| @@ -313,11 +459,15 @@
|
| delete *profile_ptr;
|
| }
|
|
|
| +static void DeleteProfilesList(List<CpuProfile*>** list_ptr) {
|
| + (*list_ptr)->Iterate(DeleteCpuProfile);
|
| + delete *list_ptr;
|
| +}
|
|
|
| CpuProfilesCollection::~CpuProfilesCollection() {
|
| delete current_profiles_semaphore_;
|
| current_profiles_.Iterate(DeleteCpuProfile);
|
| - profiles_.Iterate(DeleteCpuProfile);
|
| + profiles_by_token_.Iterate(DeleteProfilesList);
|
| code_entries_.Iterate(DeleteCodeEntry);
|
| args_count_names_.Iterate(DeleteArgsCountName);
|
| for (HashMap::Entry* p = function_and_resource_names_.Start();
|
| @@ -349,7 +499,8 @@
|
| }
|
|
|
|
|
| -CpuProfile* CpuProfilesCollection::StopProfiling(const char* title,
|
| +CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
|
| + const char* title,
|
| double actual_sampling_rate) {
|
| const int title_len = StrLength(title);
|
| CpuProfile* profile = NULL;
|
| @@ -365,32 +516,92 @@
|
| if (profile != NULL) {
|
| profile->CalculateTotalTicks();
|
| profile->SetActualSamplingRate(actual_sampling_rate);
|
| - profiles_.Add(profile);
|
| + List<CpuProfile*>* unabridged_list =
|
| + profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
|
| + unabridged_list->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;
|
| + entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1);
|
| + return GetProfile(security_token_id, profile->uid());
|
| }
|
| - return profile;
|
| + return NULL;
|
| }
|
|
|
|
|
| -CpuProfile* CpuProfilesCollection::StopProfiling(String* title,
|
| +CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
|
| + String* title,
|
| double actual_sampling_rate) {
|
| - return StopProfiling(GetName(title), actual_sampling_rate);
|
| + return StopProfiling(security_token_id, GetName(title), actual_sampling_rate);
|
| }
|
|
|
|
|
| -CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) {
|
| +CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
|
| + 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;
|
| + int index;
|
| + if (entry != NULL) {
|
| + index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
|
| + } else {
|
| + return NULL;
|
| + }
|
| + List<CpuProfile*>* unabridged_list =
|
| + profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
|
| + if (security_token_id == CodeEntry::kNoSecurityToken) {
|
| + return unabridged_list->at(index);
|
| + }
|
| + List<CpuProfile*>* list = GetProfilesList(security_token_id);
|
| + if (list->at(index) == NULL) {
|
| + list->at(index) =
|
| + unabridged_list->at(index)->FilteredClone(security_token_id);
|
| + }
|
| + return list->at(index);
|
| }
|
|
|
|
|
| +int CpuProfilesCollection::TokenToIndex(int security_token_id) {
|
| + ASSERT(CodeEntry::kNoSecurityToken == -1);
|
| + return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ...
|
| +}
|
| +
|
| +
|
| +List<CpuProfile*>* CpuProfilesCollection::GetProfilesList(
|
| + int security_token_id) {
|
| + const int index = TokenToIndex(security_token_id);
|
| + profiles_by_token_.AddBlock(NULL, profiles_by_token_.length() - index + 1);
|
| + List<CpuProfile*>* unabridged_list =
|
| + profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
|
| + const int current_count = unabridged_list->length();
|
| + if (profiles_by_token_[index] == NULL) {
|
| + profiles_by_token_[index] = new List<CpuProfile*>(current_count);
|
| + }
|
| + List<CpuProfile*>* list = profiles_by_token_[index];
|
| + list->AddBlock(NULL, current_count - list->length());
|
| + return list;
|
| +}
|
| +
|
| +
|
| +List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
|
| + List<CpuProfile*>* unabridged_list =
|
| + profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
|
| + if (security_token_id == CodeEntry::kNoSecurityToken) {
|
| + return unabridged_list;
|
| + }
|
| + List<CpuProfile*>* list = GetProfilesList(security_token_id);
|
| + const int current_count = unabridged_list->length();
|
| + for (int i = 0; i < current_count; ++i) {
|
| + if (list->at(i) == NULL) {
|
| + list->at(i) = unabridged_list->at(i)->FilteredClone(security_token_id);
|
| + }
|
| + }
|
| + return list;
|
| +}
|
| +
|
| +
|
| CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
| String* name,
|
| String* resource_name,
|
| @@ -399,7 +610,8 @@
|
| CodeEntry::kEmptyNamePrefix,
|
| GetFunctionName(name),
|
| GetName(resource_name),
|
| - line_number);
|
| + line_number,
|
| + CodeEntry::kNoSecurityToken);
|
| code_entries_.Add(entry);
|
| return entry;
|
| }
|
| @@ -411,7 +623,8 @@
|
| CodeEntry::kEmptyNamePrefix,
|
| GetFunctionName(name),
|
| "",
|
| - v8::CpuProfileNode::kNoLineNumberInfo);
|
| + v8::CpuProfileNode::kNoLineNumberInfo,
|
| + CodeEntry::kNoSecurityToken);
|
| code_entries_.Add(entry);
|
| return entry;
|
| }
|
| @@ -424,7 +637,8 @@
|
| name_prefix,
|
| GetName(name),
|
| "",
|
| - v8::CpuProfileNode::kNoLineNumberInfo);
|
| + v8::CpuProfileNode::kNoLineNumberInfo,
|
| + CodeEntry::kInheritsSecurityToken);
|
| code_entries_.Add(entry);
|
| return entry;
|
| }
|
| @@ -436,12 +650,20 @@
|
| "args_count: ",
|
| GetName(args_count),
|
| "",
|
| - v8::CpuProfileNode::kNoLineNumberInfo);
|
| + v8::CpuProfileNode::kNoLineNumberInfo,
|
| + CodeEntry::kInheritsSecurityToken);
|
| code_entries_.Add(entry);
|
| return entry;
|
| }
|
|
|
|
|
| +CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) {
|
| + CodeEntry* entry = new CodeEntry(security_token_id);
|
| + code_entries_.Add(entry);
|
| + return entry;
|
| +}
|
| +
|
| +
|
| const char* CpuProfilesCollection::GetName(String* name) {
|
| if (name->IsString()) {
|
| char* c_name =
|
| @@ -547,8 +769,13 @@
|
| *entry = NULL;
|
| } else {
|
| CodeEntry* pc_entry = *entries.start();
|
| - if (pc_entry == NULL || pc_entry->is_js_function())
|
| + if (pc_entry == NULL) {
|
| *entry = NULL;
|
| + } else if (pc_entry->is_js_function()) {
|
| + // Use function entry in favor of pc entry, as function
|
| + // entry has security token.
|
| + *entries.start() = NULL;
|
| + }
|
| }
|
| entry++;
|
| }
|
|
|