Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1642)

Unified Diff: src/profile-generator.cc

Issue 2083005: CPU profiler: add secure profiles by filtering out functions using security tokens. (Closed)
Patch Set: Reworded comment Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/profile-generator.cc
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 4c2a330898145beadb4d226657fe52ac62516eaa..d2ae3deb2c0d00010fb4906f133b585e07fa770d 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -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 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 @@ double ProfileNode::GetTotalMillis() const {
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 @@ namespace {
class DeleteNodesCallback {
public:
+ void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
+
void AfterAllChildrenTraversed(ProfileNode* node) {
delete node;
}
@@ -104,14 +166,19 @@ class DeleteNodesCallback {
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 @@ void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) {
}
+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 @@ class Position {
// 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 @@ void ProfileTree::TraverseDepthFirstPostOrder(Callback* callback) {
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 @@ namespace {
class CalculateTotalTicksCallback {
public:
+ void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
+
void AfterAllChildrenTraversed(ProfileNode* node) {
node->IncreaseTotalTicks(node->self_ticks());
}
@@ -209,7 +343,7 @@ class CalculateTotalTicksCallback {
void ProfileTree::CalculateTotalTicks() {
CalculateTotalTicksCallback cb;
- TraverseDepthFirstPostOrder(&cb);
+ TraverseDepthFirst(&cb);
}
@@ -238,6 +372,15 @@ void CpuProfile::SetActualSamplingRate(double 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() {
OS::Print("top down ");
top_down_.ShortPrint();
@@ -259,12 +402,13 @@ const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
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 @@ void CodeMap::Print() {
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 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) {
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 @@ bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) {
}
-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 @@ CpuProfile* CpuProfilesCollection::StopProfiling(const char* title,
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 = 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* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
CodeEntry::kEmptyNamePrefix,
GetFunctionName(name),
GetName(resource_name),
- line_number);
+ line_number,
+ CodeEntry::kNoSecurityToken);
code_entries_.Add(entry);
return entry;
}
@@ -411,7 +623,8 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
CodeEntry::kEmptyNamePrefix,
GetFunctionName(name),
"",
- v8::CpuProfileNode::kNoLineNumberInfo);
+ v8::CpuProfileNode::kNoLineNumberInfo,
+ CodeEntry::kNoSecurityToken);
code_entries_.Add(entry);
return entry;
}
@@ -424,7 +637,8 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
name_prefix,
GetName(name),
"",
- v8::CpuProfileNode::kNoLineNumberInfo);
+ v8::CpuProfileNode::kNoLineNumberInfo,
+ CodeEntry::kInheritsSecurityToken);
code_entries_.Add(entry);
return entry;
}
@@ -436,7 +650,15 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
"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;
}
@@ -547,8 +769,13 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
*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++;
}
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698