Revision: 4673
Author: [email protected]
Date: Tue May 18 07:19:33 2010
Log: CPU profiler: add secure profiles by filtering out functions using
security tokens.
As several pages can run in a single V8 instance, it is possible to
have functions from different security contexts intermixed in a single
CPU profile. To avoid exposing function names from one page to
another, filtering is introduced.
The basic idea is that instead of capturing return addresses from
stack, we're now capturing JSFunction addresses (as we anyway work
only with JS stack frames.) Each JSFunction can reach out for
context's security token. When providing a profile to a page, the
profile is filtered using the security token of caller page. Any
functions with different security tokens are filtered out (yes, we
only do fast path check for now) and their ticks are attributed to
their parents.
Review URL: http://codereview.chromium.org/2083005
http://code.google.com/p/v8/source/detail?r=4673
Modified:
/branches/bleeding_edge/include/v8-profiler.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/cpu-profiler-inl.h
/branches/bleeding_edge/src/cpu-profiler.cc
/branches/bleeding_edge/src/cpu-profiler.h
/branches/bleeding_edge/src/log.cc
/branches/bleeding_edge/src/profile-generator-inl.h
/branches/bleeding_edge/src/profile-generator.cc
/branches/bleeding_edge/src/profile-generator.h
/branches/bleeding_edge/test/cctest/test-cpu-profiler.cc
/branches/bleeding_edge/test/cctest/test-log-stack-tracer.cc
/branches/bleeding_edge/test/cctest/test-profile-generator.cc
=======================================
--- /branches/bleeding_edge/include/v8-profiler.h Thu May 6 00:32:44 2010
+++ /branches/bleeding_edge/include/v8-profiler.h Tue May 18 07:19:33 2010
@@ -139,6 +139,15 @@
*/
class V8EXPORT CpuProfiler {
public:
+ /**
+ * A note on security tokens usage. As scripts from different
+ * origins can run inside a single V8 instance, it is possible to
+ * have functions from different security contexts intermixed in a
+ * single CPU profile. To avoid exposing function names belonging to
+ * other contexts, filtering by security token is performed while
+ * obtaining profiling results.
+ */
+
/**
* Returns the number of profiles collected (doesn't include
* profiles that are being collected at the moment of call.)
@@ -146,16 +155,22 @@
static int GetProfilesCount();
/** Returns a profile by index. */
- static const CpuProfile* GetProfile(int index);
+ static const CpuProfile* GetProfile(
+ int index,
+ Handle<Value> security_token = Handle<Value>());
/** Returns a profile by uid. */
- static const CpuProfile* FindProfile(unsigned uid);
+ static const CpuProfile* FindProfile(
+ unsigned uid,
+ Handle<Value> security_token = Handle<Value>());
/**
* Starts collecting CPU profile. Title may be an empty string. It
* is allowed to have several profiles being collected at
* once. Attempts to start collecting several profiles with the same
- * title are silently ignored.
+ * title are silently ignored. While collecting a profile, functions
+ * from all security contexts are included in it. The token-based
+ * filtering is only performed when querying for a profile.
*/
static void StartProfiling(Handle<String> title);
@@ -163,7 +178,9 @@
* Stops collecting CPU profile with a given title and returns it.
* If the title given is empty, finishes the last profile started.
*/
- static const CpuProfile* StopProfiling(Handle<String> title);
+ static const CpuProfile* StopProfiling(
+ Handle<String> title,
+ Handle<Value> security_token = Handle<Value>());
};
=======================================
--- /branches/bleeding_edge/src/api.cc Thu May 6 00:32:44 2010
+++ /branches/bleeding_edge/src/api.cc Tue May 18 07:19:33 2010
@@ -4250,15 +4250,23 @@
}
-const CpuProfile* CpuProfiler::GetProfile(int index) {
+const CpuProfile* CpuProfiler::GetProfile(int index,
+ Handle<Value> security_token) {
IsDeadCheck("v8::CpuProfiler::GetProfile");
- return reinterpret_cast<const
CpuProfile*>(i::CpuProfiler::GetProfile(index));
+ return reinterpret_cast<const CpuProfile*>(
+ i::CpuProfiler::GetProfile(
+ security_token.IsEmpty() ? NULL :
*Utils::OpenHandle(*security_token),
+ index));
}
-const CpuProfile* CpuProfiler::FindProfile(unsigned uid) {
+const CpuProfile* CpuProfiler::FindProfile(unsigned uid,
+ Handle<Value> security_token) {
IsDeadCheck("v8::CpuProfiler::FindProfile");
- return reinterpret_cast<const
CpuProfile*>(i::CpuProfiler::FindProfile(uid));
+ return reinterpret_cast<const CpuProfile*>(
+ i::CpuProfiler::FindProfile(
+ security_token.IsEmpty() ? NULL :
*Utils::OpenHandle(*security_token),
+ uid));
}
@@ -4268,10 +4276,13 @@
}
-const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title) {
+const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title,
+ Handle<Value> security_token)
{
IsDeadCheck("v8::CpuProfiler::StopProfiling");
return reinterpret_cast<const CpuProfile*>(
- i::CpuProfiler::StopProfiling(*Utils::OpenHandle(*title)));
+ i::CpuProfiler::StopProfiling(
+ security_token.IsEmpty() ? NULL :
*Utils::OpenHandle(*security_token),
+ *Utils::OpenHandle(*title)));
}
#endif // ENABLE_LOGGING_AND_PROFILING
=======================================
--- /branches/bleeding_edge/src/cpu-profiler-inl.h Thu Apr 15 04:37:29 2010
+++ /branches/bleeding_edge/src/cpu-profiler-inl.h Tue May 18 07:19:33 2010
@@ -54,7 +54,7 @@
void CodeAliasEventRecord::UpdateCodeMap(CodeMap* code_map) {
- code_map->AddAlias(alias, start);
+ code_map->AddAlias(start, entry, code_start);
}
=======================================
--- /branches/bleeding_edge/src/cpu-profiler.cc Wed Apr 21 07:07:13 2010
+++ /branches/bleeding_edge/src/cpu-profiler.cc Tue May 18 07:19:33 2010
@@ -141,13 +141,15 @@
void ProfilerEventsProcessor::FunctionCreateEvent(Address alias,
- Address start) {
+ Address start,
+ int security_token_id) {
CodeEventsContainer evt_rec;
CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_;
rec->type = CodeEventRecord::CODE_ALIAS;
rec->order = ++enqueue_order_;
- rec->alias = alias;
- rec->start = start;
+ rec->start = alias;
+ rec->entry = generator_->NewCodeEntry(security_token_id);
+ rec->code_start = start;
events_buffer_.Enqueue(evt_rec);
}
@@ -257,26 +259,30 @@
}
-CpuProfile* CpuProfiler::StopProfiling(String* title) {
- return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL;
+CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String*
title) {
+ return is_profiling() ?
+ singleton_->StopCollectingProfile(security_token, title) : NULL;
}
int CpuProfiler::GetProfilesCount() {
ASSERT(singleton_ != NULL);
- return singleton_->profiles_->profiles()->length();
+ // The count of profiles doesn't depend on a security token.
+ return
singleton_->profiles_->Profiles(CodeEntry::kNoSecurityToken)->length();
}
-CpuProfile* CpuProfiler::GetProfile(int index) {
+CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
ASSERT(singleton_ != NULL);
- return singleton_->profiles_->profiles()->at(index);
+ const int token =
singleton_->token_enumerator_->GetTokenId(security_token);
+ return singleton_->profiles_->Profiles(token)->at(index);
}
-CpuProfile* CpuProfiler::FindProfile(unsigned uid) {
+CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid)
{
ASSERT(singleton_ != NULL);
- return singleton_->profiles_->GetProfile(uid);
+ const int token =
singleton_->token_enumerator_->GetTokenId(security_token);
+ return singleton_->profiles_->GetProfile(token, uid);
}
@@ -348,8 +354,15 @@
void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
+ int security_token_id = CodeEntry::kNoSecurityToken;
+ if (function->unchecked_context()->IsContext()) {
+ security_token_id = singleton_->token_enumerator_->GetTokenId(
+ function->context()->global_context()->security_token());
+ }
singleton_->processor_->FunctionCreateEvent(
- function->address(), function->code()->address());
+ function->address(),
+ function->code()->address(),
+ security_token_id);
}
@@ -388,12 +401,14 @@
CpuProfiler::CpuProfiler()
: profiles_(new CpuProfilesCollection()),
next_profile_uid_(1),
+ token_enumerator_(new TokenEnumerator()),
generator_(NULL),
processor_(NULL) {
}
CpuProfiler::~CpuProfiler() {
+ delete token_enumerator_;
delete profiles_;
}
@@ -438,7 +453,9 @@
CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile();
- CpuProfile* result = profiles_->StopProfiling(title,
actual_sampling_rate);
+ CpuProfile* result =
profiles_->StopProfiling(CodeEntry::kNoSecurityToken,
+ title,
+ actual_sampling_rate);
if (result != NULL) {
result->Print();
}
@@ -446,10 +463,12 @@
}
-CpuProfile* CpuProfiler::StopCollectingProfile(String* title) {
+CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
+ String* title) {
const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile();
- return profiles_->StopProfiling(title, actual_sampling_rate);
+ int token = token_enumerator_->GetTokenId(security_token);
+ return profiles_->StopProfiling(token, title, actual_sampling_rate);
}
=======================================
--- /branches/bleeding_edge/src/cpu-profiler.h Wed Apr 14 11:48:05 2010
+++ /branches/bleeding_edge/src/cpu-profiler.h Tue May 18 07:19:33 2010
@@ -41,7 +41,7 @@
class CpuProfile;
class CpuProfilesCollection;
class ProfileGenerator;
-
+class TokenEnumerator;
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
@@ -94,8 +94,9 @@
class CodeAliasEventRecord : public CodeEventRecord {
public:
- Address alias;
Address start;
+ CodeEntry* entry;
+ Address code_start;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
@@ -151,7 +152,7 @@
Address start, unsigned size);
void CodeMoveEvent(Address from, Address to);
void CodeDeleteEvent(Address from);
- void FunctionCreateEvent(Address alias, Address start);
+ void FunctionCreateEvent(Address alias, Address start, int
security_token_id);
void FunctionMoveEvent(Address from, Address to);
void FunctionDeleteEvent(Address from);
void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
@@ -212,10 +213,10 @@
static void StartProfiling(const char* title);
static void StartProfiling(String* title);
static CpuProfile* StopProfiling(const char* title);
- static CpuProfile* StopProfiling(String* title);
+ static CpuProfile* StopProfiling(Object* security_token, String* title);
static int GetProfilesCount();
- static CpuProfile* GetProfile(int index);
- static CpuProfile* FindProfile(unsigned uid);
+ static CpuProfile* GetProfile(Object* security_token, int index);
+ static CpuProfile* FindProfile(Object* security_token, unsigned uid);
// Invoked from stack sampler (thread or signal handler.)
static TickSample* TickSampleEvent();
@@ -252,11 +253,12 @@
void StartCollectingProfile(String* title);
void StartProcessorIfNotStarted();
CpuProfile* StopCollectingProfile(const char* title);
- CpuProfile* StopCollectingProfile(String* title);
+ CpuProfile* StopCollectingProfile(Object* security_token, String* title);
void StopProcessorIfLastProfile();
CpuProfilesCollection* profiles_;
unsigned next_profile_uid_;
+ TokenEnumerator* token_enumerator_;
ProfileGenerator* generator_;
ProfilerEventsProcessor* processor_;
int saved_logging_nesting_;
=======================================
--- /branches/bleeding_edge/src/log.cc Wed May 5 05:25:58 2010
+++ /branches/bleeding_edge/src/log.cc Tue May 18 07:19:33 2010
@@ -170,7 +170,7 @@
SafeStackTraceFrameIterator it(sample->fp, sample->sp,
sample->sp, js_entry_sp);
while (!it.done() && i < TickSample::kMaxFramesCount) {
- sample->stack[i++] = it.frame()->pc();
+ sample->stack[i++] = reinterpret_cast<Address>(it.frame()->function());
it.Advance();
}
sample->frames_count = i;
=======================================
--- /branches/bleeding_edge/src/profile-generator-inl.h Thu Apr 15 04:37:29
2010
+++ /branches/bleeding_edge/src/profile-generator-inl.h Tue May 18 07:19:33
2010
@@ -35,17 +35,30 @@
namespace v8 {
namespace internal {
+CodeEntry::CodeEntry(int security_token_id)
+ : call_uid_(0),
+ tag_(Logger::FUNCTION_TAG),
+ name_prefix_(kEmptyNamePrefix),
+ name_(""),
+ resource_name_(""),
+ line_number_(0),
+ security_token_id_(security_token_id) {
+}
+
+
CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix,
const char* name,
const char* resource_name,
- int line_number)
+ int line_number,
+ int security_token_id)
: call_uid_(next_call_uid_++),
tag_(tag),
name_prefix_(name_prefix),
name_(name),
resource_name_(resource_name),
- line_number_(line_number) {
+ line_number_(line_number),
+ security_token_id_(security_token_id) {
}
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Thu Apr 15 07:12:17
2010
+++ /branches/bleeding_edge/src/profile-generator.cc Tue May 18 07:19:33
2010
@@ -28,6 +28,7 @@
#ifdef ENABLE_LOGGING_AND_PROFILING
#include "v8.h"
+#include "global-handles.h"
#include "profile-generator-inl.h"
@@ -35,12 +36,70 @@
namespace v8 {
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);
}
@@ -139,6 +206,70 @@
}
node->IncrementSelfTicks();
}
+
+
+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) {
@@ -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();
- }
- }
- } while (stack.length() > 1 || stack.last().has_current_child());
+ }
+ // Remove child from the stack.
+ stack.RemoveLast();
+ }
+ }
}
@@ -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);
}
@@ -236,6 +370,15 @@
top_down_.SetTickRatePerMs(actual_sampling_rate);
bottom_up_.SetTickRatePerMs(actual_sampling_rate);
}
+
+
+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() {
@@ -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,29 +516,89 @@
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;
- }
- return profile;
+ entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1);
+ return GetProfile(security_token_id, profile->uid());
+ }
+ 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 = reinterpret_cast<int>(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;
}
@@ -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,10 +650,18 @@
"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) {
@@ -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++;
}
=======================================
--- /branches/bleeding_edge/src/profile-generator.h Thu Apr 15 04:37:29 2010
+++ /branches/bleeding_edge/src/profile-generator.h Tue May 18 07:19:33 2010
@@ -35,14 +35,34 @@
namespace v8 {
namespace internal {
+class TokenEnumerator {
+ public:
+ TokenEnumerator();
+ ~TokenEnumerator();
+ int GetTokenId(Object* token);
+
+ private:
+ static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
+ void* parameter);
+ void TokenRemoved(Object** token_location);
+
+ List<Object**> token_locations_;
+ List<bool> token_removed_;
+
+ friend class TokenEnumeratorTester;
+};
+
+
class CodeEntry {
public:
+ explicit INLINE(CodeEntry(int security_token_id));
// CodeEntry doesn't own name strings, just references them.
INLINE(CodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix,
const char* name,
const char* resource_name,
- int line_number));
+ int line_number,
+ int security_token_id));
INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
INLINE(const char* name_prefix() const) { return name_prefix_; }
@@ -51,18 +71,24 @@
INLINE(const char* resource_name() const) { return resource_name_; }
INLINE(int line_number() const) { return line_number_; }
INLINE(unsigned call_uid() const) { return call_uid_; }
+ INLINE(int security_token_id() const) { return security_token_id_; }
INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
+ void CopyData(const CodeEntry& source);
+
static const char* kEmptyNamePrefix;
+ static const int kNoSecurityToken = -1;
+ static const int kInheritsSecurityToken = -2;
private:
- const unsigned call_uid_;
+ unsigned call_uid_;
Logger::LogEventsAndTags tag_;
const char* name_prefix_;
const char* name_;
const char* resource_name_;
int line_number_;
+ int security_token_id_;
static unsigned next_call_uid_;
@@ -79,6 +105,7 @@
ProfileNode* FindChild(CodeEntry* entry);
ProfileNode* FindOrAddChild(CodeEntry* entry);
INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
+ INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount;
}
INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ +=
amount; }
INLINE(CodeEntry* entry() const) { return entry_; }
@@ -119,6 +146,7 @@
void AddPathFromEnd(const Vector<CodeEntry*>& path);
void AddPathFromStart(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
+ void FilteredClone(ProfileTree* src, int security_token_id);
double TicksToMillis(unsigned ticks) const {
return ticks * ms_to_ticks_scale_;
@@ -133,7 +161,7 @@
private:
template <typename Callback>
- void TraverseDepthFirstPostOrder(Callback* callback);
+ void TraverseDepthFirst(Callback* callback);
CodeEntry root_entry_;
ProfileNode* root_;
@@ -152,6 +180,7 @@
void AddPath(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
void SetActualSamplingRate(double actual_sampling_rate);
+ CpuProfile* FilteredClone(int security_token_id);
INLINE(const char* title() const) { return title_; }
INLINE(unsigned uid() const) { return uid_; }
@@ -179,7 +208,7 @@
INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
INLINE(void MoveCode(Address from, Address to));
INLINE(void DeleteCode(Address addr));
- void AddAlias(Address alias, Address addr);
+ void AddAlias(Address start, CodeEntry* entry, Address code_start);
CodeEntry* FindEntry(Address addr);
void Print();
@@ -221,10 +250,14 @@
bool StartProfiling(const char* title, unsigned uid);
bool StartProfiling(String* title, unsigned uid);
- CpuProfile* StopProfiling(const char* title, double
actual_sampling_rate);
- CpuProfile* StopProfiling(String* title, double actual_sampling_rate);
- INLINE(List<CpuProfile*>* profiles()) { return &profiles_; }
- CpuProfile* GetProfile(unsigned uid);
+ CpuProfile* StopProfiling(int security_token_id,
+ const char* title,
+ double actual_sampling_rate);
+ CpuProfile* StopProfiling(int security_token_id,
+ String* title,
+ double actual_sampling_rate);
+ List<CpuProfile*>* Profiles(int security_token_id);
+ CpuProfile* GetProfile(int security_token_id, unsigned uid);
inline bool is_last_profile();
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
@@ -233,6 +266,7 @@
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix, String* name);
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
+ CodeEntry* NewCodeEntry(int security_token_id);
// Called from profile generator thread.
void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
@@ -242,13 +276,15 @@
INLINE(const char* GetFunctionName(const char* name));
const char* GetName(String* name);
const char* GetName(int args_count);
+ List<CpuProfile*>* GetProfilesList(int security_token_id);
+ int TokenToIndex(int security_token_id);
INLINE(static bool StringsMatch(void* key1, void* key2)) {
return strcmp(reinterpret_cast<char*>(key1),
reinterpret_cast<char*>(key2)) == 0;
}
- INLINE(static bool CpuProfilesMatch(void* key1, void* key2)) {
+ INLINE(static bool UidsMatch(void* key1, void* key2)) {
return key1 == key2;
}
@@ -257,8 +293,8 @@
// args_count -> char*
List<char*> args_count_names_;
List<CodeEntry*> code_entries_;
- List<CpuProfile*> profiles_;
- // uid -> CpuProfile*
+ List<List<CpuProfile*>* > profiles_by_token_;
+ // uid -> index
HashMap profiles_uids_;
// Accessed by VM thread and profile generator thread.
@@ -331,6 +367,10 @@
int args_count)) {
return profiles_->NewCodeEntry(tag, args_count);
}
+
+ INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
+ return profiles_->NewCodeEntry(security_token_id);
+ }
void RecordTickSample(const TickSample& sample);
=======================================
--- /branches/bleeding_edge/test/cctest/test-cpu-profiler.cc Thu Apr 15
04:37:29 2010
+++ /branches/bleeding_edge/test/cctest/test-cpu-profiler.cc Tue May 18
07:19:33 2010
@@ -114,7 +114,8 @@
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600),
0x10);
processor.CodeDeleteEvent(ToAddress(0x1600));
- processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000));
+ processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000),
+ CodeEntry::kNoSecurityToken);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
@@ -176,7 +177,8 @@
processor.Stop();
processor.Join();
- CpuProfile* profile = profiles.StopProfiling("", 1);
+ CpuProfile* profile =
+ profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
// Check call trees.
=======================================
--- /branches/bleeding_edge/test/cctest/test-log-stack-tracer.cc Wed Apr 7
01:18:51 2010
+++ /branches/bleeding_edge/test/cctest/test-log-stack-tracer.cc Tue May 18
07:19:33 2010
@@ -64,28 +64,6 @@
DoTrace(fp);
*(Top::c_entry_fp_address()) = saved_c_frame_fp;
}
-
-
-static void CheckRetAddrIsInFunction(const char* func_name,
- Address ret_addr,
- Address func_start_addr,
- unsigned int func_len) {
- printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n",
- func_name, func_start_addr, ret_addr, func_start_addr + func_len);
- CHECK_GE(ret_addr, func_start_addr);
- CHECK_GE(func_start_addr + func_len, ret_addr);
-}
-
-
-static void CheckRetAddrIsInJSFunction(const char* func_name,
- Address ret_addr,
- Handle<JSFunction> func) {
- v8::internal::Code* func_code = func->code();
- CheckRetAddrIsInFunction(
- func_name, ret_addr,
- func_code->instruction_start(),
- func_code->ExecutableSize());
-}
// --- T r a c e E x t e n s i o n ---
@@ -209,11 +187,16 @@
}
-static void CheckRetAddrIsInJSFunction(const char* func_name,
- Address ret_addr) {
- CheckRetAddrIsInJSFunction(func_name,
- ret_addr,
- GetGlobalJSFunction(func_name));
+static void CheckObjectIsJSFunction(const char* func_name,
+ Address addr) {
+ i::Object* obj = reinterpret_cast<i::Object*>(addr);
+ CHECK(obj->IsJSFunction());
+ CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
+ i::SmartPointer<char> found_name =
+ i::String::cast(
+ JSFunction::cast(
+ obj)->shared()->name())->ToCString();
+ CHECK_EQ(func_name, *found_name);
}
@@ -272,6 +255,7 @@
Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
CHECK(!func.is_null());
i::FLAG_allow_natives_syntax = allow_natives_syntax;
+ func->shared()->set_name(*NewString(func_name));
#ifdef DEBUG
v8::internal::Code* func_code = func->code();
@@ -313,10 +297,8 @@
// StackTracer::Trace
CHECK_GT(sample.frames_count, 1);
// Stack tracing will start from the first JS function,
i.e. "JSFuncDoTrace"
- CheckRetAddrIsInJSFunction("JSFuncDoTrace",
- sample.stack[0]);
- CheckRetAddrIsInJSFunction("JSTrace",
- sample.stack[1]);
+ CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]);
+ CheckObjectIsJSFunction("JSTrace", sample.stack[1]);
}
@@ -359,10 +341,8 @@
sample.function);
CHECK_GT(sample.frames_count, 1);
// Stack sampling will start from the caller of JSFuncDoTrace,
i.e. "JSTrace"
- CheckRetAddrIsInJSFunction("JSTrace",
- sample.stack[0]);
- CheckRetAddrIsInJSFunction("OuterJSTrace",
- sample.stack[1]);
+ CheckObjectIsJSFunction("JSTrace", sample.stack[0]);
+ CheckObjectIsJSFunction("OuterJSTrace", sample.stack[1]);
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-profile-generator.cc Thu Apr
15 04:37:29 2010
+++ /branches/bleeding_edge/test/cctest/test-profile-generator.cc Tue May
18 07:19:33 2010
@@ -19,22 +19,64 @@
using i::ProfileGenerator;
using i::SampleRateCalculator;
using i::TickSample;
+using i::TokenEnumerator;
using i::Vector;
+namespace v8 {
+namespace internal {
+
+class TokenEnumeratorTester {
+ public:
+ static i::List<bool>* token_removed(TokenEnumerator* te) {
+ return &te->token_removed_;
+ }
+};
+
+} } // namespace v8::internal
+
+TEST(TokenEnumerator) {
+ TokenEnumerator te;
+ CHECK_EQ(CodeEntry::kNoSecurityToken, te.GetTokenId(NULL));
+ v8::HandleScope hs;
+ v8::Local<v8::String> token1(v8::String::New("1"));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ v8::Local<v8::String> token2(v8::String::New("2"));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ {
+ v8::HandleScope hs;
+ v8::Local<v8::String> token3(v8::String::New("3"));
+ CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ }
+ CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
+ i::Heap::CollectAllGarbage(false);
+ CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+}
+
+
TEST(ProfileNodeFindOrAddChild) {
ProfileNode node(NULL, NULL);
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
CodeEntry::kNoSecurityToken);
ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
CHECK_NE(NULL, childNode1);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
CodeEntry::kNoSecurityToken);
ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
CHECK_NE(NULL, childNode2);
CHECK_NE(childNode1, childNode2);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
CodeEntry::kNoSecurityToken);
ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
CHECK_NE(NULL, childNode3);
CHECK_NE(childNode1, childNode3);
@@ -75,9 +117,12 @@
} // namespace
TEST(ProfileTreeAddPathFromStart) {
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
CodeEntry::kNoSecurityToken);
ProfileTree tree;
ProfileTreeTestHelper helper(&tree);
CHECK_EQ(NULL, helper.Walk(&entry1));
@@ -142,9 +187,12 @@
TEST(ProfileTreeAddPathFromEnd) {
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
CodeEntry::kNoSecurityToken);
ProfileTree tree;
ProfileTreeTestHelper helper(&tree);
CHECK_EQ(NULL, helper.Walk(&entry1));
@@ -222,11 +270,30 @@
CHECK_EQ(1, empty_tree.root()->total_ticks());
CHECK_EQ(1, empty_tree.root()->self_ticks());
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
CodeEntry::kNoSecurityToken);
CodeEntry* e1_path[] = {&entry1};
Vector<CodeEntry*> e1_path_vec(
e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
+
+ ProfileTree single_child_tree;
+ single_child_tree.AddPathFromStart(e1_path_vec);
+ single_child_tree.root()->IncrementSelfTicks();
+ CHECK_EQ(0, single_child_tree.root()->total_ticks());
+ CHECK_EQ(1, single_child_tree.root()->self_ticks());
+ ProfileTreeTestHelper single_child_helper(&single_child_tree);
+ ProfileNode* node1 = single_child_helper.Walk(&entry1);
+ CHECK_NE(NULL, node1);
+ CHECK_EQ(0, node1->total_ticks());
+ CHECK_EQ(1, node1->self_ticks());
+ single_child_tree.CalculateTotalTicks();
+ CHECK_EQ(2, single_child_tree.root()->total_ticks());
+ CHECK_EQ(1, single_child_tree.root()->self_ticks());
+ CHECK_EQ(1, node1->total_ticks());
+ CHECK_EQ(1, node1->self_ticks());
+
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
CodeEntry::kNoSecurityToken);
CodeEntry* e1_e2_path[] = {&entry1, &entry2};
Vector<CodeEntry*> e1_e2_path_vec(
e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
@@ -241,7 +308,7 @@
// Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
CHECK_EQ(0, flat_tree.root()->total_ticks());
CHECK_EQ(0, flat_tree.root()->self_ticks());
- ProfileNode* node1 = flat_helper.Walk(&entry1);
+ node1 = flat_helper.Walk(&entry1);
CHECK_NE(NULL, node1);
CHECK_EQ(0, node1->total_ticks());
CHECK_EQ(2, node1->self_ticks());
@@ -261,7 +328,8 @@
CodeEntry* e2_path[] = {&entry2};
Vector<CodeEntry*> e2_path_vec(
e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
CodeEntry::kNoSecurityToken);
CodeEntry* e3_path[] = {&entry3};
Vector<CodeEntry*> e3_path_vec(
e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
@@ -314,6 +382,105 @@
CHECK_EQ(4, node3->total_ticks());
CHECK_EQ(4, node3->self_ticks());
}
+
+
+TEST(ProfileTreeFilteredClone) {
+ ProfileTree source_tree;
+ const int token0 = 0, token1 = 1, token2 = 2;
+ CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
+ CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
+ CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
+ CodeEntry entry4(
+ i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
+ CodeEntry::kInheritsSecurityToken);
+
+ {
+ CodeEntry* e1_e2_path[] = {&entry1, &entry2};
+ Vector<CodeEntry*> e1_e2_path_vec(
+ e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
+ source_tree.AddPathFromStart(e1_e2_path_vec);
+ CodeEntry* e2_e4_path[] = {&entry2, &entry4};
+ Vector<CodeEntry*> e2_e4_path_vec(
+ e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
+ source_tree.AddPathFromStart(e2_e4_path_vec);
+ CodeEntry* e3_e1_path[] = {&entry3, &entry1};
+ Vector<CodeEntry*> e3_e1_path_vec(
+ e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
+ source_tree.AddPathFromStart(e3_e1_path_vec);
+ CodeEntry* e3_e2_path[] = {&entry3, &entry2};
+ Vector<CodeEntry*> e3_e2_path_vec(
+ e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
+ source_tree.AddPathFromStart(e3_e2_path_vec);
+ source_tree.CalculateTotalTicks();
+ // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
+ // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
+ // -> {entry3,0,2,0} -> {entry1,1,1,0}
+ // -> {entry2,1,1,1}
+ CHECK_EQ(4, source_tree.root()->total_ticks());
+ CHECK_EQ(0, source_tree.root()->self_ticks());
+ }
+
+ {
+ ProfileTree token0_tree;
+ token0_tree.FilteredClone(&source_tree, token0);
+ // Should be -> {entry1,1,1,0}
+ // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
+ // [self ticks from filtered nodes are attributed to their parents]
+ CHECK_EQ(4, token0_tree.root()->total_ticks());
+ CHECK_EQ(1, token0_tree.root()->self_ticks());
+ ProfileTreeTestHelper token0_helper(&token0_tree);
+ ProfileNode* node1 = token0_helper.Walk(&entry1);
+ CHECK_NE(NULL, node1);
+ CHECK_EQ(1, node1->total_ticks());
+ CHECK_EQ(1, node1->self_ticks());
+ CHECK_EQ(NULL, token0_helper.Walk(&entry2));
+ ProfileNode* node3 = token0_helper.Walk(&entry3);
+ CHECK_NE(NULL, node3);
+ CHECK_EQ(2, node3->total_ticks());
+ CHECK_EQ(1, node3->self_ticks());
+ ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
+ CHECK_NE(NULL, node3_1);
+ CHECK_EQ(1, node3_1->total_ticks());
+ CHECK_EQ(1, node3_1->self_ticks());
+ CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
+ }
+
+ {
+ ProfileTree token1_tree;
+ token1_tree.FilteredClone(&source_tree, token1);
+ // Should be
+ // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
+ // [child nodes referring to the same entry get merged and
+ // their self times summed up]
+ CHECK_EQ(4, token1_tree.root()->total_ticks());
+ CHECK_EQ(1, token1_tree.root()->self_ticks());
+ ProfileTreeTestHelper token1_helper(&token1_tree);
+ CHECK_EQ(NULL, token1_helper.Walk(&entry1));
+ CHECK_EQ(NULL, token1_helper.Walk(&entry3));
+ ProfileNode* node2 = token1_helper.Walk(&entry2);
+ CHECK_NE(NULL, node2);
+ CHECK_EQ(3, node2->total_ticks());
+ CHECK_EQ(2, node2->self_ticks());
+ ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
+ CHECK_NE(NULL, node2_4);
+ CHECK_EQ(1, node2_4->total_ticks());
+ CHECK_EQ(1, node2_4->self_ticks());
+ }
+
+ {
+ ProfileTree token2_tree;
+ token2_tree.FilteredClone(&source_tree, token2);
+ // Should be
+ // {root,4,4,-1}
+ // [no nodes, all ticks get migrated into root node]
+ CHECK_EQ(4, token2_tree.root()->total_ticks());
+ CHECK_EQ(4, token2_tree.root()->self_ticks());
+ ProfileTreeTestHelper token2_helper(&token2_tree);
+ CHECK_EQ(NULL, token2_helper.Walk(&entry1));
+ CHECK_EQ(NULL, token2_helper.Walk(&entry2));
+ CHECK_EQ(NULL, token2_helper.Walk(&entry3));
+ }
+}
static inline i::Address ToAddress(int n) {
@@ -322,10 +489,14 @@
TEST(CodeMapAddCode) {
CodeMap code_map;
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
- CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry4(
+ i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
CodeEntry::kNoSecurityToken);
code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
@@ -352,8 +523,10 @@
TEST(CodeMapMoveAndDeleteCode) {
CodeMap code_map;
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
CodeEntry::kNoSecurityToken);
code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
@@ -425,7 +598,8 @@
sample3.frames_count = 2;
generator.RecordTickSample(sample3);
- CpuProfile* profile = profiles.StopProfiling("", 1);
+ CpuProfile* profile =
+ profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
ProfileTreeTestHelper top_down_test_helper(profile->top_down());
CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev