Chromium Code Reviews| Index: runtime/vm/profiler_service.cc |
| diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc |
| index b6e6018ba19237ac35fc14a2da64c364bf4a755b..3967bebe671019a40896ab4db7e44cfca557cab4 100644 |
| --- a/runtime/vm/profiler_service.cc |
| +++ b/runtime/vm/profiler_service.cc |
| @@ -174,7 +174,9 @@ class ProfileFunction : public ZoneAllocated { |
| intptr_t inclusive_ticks() const { |
| return inclusive_ticks_; |
| } |
| - |
| + void inc_inclusive_ticks() { |
| + inclusive_ticks_++; |
| + } |
| intptr_t exclusive_ticks() const { |
| return exclusive_ticks_; |
| } |
| @@ -436,6 +438,9 @@ class CodeRegion : public ZoneAllocated { |
| void set_inclusive_ticks(intptr_t inclusive_ticks) { |
| inclusive_ticks_ = inclusive_ticks; |
| } |
| + void inc_inclusive_ticks() { |
| + inclusive_ticks_++; |
| + } |
| intptr_t exclusive_ticks() const { return exclusive_ticks_; } |
| void set_exclusive_ticks(intptr_t exclusive_ticks) { |
| @@ -1412,7 +1417,7 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| dead_code_table_(dead_code_table), |
| tag_code_table_(tag_code_table), |
| function_table_(function_table), |
| - inclusive_(false), |
| + inclusive_tree_(false), |
| trace_(false), |
| trace_code_filter_(NULL) { |
| ASSERT(live_code_table_ != NULL); |
| @@ -1439,9 +1444,9 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| } |
| void VisitSample(Sample* sample) { |
| - inclusive_ = false; |
| + inclusive_tree_ = false; |
| ProcessSampleExclusive(sample); |
| - inclusive_ = true; |
| + inclusive_tree_ = true; |
| ProcessSampleInclusive(sample); |
| } |
| @@ -1457,6 +1462,12 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| return tag_order_; |
| } |
| + bool vm_tags_emitted() const { |
| + return (tag_order_ == ProfilerService::kUserVM) || |
| + (tag_order_ == ProfilerService::kVMUser) || |
| + (tag_order_ == ProfilerService::kVM); |
| + } |
| + |
| void set_tag_order(ProfilerService::TagOrder tag_order) { |
| tag_order_ = tag_order; |
| } |
| @@ -1468,6 +1479,7 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| ProfileFunctionTrieNode* current = inclusive_root_; |
| current = AppendTags(sample, current); |
| if (sample->truncated_trace()) { |
| + InclusiveTickTruncatedTag(); |
| current = AppendTruncatedTag(current); |
| } |
| // Walk the sampled PCs. |
| @@ -1475,11 +1487,12 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| if (sample->At(i) == 0) { |
| continue; |
| } |
| - // 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, |
| + current = ProcessPC(sample->At(i), |
| + sample->timestamp(), |
| + current, |
| + visited(), |
| + (i == 0), |
| + sample->exit_frame_sample() && (i == 0), |
| sample->missing_frame_inserted()); |
| } |
| } |
| @@ -1494,11 +1507,12 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| 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, |
| + current = ProcessPC(sample->At(i), |
| + sample->timestamp(), |
| + current, |
| + visited(), |
| + (i == 0), |
| + sample->exit_frame_sample() && (i == 0), |
| sample->missing_frame_inserted()); |
| } |
| if (sample->truncated_trace()) { |
| @@ -1527,6 +1541,12 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| return current; |
| } |
| + void InclusiveTickTruncatedTag() { |
| + intptr_t index = tag_code_table_->FindIndex(VMTag::kTruncatedTagId); |
| + CodeRegion* region = tag_code_table_->At(index); |
|
Ivan Posva
2015/03/16 22:17:37
I am wondering whether some of this information co
|
| + ProfileFunction* function = region->function(); |
| + function->inc_inclusive_ticks(); |
| + } |
| ProfileFunctionTrieNode* AppendVMTag(Sample* sample, |
| ProfileFunctionTrieNode* current) { |
| @@ -1624,10 +1644,12 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| OS::Print("\n"); |
| } |
| - ProfileFunctionTrieNode* ProcessPC(uword pc, int64_t timestamp, |
| + ProfileFunctionTrieNode* ProcessPC(uword pc, |
| + int64_t timestamp, |
| ProfileFunctionTrieNode* current, |
| intptr_t inclusive_serial, |
| - bool exclusive, |
| + bool exclusive_frame, |
| + bool exit_frame, |
| bool missing_frame_inserted) { |
| CodeRegion* region = FindCodeObject(pc, timestamp); |
| if (region == NULL) { |
| @@ -1652,12 +1674,12 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| OS::Print("[%" Px "] X - %s (%s)\n", |
| pc, function->name(), region_name); |
| } |
| - if (!inclusive_) { |
| - function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
| - } |
| - current = current->GetChild(function->index()); |
| - current->AddCodeObjectIndex(code_index); |
| - current->Tick(); |
| + current = ProcessFunction(function, |
| + current, |
| + inclusive_serial, |
| + exclusive_frame, |
| + exit_frame, |
| + code_index); |
| if ((trace_code_filter_ != NULL) && |
| (strstr(region_name, trace_code_filter_) != NULL)) { |
| trace_ = true; |
| @@ -1668,14 +1690,18 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| return current; |
| } |
| - if (inclusive_) { |
| + if (inclusive_tree_) { |
| 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; |
| + current = ProcessInlinedFunction(inlined_function, |
| + current, |
| + inclusive_serial, |
| + exclusive_frame, |
| + exit_frame, |
| + code_index); |
| + exclusive_frame = false; |
| } |
| } else { |
| for (intptr_t i = 0; i < inlined_functions.length(); i++) { |
| @@ -1687,9 +1713,13 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| 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; |
| + current = ProcessInlinedFunction(inlined_function, |
| + current, |
| + inclusive_serial, |
| + exclusive_frame, |
| + exit_frame, |
| + code_index); |
| + exclusive_frame = false; |
| if ((trace_code_filter_ != NULL) && |
| (strstr(region_name, trace_code_filter_) != NULL)) { |
| trace_ = true; |
| @@ -1707,16 +1737,44 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| Function* inlined_function, |
| ProfileFunctionTrieNode* current, |
| intptr_t inclusive_serial, |
| - bool exclusive, |
| + bool exclusive_frame, |
|
Ivan Posva
2015/03/16 22:17:37
exclusive_frame really means the top frame.
|
| + bool exit_frame, |
| intptr_t code_index) { |
| ProfileFunction* function = |
| function_table_->LookupOrAdd(*inlined_function); |
| ASSERT(function != NULL); |
| + return ProcessFunction(function, |
| + current, |
| + inclusive_serial, |
| + exclusive_frame, |
| + exit_frame, |
| + code_index); |
| + } |
| + |
| + ProfileFunctionTrieNode* ProcessFunction(ProfileFunction* function, |
| + ProfileFunctionTrieNode* current, |
| + intptr_t inclusive_serial, |
| + bool exclusive_frame, |
| + bool exit_frame, |
| + intptr_t code_index) { |
| + const bool exclusive = exclusive_frame && !exit_frame; |
| + if (!inclusive_tree_) { |
| + // We process functions for the inclusive and exclusive trees. |
| + // Only tick the function for the exclusive tree. |
| + function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
| + } |
| function->AddCodeObjectIndex(code_index); |
| - function->Tick(exclusive, exclusive ? -1 : inclusive_serial); |
| + |
| current = current->GetChild(function->index()); |
| current->AddCodeObjectIndex(code_index); |
| - current->Tick(); |
| + if (exclusive_frame) { |
| + if (!exit_frame || vm_tags_emitted()) { |
| + // Only tick if this isn't an exit frame or VM tags are emitted. |
| + current->Tick(); |
| + } |
| + } else { |
| + current->Tick(); |
| + } |
| return current; |
| } |
| @@ -1749,7 +1807,7 @@ class ProfileFunctionTrieBuilder : public SampleVisitor { |
| CodeRegionTable* dead_code_table_; |
| CodeRegionTable* tag_code_table_; |
| ProfileFunctionTable* function_table_; |
| - bool inclusive_; |
| + bool inclusive_tree_; |
| bool trace_; |
| const char* trace_code_filter_; |
| }; |
| @@ -1892,6 +1950,12 @@ class CodeRegionTrieBuilder : public SampleVisitor { |
| return tag_order_; |
| } |
| + bool vm_tags_emitted() const { |
| + return (tag_order_ == ProfilerService::kUserVM) || |
| + (tag_order_ == ProfilerService::kVMUser) || |
| + (tag_order_ == ProfilerService::kVM); |
| + } |
| + |
| void set_tag_order(ProfilerService::TagOrder tag_order) { |
| tag_order_ = tag_order; |
| } |
| @@ -1934,7 +1998,16 @@ class CodeRegionTrieBuilder : public SampleVisitor { |
| continue; |
| } |
| current = current->GetChild(index); |
| - current->Tick(); |
| + if (i == 0) { |
| + // Executing PC. |
| + if (!sample->exit_frame_sample() || vm_tags_emitted()) { |
| + // Only tick if this isn't an exit frame or VM tags are emitted. |
| + current->Tick(); |
| + } |
| + } else { |
| + // Caller PCs. |
| + current->Tick(); |
| + } |
| } |
| if (sample->truncated_trace()) { |
| current = AppendTruncatedTag(current); |
| @@ -2133,10 +2206,14 @@ void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { |
| intptr_t samples = builder.visited(); |
| intptr_t frames = builder.frames(); |
| if (FLAG_trace_profiler) { |
| + OS::Print( |
| + "Processed %" Pd " samples with %" Pd " frames\n", samples, frames); |
| + } |
|
Ivan Posva
2015/03/16 22:17:37
if (x) {
}
if (x) {
}
???
|
| + if (FLAG_trace_profiler) { |
| intptr_t total_live_code_objects = live_code_table.Length(); |
| intptr_t total_dead_code_objects = dead_code_table.Length(); |
| intptr_t total_tag_code_objects = tag_code_table.Length(); |
| - OS::Print("Processed %" Pd " frames\n", frames); |
| + |
| OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n", |
| total_live_code_objects, |
| total_dead_code_objects, |
| @@ -2174,6 +2251,11 @@ void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { |
| code_trie_builder.exclusive_root()->SortByCount(); |
| code_trie_builder.inclusive_root()->SortByCount(); |
| } |
| + if (FLAG_trace_profiler) { |
| + OS::Print("Code Trie Root Count: E: %" Pd " I: %" Pd "\n", |
| + code_trie_builder.exclusive_root()->count(), |
| + code_trie_builder.inclusive_root()->count()); |
| + } |
| ProfileFunctionTrieBuilder function_trie_builder(isolate, |
| &live_code_table, |
| &dead_code_table, |
| @@ -2188,6 +2270,11 @@ void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { |
| function_trie_builder.exclusive_root()->SortByCount(); |
| function_trie_builder.inclusive_root()->SortByCount(); |
| } |
| + if (FLAG_trace_profiler) { |
| + OS::Print("Function Trie Root Count: E: %" Pd " I: %" Pd "\n", |
| + function_trie_builder.exclusive_root()->count(), |
| + function_trie_builder.inclusive_root()->count()); |
| + } |
| { |
| ScopeTimer sw("CpuProfileJSONStream", FLAG_trace_profiler); |
| // Serialize to JSON. |