| Index: src/profile-generator.cc
|
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc
|
| index 8505b5b40d63fa4dec91195a724de24d13aa4d94..cc86724437f155d537609f947bd103601b0f37c2 100644
|
| --- a/src/profile-generator.cc
|
| +++ b/src/profile-generator.cc
|
| @@ -30,70 +30,17 @@
|
| #include "profile-generator-inl.h"
|
|
|
| #include "compiler.h"
|
| +#include "debug.h"
|
| +#include "sampler.h"
|
| #include "global-handles.h"
|
| #include "scopeinfo.h"
|
| #include "unicode.h"
|
| #include "zone-inl.h"
|
| -#include "debug.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
|
|
|
|
| -TokenEnumerator::TokenEnumerator()
|
| - : token_locations_(4),
|
| - token_removed_(4) {
|
| -}
|
| -
|
| -
|
| -TokenEnumerator::~TokenEnumerator() {
|
| - Isolate* isolate = Isolate::Current();
|
| - for (int i = 0; i < token_locations_.length(); ++i) {
|
| - if (!token_removed_[i]) {
|
| - isolate->global_handles()->ClearWeakness(token_locations_[i]);
|
| - isolate->global_handles()->Destroy(token_locations_[i]);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -int TokenEnumerator::GetTokenId(Object* token) {
|
| - Isolate* isolate = Isolate::Current();
|
| - if (token == NULL) return TokenEnumerator::kNoSecurityToken;
|
| - for (int i = 0; i < token_locations_.length(); ++i) {
|
| - if (*token_locations_[i] == token && !token_removed_[i]) return i;
|
| - }
|
| - Handle<Object> handle = isolate->global_handles()->Create(token);
|
| - // handle.location() points to a memory cell holding a pointer
|
| - // to a token object in the V8's heap.
|
| - isolate->global_handles()->MakeWeak(handle.location(),
|
| - this,
|
| - TokenRemovedCallback);
|
| - token_locations_.Add(handle.location());
|
| - token_removed_.Add(false);
|
| - return token_locations_.length() - 1;
|
| -}
|
| -
|
| -
|
| -void TokenEnumerator::TokenRemovedCallback(v8::Isolate* isolate,
|
| - v8::Persistent<v8::Value>* handle,
|
| - void* parameter) {
|
| - reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved(
|
| - Utils::OpenPersistent(handle).location());
|
| - handle->Dispose(isolate);
|
| -}
|
| -
|
| -
|
| -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;
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| StringsStorage::StringsStorage()
|
| : names_(StringsMatch) {
|
| }
|
| @@ -235,6 +182,12 @@ bool CodeEntry::IsSameAs(CodeEntry* entry) const {
|
| }
|
|
|
|
|
| +void CodeEntry::SetBuiltinId(Builtins::Name id) {
|
| + tag_ = Logger::BUILTIN_TAG;
|
| + builtin_id_ = id;
|
| +}
|
| +
|
| +
|
| ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
|
| HashMap::Entry* map_entry =
|
| children_.Lookup(entry, CodeEntryHash(entry), false);
|
| @@ -267,12 +220,12 @@ double ProfileNode::GetTotalMillis() const {
|
|
|
|
|
| void ProfileNode::Print(int indent) {
|
| - OS::Print("%5u %5u %*c %s%s [%d] #%d",
|
| + OS::Print("%5u %5u %*c %s%s #%d %d",
|
| total_ticks_, self_ticks_,
|
| indent, ' ',
|
| entry_->name_prefix(),
|
| entry_->name(),
|
| - entry_->security_token_id(),
|
| + entry_->script_id(),
|
| id());
|
| if (entry_->resource_name()[0] != '\0')
|
| OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
|
| @@ -298,7 +251,7 @@ class DeleteNodesCallback {
|
|
|
|
|
| ProfileTree::ProfileTree()
|
| - : root_entry_(Logger::FUNCTION_TAG, "", "(root)"),
|
| + : root_entry_(Logger::FUNCTION_TAG, "(root)"),
|
| next_node_id_(1),
|
| root_(new ProfileNode(this, &root_entry_)) {
|
| }
|
| @@ -345,58 +298,6 @@ struct NodesPair {
|
| };
|
|
|
|
|
| -class FilteredCloneCallback {
|
| - public:
|
| - 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 == TokenEnumerator::kNoSecurityToken
|
| - || token == security_token_id_) return true;
|
| - if (token == TokenEnumerator::kInheritsSecurityToken) {
|
| - ASSERT(parent_token != TokenEnumerator::kInheritsSecurityToken);
|
| - return parent_token == TokenEnumerator::kNoSecurityToken
|
| - || parent_token == security_token_id_;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - List<NodesPair> stack_;
|
| - int security_token_id_;
|
| -};
|
| -
|
| -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;
|
| }
|
| @@ -487,14 +388,6 @@ void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) {
|
| }
|
|
|
|
|
| -CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
|
| - ASSERT(security_token_id != TokenEnumerator::kNoSecurityToken);
|
| - CpuProfile* clone = new CpuProfile(title_, uid_, false);
|
| - clone->top_down_.FilteredClone(&top_down_, security_token_id);
|
| - return clone;
|
| -}
|
| -
|
| -
|
| void CpuProfile::ShortPrint() {
|
| OS::Print("top down ");
|
| top_down_.ShortPrint();
|
| @@ -593,10 +486,7 @@ void CodeMap::Print() {
|
|
|
|
|
| CpuProfilesCollection::CpuProfilesCollection()
|
| - : profiles_uids_(UidsMatch),
|
| - current_profiles_semaphore_(OS::CreateSemaphore(1)) {
|
| - // Create list of unabridged profiles.
|
| - profiles_by_token_.Add(new List<CpuProfile*>());
|
| + : current_profiles_semaphore_(OS::CreateSemaphore(1)) {
|
| }
|
|
|
|
|
| @@ -604,22 +494,16 @@ static void DeleteCodeEntry(CodeEntry** entry_ptr) {
|
| delete *entry_ptr;
|
| }
|
|
|
| +
|
| static void DeleteCpuProfile(CpuProfile** profile_ptr) {
|
| delete *profile_ptr;
|
| }
|
|
|
| -static void DeleteProfilesList(List<CpuProfile*>** list_ptr) {
|
| - if (*list_ptr != NULL) {
|
| - (*list_ptr)->Iterate(DeleteCpuProfile);
|
| - delete *list_ptr;
|
| - }
|
| -}
|
|
|
| CpuProfilesCollection::~CpuProfilesCollection() {
|
| delete current_profiles_semaphore_;
|
| + finished_profiles_.Iterate(DeleteCpuProfile);
|
| current_profiles_.Iterate(DeleteCpuProfile);
|
| - detached_profiles_.Iterate(DeleteCpuProfile);
|
| - profiles_by_token_.Iterate(DeleteProfilesList);
|
| code_entries_.Iterate(DeleteCodeEntry);
|
| }
|
|
|
| @@ -645,8 +529,7 @@ bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid,
|
| }
|
|
|
|
|
| -CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
|
| - const char* title,
|
| +CpuProfile* CpuProfilesCollection::StopProfiling(const char* title,
|
| double actual_sampling_rate) {
|
| const int title_len = StrLength(title);
|
| CpuProfile* profile = NULL;
|
| @@ -659,48 +542,11 @@ CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
|
| }
|
| current_profiles_semaphore_->Signal();
|
|
|
| - if (profile != NULL) {
|
| - profile->CalculateTotalTicks();
|
| - profile->SetActualSamplingRate(actual_sampling_rate);
|
| - List<CpuProfile*>* unabridged_list =
|
| - profiles_by_token_[TokenToIndex(TokenEnumerator::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 = reinterpret_cast<void*>(unabridged_list->length() - 1);
|
| - return GetProfile(security_token_id, profile->uid());
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -
|
| -CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
|
| - unsigned uid) {
|
| - int index = GetProfileIndex(uid);
|
| - if (index < 0) return NULL;
|
| - List<CpuProfile*>* unabridged_list =
|
| - profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
|
| - if (security_token_id == TokenEnumerator::kNoSecurityToken) {
|
| - return unabridged_list->at(index);
|
| - }
|
| - List<CpuProfile*>* list = GetProfilesList(security_token_id);
|
| - if (list->at(index) == NULL) {
|
| - (*list)[index] =
|
| - unabridged_list->at(index)->FilteredClone(security_token_id);
|
| - }
|
| - return list->at(index);
|
| -}
|
| -
|
| -
|
| -int CpuProfilesCollection::GetProfileIndex(unsigned uid) {
|
| - HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
|
| - static_cast<uint32_t>(uid),
|
| - false);
|
| - return entry != NULL ?
|
| - static_cast<int>(reinterpret_cast<intptr_t>(entry->value)) : -1;
|
| + if (profile == NULL) return NULL;
|
| + profile->CalculateTotalTicks();
|
| + profile->SetActualSamplingRate(actual_sampling_rate);
|
| + finished_profiles_.Add(profile);
|
| + return profile;
|
| }
|
|
|
|
|
| @@ -716,122 +562,13 @@ bool CpuProfilesCollection::IsLastProfile(const char* title) {
|
| void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
|
| // Called from VM thread for a completed profile.
|
| unsigned uid = profile->uid();
|
| - int index = GetProfileIndex(uid);
|
| - if (index < 0) {
|
| - detached_profiles_.RemoveElement(profile);
|
| - return;
|
| - }
|
| - profiles_uids_.Remove(reinterpret_cast<void*>(uid),
|
| - static_cast<uint32_t>(uid));
|
| - // Decrement all indexes above the deleted one.
|
| - for (HashMap::Entry* p = profiles_uids_.Start();
|
| - p != NULL;
|
| - p = profiles_uids_.Next(p)) {
|
| - intptr_t p_index = reinterpret_cast<intptr_t>(p->value);
|
| - if (p_index > index) {
|
| - p->value = reinterpret_cast<void*>(p_index - 1);
|
| - }
|
| - }
|
| - for (int i = 0; i < profiles_by_token_.length(); ++i) {
|
| - List<CpuProfile*>* list = profiles_by_token_[i];
|
| - if (list != NULL && index < list->length()) {
|
| - // Move all filtered clones into detached_profiles_,
|
| - // so we can know that they are still in use.
|
| - CpuProfile* cloned_profile = list->Remove(index);
|
| - if (cloned_profile != NULL && cloned_profile != profile) {
|
| - detached_profiles_.Add(cloned_profile);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -int CpuProfilesCollection::TokenToIndex(int security_token_id) {
|
| - ASSERT(TokenEnumerator::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);
|
| - const int lists_to_add = index - profiles_by_token_.length() + 1;
|
| - if (lists_to_add > 0) profiles_by_token_.AddBlock(NULL, lists_to_add);
|
| - List<CpuProfile*>* unabridged_list =
|
| - profiles_by_token_[TokenToIndex(TokenEnumerator::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];
|
| - const int profiles_to_add = current_count - list->length();
|
| - if (profiles_to_add > 0) list->AddBlock(NULL, profiles_to_add);
|
| - return list;
|
| -}
|
| -
|
| -
|
| -List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
|
| - List<CpuProfile*>* unabridged_list =
|
| - profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
|
| - if (security_token_id == TokenEnumerator::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)[i] = unabridged_list->at(i)->FilteredClone(security_token_id);
|
| + for (int i = 0; i < finished_profiles_.length(); i++) {
|
| + if (uid == finished_profiles_[i]->uid()) {
|
| + finished_profiles_.Remove(i);
|
| + return;
|
| }
|
| }
|
| - return list;
|
| -}
|
| -
|
| -
|
| -CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
| - Name* name,
|
| - String* resource_name,
|
| - int line_number) {
|
| - CodeEntry* entry = new CodeEntry(tag,
|
| - CodeEntry::kEmptyNamePrefix,
|
| - GetFunctionName(name),
|
| - TokenEnumerator::kNoSecurityToken,
|
| - GetName(resource_name),
|
| - line_number);
|
| - code_entries_.Add(entry);
|
| - return entry;
|
| -}
|
| -
|
| -
|
| -CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
| - const char* name) {
|
| - CodeEntry* entry = new CodeEntry(tag,
|
| - CodeEntry::kEmptyNamePrefix,
|
| - GetFunctionName(name));
|
| - code_entries_.Add(entry);
|
| - return entry;
|
| -}
|
| -
|
| -
|
| -CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
| - const char* name_prefix,
|
| - Name* name) {
|
| - CodeEntry* entry = new CodeEntry(tag,
|
| - name_prefix,
|
| - GetName(name),
|
| - TokenEnumerator::kInheritsSecurityToken);
|
| - code_entries_.Add(entry);
|
| - return entry;
|
| -}
|
| -
|
| -
|
| -CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
| - int args_count) {
|
| - CodeEntry* entry = new CodeEntry(tag,
|
| - "args_count: ",
|
| - GetName(args_count),
|
| - TokenEnumerator::kInheritsSecurityToken);
|
| - code_entries_.Add(entry);
|
| - return entry;
|
| + UNREACHABLE();
|
| }
|
|
|
|
|
| @@ -848,6 +585,22 @@ void CpuProfilesCollection::AddPathToCurrentProfiles(
|
| }
|
|
|
|
|
| +CodeEntry* CpuProfilesCollection::NewCodeEntry(
|
| + Logger::LogEventsAndTags tag,
|
| + const char* name,
|
| + const char* name_prefix,
|
| + const char* resource_name,
|
| + int line_number) {
|
| + CodeEntry* code_entry = new CodeEntry(tag,
|
| + name,
|
| + name_prefix,
|
| + resource_name,
|
| + line_number);
|
| + code_entries_.Add(code_entry);
|
| + return code_entry;
|
| +}
|
| +
|
| +
|
| void SampleRateCalculator::Tick() {
|
| if (--wall_time_query_countdown_ == 0)
|
| UpdateMeasurements(OS::TimeCurrentMillis());
|
| @@ -877,6 +630,8 @@ const char* const ProfileGenerator::kProgramEntryName =
|
| "(program)";
|
| const char* const ProfileGenerator::kGarbageCollectorEntryName =
|
| "(garbage collector)";
|
| +const char* const ProfileGenerator::kUnresolvedFunctionName =
|
| + "(unresolved function)";
|
|
|
|
|
| ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
|
| @@ -885,7 +640,10 @@ ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
|
| profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)),
|
| gc_entry_(
|
| profiles->NewCodeEntry(Logger::BUILTIN_TAG,
|
| - kGarbageCollectorEntryName)) {
|
| + kGarbageCollectorEntryName)),
|
| + unresolved_entry_(
|
| + profiles->NewCodeEntry(Logger::FUNCTION_TAG,
|
| + kUnresolvedFunctionName)) {
|
| }
|
|
|
|
|
| @@ -897,33 +655,45 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
|
| CodeEntry** entry = entries.start();
|
| memset(entry, 0, entries.length() * sizeof(*entry));
|
| if (sample.pc != NULL) {
|
| - Address start;
|
| - CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start);
|
| - // If pc is in the function code before it set up stack frame or after the
|
| - // frame was destroyed SafeStackFrameIterator incorrectly thinks that
|
| - // ebp contains return address of the current function and skips caller's
|
| - // frame. Check for this case and just skip such samples.
|
| - if (pc_entry) {
|
| - List<OffsetRange>* ranges = pc_entry->no_frame_ranges();
|
| - if (ranges) {
|
| - Code* code = Code::cast(HeapObject::FromAddress(start));
|
| - int pc_offset = static_cast<int>(sample.pc - code->instruction_start());
|
| - for (int i = 0; i < ranges->length(); i++) {
|
| - OffsetRange& range = ranges->at(i);
|
| - if (range.from <= pc_offset && pc_offset < range.to) {
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - *entry++ = pc_entry;
|
| -
|
| if (sample.has_external_callback) {
|
| // Don't use PC when in external callback code, as it can point
|
| // inside callback's code, and we will erroneously report
|
| // that a callback calls itself.
|
| - *(entries.start()) = NULL;
|
| *entry++ = code_map_.FindEntry(sample.external_callback);
|
| + } else {
|
| + Address start;
|
| + CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start);
|
| + // If pc is in the function code before it set up stack frame or after the
|
| + // frame was destroyed SafeStackFrameIterator incorrectly thinks that
|
| + // ebp contains return address of the current function and skips caller's
|
| + // frame. Check for this case and just skip such samples.
|
| + if (pc_entry) {
|
| + List<OffsetRange>* ranges = pc_entry->no_frame_ranges();
|
| + if (ranges) {
|
| + Code* code = Code::cast(HeapObject::FromAddress(start));
|
| + int pc_offset = static_cast<int>(
|
| + sample.pc - code->instruction_start());
|
| + for (int i = 0; i < ranges->length(); i++) {
|
| + OffsetRange& range = ranges->at(i);
|
| + if (range.from <= pc_offset && pc_offset < range.to) {
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + *entry++ = pc_entry;
|
| +
|
| + if (pc_entry->builtin_id() == Builtins::kFunctionCall ||
|
| + pc_entry->builtin_id() == Builtins::kFunctionApply) {
|
| + // When current function is FunctionCall or FunctionApply builtin the
|
| + // top frame is either frame of the calling JS function or internal
|
| + // frame. In the latter case we know the caller for sure but in the
|
| + // former case we don't so we simply replace the frame with
|
| + // 'unresolved' entry.
|
| + if (sample.top_frame_type == StackFrame::JAVA_SCRIPT) {
|
| + *entry++ = unresolved_entry_;
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
| for (const Address* stack_pos = sample.stack,
|
|
|