Index: runtime/vm/profiler_service.cc |
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc |
index bfd4912fccdb83dd1f484bf0f092eef7010bf2aa..af03a3cca55ba0d464a528a7e8c0db842946a1a7 100644 |
--- a/runtime/vm/profiler_service.cc |
+++ b/runtime/vm/profiler_service.cc |
@@ -196,25 +196,9 @@ class ProfileFunction : public ZoneAllocated { |
} |
void PrintToJSONObject(JSONObject* func) { |
- if (kind() == kNativeFunction) { |
- func->AddProperty("type", "@Function"); |
- func->AddProperty("name", name()); |
- func->AddProperty("kind", "Native"); |
- } else if (kind() == kTagFunction) { |
- func->AddProperty("type", "@Function"); |
- func->AddProperty("kind", "Tag"); |
- func->AddProperty("name", name()); |
- } else if (kind() == kUnkownFunction) { |
- func->AddProperty("type", "@Function"); |
- func->AddProperty("name", name()); |
- func->AddProperty("kind", "Collected"); |
- } else if (kind() == kStubFunction) { |
- func->AddProperty("type", "@Function"); |
- func->AddProperty("name", name()); |
- func->AddProperty("kind", "Stub"); |
- } else { |
- UNREACHABLE(); |
- } |
+ func->AddProperty("type", "@Function"); |
+ func->AddProperty("name", name()); |
+ func->AddProperty("kind", KindToCString(kind())); |
} |
void PrintToJSONArray(JSONArray* functions) { |
@@ -630,7 +614,7 @@ class CodeRegion : public ZoneAllocated { |
ASSERT(kind() == kReusedCode); |
JSONObject obj(profile_code_obj, "code"); |
obj.AddProperty("type", "@Code"); |
- obj.AddProperty("kind", "Reused"); |
+ obj.AddProperty("kind", "Collected"); |
obj.AddProperty("name", name()); |
obj.AddPropertyF("start", "%" Px "", start()); |
obj.AddPropertyF("end", "%" Px "", end()); |
@@ -1394,18 +1378,19 @@ class ProfileFunctionTrieNode : public ZoneAllocated { |
}; |
-class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor { |
+class ProfileFunctionTrieBuilder : public SampleVisitor { |
public: |
- ProfileFunctionExclusiveTrieBuilder(Isolate* isolate, |
- CodeRegionTable* live_code_table, |
- CodeRegionTable* dead_code_table, |
- CodeRegionTable* tag_code_table, |
- ProfileFunctionTable* function_table) |
+ ProfileFunctionTrieBuilder(Isolate* isolate, |
+ CodeRegionTable* live_code_table, |
+ CodeRegionTable* dead_code_table, |
+ CodeRegionTable* tag_code_table, |
+ ProfileFunctionTable* function_table) |
: SampleVisitor(isolate), |
live_code_table_(live_code_table), |
dead_code_table_(dead_code_table), |
tag_code_table_(tag_code_table), |
function_table_(function_table), |
+ inclusive_(false), |
trace_(false), |
trace_code_filter_(NULL) { |
ASSERT(live_code_table_ != NULL); |
@@ -1419,20 +1404,46 @@ class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor { |
ASSERT(root_index >= 0); |
CodeRegion* region = tag_code_table_->At(root_index); |
ASSERT(region != NULL); |
- |
ProfileFunction* function = region->function(); |
- root_ = new ProfileFunctionTrieNode(function->index()); |
+ ASSERT(function != NULL); |
+ |
+ exclusive_root_ = new ProfileFunctionTrieNode(function->index()); |
+ inclusive_root_ = new ProfileFunctionTrieNode(function->index()); |
} |
void VisitSample(Sample* sample) { |
+ inclusive_ = false; |
+ ProcessSampleExclusive(sample); |
+ inclusive_ = true; |
+ ProcessSampleInclusive(sample); |
+ } |
+ |
+ ProfileFunctionTrieNode* exclusive_root() const { |
+ return exclusive_root_; |
+ } |
+ |
+ ProfileFunctionTrieNode* inclusive_root() const { |
+ return inclusive_root_; |
+ } |
+ |
+ ProfilerService::TagOrder tag_order() const { |
+ return tag_order_; |
+ } |
+ |
+ void set_tag_order(ProfilerService::TagOrder tag_order) { |
+ tag_order_ = tag_order; |
+ } |
+ |
+ private: |
+ void ProcessSampleInclusive(Sample* sample) { |
// Give the root a tick. |
- root_->Tick(); |
- ProfileFunctionTrieNode* current = root_; |
+ inclusive_root_->Tick(); |
+ ProfileFunctionTrieNode* current = inclusive_root_; |
current = ProcessTags(sample, current); |
// Walk the sampled PCs. |
- for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
+ for (intptr_t i = FLAG_profile_depth - 1; i >= 0; i--) { |
if (sample->At(i) == 0) { |
- break; |
+ continue; |
} |
// If we aren't sampled out of an exit frame and this is the top |
// frame. |
@@ -1443,19 +1454,25 @@ class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor { |
} |
} |
- ProfileFunctionTrieNode* root() const { |
- return root_; |
- } |
- |
- ProfilerService::TagOrder tag_order() const { |
- return tag_order_; |
- } |
- |
- void set_tag_order(ProfilerService::TagOrder tag_order) { |
- tag_order_ = tag_order; |
+ void ProcessSampleExclusive(Sample* sample) { |
+ // Give the root a tick. |
+ exclusive_root_->Tick(); |
+ ProfileFunctionTrieNode* current = exclusive_root_; |
+ current = ProcessTags(sample, current); |
+ // Walk the sampled PCs. |
+ for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
+ if (sample->At(i) == 0) { |
+ break; |
+ } |
+ // If we aren't sampled out of an exit frame and this is the top |
+ // frame. |
+ bool exclusive_tick = (i == 0) && !sample->exit_frame_sample(); |
+ current = ProcessPC(sample->At(i), sample->timestamp(), current, |
+ visited(), exclusive_tick, |
+ sample->missing_frame_inserted()); |
+ } |
} |
- private: |
ProfileFunctionTrieNode* ProcessUserTags(Sample* sample, |
ProfileFunctionTrieNode* current) { |
intptr_t user_tag_index = FindTagIndex(sample->user_tag()); |
@@ -1569,7 +1586,9 @@ class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor { |
OS::Print("[%" Px "] X - %s (%s)\n", |
pc, function->name(), region_name); |
} |
- function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
+ if (!inclusive_) { |
+ function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
+ } |
current = current->GetChild(function->index()); |
current->AddCodeObjectIndex(code_index); |
current->Tick(); |
@@ -1583,33 +1602,55 @@ class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor { |
return current; |
} |
- |
- for (intptr_t i = 0; i < inlined_functions.length(); i++) { |
- Function* inlined_function = inlined_functions[i]; |
- ASSERT(inlined_function != NULL); |
- ASSERT(!inlined_function->IsNull()); |
- const char* inline_name = inlined_function->ToQualifiedCString(); |
- if (trace_) { |
- OS::Print("[%" Px "] %" Pd " - %s (%s)\n", |
- pc, i, inline_name, region_name); |
+ if (inclusive_) { |
+ for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) { |
+ Function* inlined_function = inlined_functions[i]; |
+ ASSERT(inlined_function != NULL); |
+ ASSERT(!inlined_function->IsNull()); |
+ current = ProcessInlinedFunction( |
+ inlined_function, current, inclusive_serial, exclusive, code_index); |
+ exclusive = false; |
} |
- ProfileFunction* function = |
- function_table_->LookupOrAdd(*inlined_function); |
- ASSERT(function != NULL); |
- function->AddCodeObjectIndex(code_index); |
- function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
- exclusive = false; |
- current = current->GetChild(function->index()); |
- current->AddCodeObjectIndex(code_index); |
- current->Tick(); |
- if ((trace_code_filter_ != NULL) && |
- (strstr(region_name, trace_code_filter_) != NULL)) { |
- trace_ = true; |
- OS::Print("Tracing from: %" Px " [%s] ", |
- pc, missing_frame_inserted ? "INSERTED" : ""); |
- Dump(current); |
+ } else { |
+ for (intptr_t i = 0; i < inlined_functions.length(); i++) { |
+ Function* inlined_function = inlined_functions[i]; |
+ ASSERT(inlined_function != NULL); |
+ ASSERT(!inlined_function->IsNull()); |
+ const char* inline_name = inlined_function->ToQualifiedCString(); |
+ if (trace_) { |
+ OS::Print("[%" Px "] %" Pd " - %s (%s)\n", |
+ pc, i, inline_name, region_name); |
+ } |
+ current = ProcessInlinedFunction( |
+ inlined_function, current, inclusive_serial, exclusive, code_index); |
+ exclusive = false; |
+ if ((trace_code_filter_ != NULL) && |
+ (strstr(region_name, trace_code_filter_) != NULL)) { |
+ trace_ = true; |
+ OS::Print("Tracing from: %" Px " [%s] ", |
+ pc, missing_frame_inserted ? "INSERTED" : ""); |
+ Dump(current); |
+ } |
} |
} |
+ |
+ return current; |
+ } |
+ |
+ ProfileFunctionTrieNode* ProcessInlinedFunction( |
+ Function* inlined_function, |
+ ProfileFunctionTrieNode* current, |
+ intptr_t inclusive_serial, |
+ bool exclusive, |
+ intptr_t code_index) { |
+ ProfileFunction* function = |
+ function_table_->LookupOrAdd(*inlined_function); |
+ ASSERT(function != NULL); |
+ function->AddCodeObjectIndex(code_index); |
+ function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
+ current = current->GetChild(function->index()); |
+ current->AddCodeObjectIndex(code_index); |
+ current->Tick(); |
return current; |
} |
@@ -1636,11 +1677,13 @@ class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor { |
} |
ProfilerService::TagOrder tag_order_; |
- ProfileFunctionTrieNode* root_; |
+ ProfileFunctionTrieNode* exclusive_root_; |
+ ProfileFunctionTrieNode* inclusive_root_; |
CodeRegionTable* live_code_table_; |
CodeRegionTable* dead_code_table_; |
CodeRegionTable* tag_code_table_; |
ProfileFunctionTable* function_table_; |
+ bool inclusive_; |
bool trace_; |
const char* trace_code_filter_; |
}; |
@@ -1738,12 +1781,12 @@ class CodeRegionTrieNode : public ZoneAllocated { |
}; |
-class CodeRegionExclusiveTrieBuilder : public SampleVisitor { |
+class CodeRegionTrieBuilder : public SampleVisitor { |
public: |
- CodeRegionExclusiveTrieBuilder(Isolate* isolate, |
- CodeRegionTable* live_code_table, |
- CodeRegionTable* dead_code_table, |
- CodeRegionTable* tag_code_table) |
+ CodeRegionTrieBuilder(Isolate* isolate, |
+ CodeRegionTable* live_code_table, |
+ CodeRegionTable* dead_code_table, |
+ CodeRegionTable* tag_code_table) |
: SampleVisitor(isolate), |
live_code_table_(live_code_table), |
dead_code_table_(dead_code_table), |
@@ -1758,18 +1801,42 @@ class CodeRegionExclusiveTrieBuilder : public SampleVisitor { |
ASSERT(root_index >= 0); |
CodeRegion* region = tag_code_table_->At(root_index); |
ASSERT(region != NULL); |
- root_ = new CodeRegionTrieNode(region->code_table_index()); |
+ |
+ exclusive_root_ = new CodeRegionTrieNode(region->code_table_index()); |
+ inclusive_root_ = new CodeRegionTrieNode(region->code_table_index()); |
} |
void VisitSample(Sample* sample) { |
+ ProcessSampleExclusive(sample); |
+ ProcessSampleInclusive(sample); |
+ } |
+ |
+ CodeRegionTrieNode* inclusive_root() const { |
+ return inclusive_root_; |
+ } |
+ |
+ CodeRegionTrieNode* exclusive_root() const { |
+ return exclusive_root_; |
+ } |
+ |
+ ProfilerService::TagOrder tag_order() const { |
+ return tag_order_; |
+ } |
+ |
+ void set_tag_order(ProfilerService::TagOrder tag_order) { |
+ tag_order_ = tag_order; |
+ } |
+ |
+ private: |
+ void ProcessSampleInclusive(Sample* sample) { |
// Give the root a tick. |
- root_->Tick(); |
- CodeRegionTrieNode* current = root_; |
+ inclusive_root_->Tick(); |
+ CodeRegionTrieNode* current = inclusive_root_; |
current = ProcessTags(sample, current); |
// Walk the sampled PCs. |
- for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
+ for (intptr_t i = FLAG_profile_depth - 1; i >= 0; i--) { |
if (sample->At(i) == 0) { |
- break; |
+ continue; |
} |
intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); |
if (index < 0) { |
@@ -1780,19 +1847,25 @@ class CodeRegionExclusiveTrieBuilder : public SampleVisitor { |
} |
} |
- CodeRegionTrieNode* root() const { |
- return root_; |
- } |
- |
- ProfilerService::TagOrder tag_order() const { |
- return tag_order_; |
- } |
- |
- void set_tag_order(ProfilerService::TagOrder tag_order) { |
- tag_order_ = tag_order; |
+ void ProcessSampleExclusive(Sample* sample) { |
+ // Give the root a tick. |
+ exclusive_root_->Tick(); |
+ CodeRegionTrieNode* current = exclusive_root_; |
+ current = ProcessTags(sample, current); |
+ // Walk the sampled PCs. |
+ for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
+ if (sample->At(i) == 0) { |
+ break; |
+ } |
+ intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); |
+ if (index < 0) { |
+ continue; |
+ } |
+ current = current->GetChild(index); |
+ current->Tick(); |
+ } |
} |
- private: |
CodeRegionTrieNode* ProcessUserTags(Sample* sample, |
CodeRegionTrieNode* current) { |
intptr_t user_tag_index = FindTagIndex(sample->user_tag()); |
@@ -1897,7 +1970,8 @@ class CodeRegionExclusiveTrieBuilder : public SampleVisitor { |
} |
ProfilerService::TagOrder tag_order_; |
- CodeRegionTrieNode* root_; |
+ CodeRegionTrieNode* exclusive_root_; |
+ CodeRegionTrieNode* inclusive_root_; |
CodeRegionTable* live_code_table_; |
CodeRegionTable* dead_code_table_; |
CodeRegionTable* tag_code_table_; |
@@ -1983,33 +2057,34 @@ void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { |
intptr_t total_functions = function_table.Length(); |
OS::Print("FunctionTable: size=%" Pd "\n", total_functions); |
} |
- CodeRegionExclusiveTrieBuilder code_trie_builder(isolate, |
- &live_code_table, |
- &dead_code_table, |
- &tag_code_table); |
+ CodeRegionTrieBuilder code_trie_builder(isolate, |
+ &live_code_table, |
+ &dead_code_table, |
+ &tag_code_table); |
code_trie_builder.set_tag_order(tag_order); |
{ |
// Build CodeRegion trie. |
- ScopeTimer sw("CodeRegionExclusiveTrieBuilder", FLAG_trace_profiler); |
+ ScopeTimer sw("CodeRegionTrieBuilder", FLAG_trace_profiler); |
sample_buffer->VisitSamples(&code_trie_builder); |
- code_trie_builder.root()->SortByCount(); |
+ code_trie_builder.exclusive_root()->SortByCount(); |
+ code_trie_builder.inclusive_root()->SortByCount(); |
} |
- ProfileFunctionExclusiveTrieBuilder |
- function_trie_builder(isolate, |
- &live_code_table, |
- &dead_code_table, |
- &tag_code_table, |
- &function_table); |
+ ProfileFunctionTrieBuilder function_trie_builder(isolate, |
+ &live_code_table, |
+ &dead_code_table, |
+ &tag_code_table, |
+ &function_table); |
function_trie_builder.set_tag_order(tag_order); |
{ |
// Build ProfileFunction trie. |
- ScopeTimer sw("ProfileFunctionExclusiveTrieBuilder", |
+ ScopeTimer sw("ProfileFunctionTrieBuilder", |
FLAG_trace_profiler); |
sample_buffer->VisitSamples(&function_trie_builder); |
- function_trie_builder.root()->SortByCount(); |
+ function_trie_builder.exclusive_root()->SortByCount(); |
+ function_trie_builder.inclusive_root()->SortByCount(); |
} |
{ |
- ScopeTimer sw("CodeTableStream", FLAG_trace_profiler); |
+ ScopeTimer sw("CpuProfileJSONStream", FLAG_trace_profiler); |
// Serialize to JSON. |
JSONObject obj(stream); |
obj.AddProperty("type", "_CpuProfile"); |
@@ -2021,14 +2096,28 @@ void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { |
obj.AddProperty("timeSpan", |
MicrosecondsToSeconds(builder.TimeDeltaMicros())); |
{ |
- JSONArray exclusive_trie(&obj, "exclusiveCodeTrie"); |
- CodeRegionTrieNode* root = code_trie_builder.root(); |
+ JSONArray code_trie(&obj, "exclusiveCodeTrie"); |
+ CodeRegionTrieNode* root = code_trie_builder.exclusive_root(); |
ASSERT(root != NULL); |
- root->PrintToJSONArray(&exclusive_trie); |
+ root->PrintToJSONArray(&code_trie); |
+ } |
+ { |
+ JSONArray code_trie(&obj, "inclusiveCodeTrie"); |
+ CodeRegionTrieNode* root = code_trie_builder.inclusive_root(); |
+ ASSERT(root != NULL); |
+ root->PrintToJSONArray(&code_trie); |
} |
{ |
JSONArray function_trie(&obj, "exclusiveFunctionTrie"); |
- ProfileFunctionTrieNode* root = function_trie_builder.root(); |
+ ProfileFunctionTrieNode* root = |
+ function_trie_builder.exclusive_root(); |
+ ASSERT(root != NULL); |
+ root->PrintToJSONArray(&function_trie); |
+ } |
+ { |
+ JSONArray function_trie(&obj, "inclusiveFunctionTrie"); |
+ ProfileFunctionTrieNode* root = |
+ function_trie_builder.inclusive_root(); |
ASSERT(root != NULL); |
root->PrintToJSONArray(&function_trie); |
} |