Chromium Code Reviews| Index: runtime/vm/profiler_service.cc |
| diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc |
| index 997aab191597c6a6c17eed9a57fc02144318031b..573540b5dd57fd7e5cb9bc792ecc712f8974aa77 100644 |
| --- a/runtime/vm/profiler_service.cc |
| +++ b/runtime/vm/profiler_service.cc |
| @@ -581,11 +581,34 @@ ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) { |
| ASSERT(tag_name != NULL); |
| SetName(tag_name); |
| } else { |
| - if (start() == VMTag::kRootTagId) { |
| - SetName("Root"); |
| - } else { |
| - ASSERT(start() == VMTag::kTruncatedTagId); |
| - SetName("[Truncated]"); |
| + switch (start()) { |
| + case VMTag::kRootTagId: |
| + SetName("Root"); |
| + break; |
| + case VMTag::kTruncatedTagId: |
| + SetName("[Truncated]"); |
| + break; |
| + case VMTag::kNoneCodeTagId: |
| + SetName("[No Code]"); |
| + break; |
| + case VMTag::kOptimizedCodeTagId: |
| + SetName("[Optimized Code]"); |
| + break; |
| + case VMTag::kUnoptimizedCodeTagId: |
| + SetName("[Unoptimized Code]"); |
| + break; |
| + case VMTag::kNativeCodeTagId: |
| + SetName("[Native Code]"); |
| + break; |
| + case VMTag::kInlineStartCodeTagId: |
| + SetName("[Inline Start]"); |
| + break; |
| + case VMTag::kInlineEndCodeTagId: |
| + SetName("[Inline End]"); |
| + break; |
| + default: |
| + UNIMPLEMENTED(); |
| + break; |
| } |
| } |
| } |
| @@ -951,21 +974,34 @@ class ProfileFunctionTrieNode : public ProfileTrieNode { |
| class ProfileBuilder : public ValueObject { |
| public: |
| + enum ProfileInfoKind { |
| + kNone, |
| + kOptimized, |
| + kUnoptimized, |
| + kNative, |
| + kInlineStart, |
| + kInlineFinish, |
| + kNumProfileInfoKind, |
| + }; |
| + |
| ProfileBuilder(Isolate* isolate, |
| SampleFilter* filter, |
| Profile::TagOrder tag_order, |
| + intptr_t extra_tags, |
| Profile* profile) |
| : isolate_(isolate), |
| vm_isolate_(Dart::vm_isolate()), |
| filter_(filter), |
| tag_order_(tag_order), |
| + extra_tags_(extra_tags), |
| profile_(profile), |
| deoptimized_code_(new DeoptimizedCodeSet(isolate)), |
| null_code_(Code::ZoneHandle()), |
| null_function_(Function::ZoneHandle()), |
| tick_functions_(false), |
| inclusive_tree_(false), |
| - samples_(NULL) { |
| + samples_(NULL), |
| + info_kind_(kNone) { |
| ASSERT(profile_ != NULL); |
| } |
| @@ -1005,6 +1041,12 @@ class ProfileBuilder : public ValueObject { |
| // Register some synthetic tags. |
| RegisterProfileCodeTag(VMTag::kRootTagId); |
| RegisterProfileCodeTag(VMTag::kTruncatedTagId); |
| + RegisterProfileCodeTag(VMTag::kNoneCodeTagId); |
| + RegisterProfileCodeTag(VMTag::kOptimizedCodeTagId); |
| + RegisterProfileCodeTag(VMTag::kUnoptimizedCodeTagId); |
| + RegisterProfileCodeTag(VMTag::kNativeCodeTagId); |
| + RegisterProfileCodeTag(VMTag::kInlineStartCodeTagId); |
| + RegisterProfileCodeTag(VMTag::kInlineEndCodeTagId); |
| } |
| void FilterSamples() { |
| @@ -1152,12 +1194,15 @@ class ProfileBuilder : public ValueObject { |
| // VM & User tags. |
| current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| + ResetKind(); |
| + |
| // Truncated tag. |
| if (sample->truncated()) { |
| current = AppendTruncatedTag(current); |
| } |
| // Walk the sampled PCs. |
| + Code& code = Code::Handle(); |
| for (intptr_t frame_index = sample->length() - 1; |
| frame_index >= 0; |
| frame_index--) { |
| @@ -1165,6 +1210,11 @@ class ProfileBuilder : public ValueObject { |
| intptr_t index = |
| GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); |
| ASSERT(index >= 0); |
| + ProfileCode* profile_code = |
| + GetProfileCode(sample->At(frame_index), sample->timestamp()); |
| + ASSERT(profile_code->code_table_index() == index); |
| + code ^= profile_code->code(); |
| + current = AppendKind(code, current); |
| current = current->GetChild(index); |
| current->Tick(); |
| } |
| @@ -1186,7 +1236,10 @@ class ProfileBuilder : public ValueObject { |
| // VM & User tags. |
| current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| + ResetKind(); |
| + |
| // Walk the sampled PCs. |
| + Code& code = Code::Handle(); |
| for (intptr_t frame_index = 0; |
| frame_index < sample->length(); |
| frame_index++) { |
| @@ -1194,10 +1247,15 @@ class ProfileBuilder : public ValueObject { |
| intptr_t index = |
| GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); |
| ASSERT(index >= 0); |
| + ProfileCode* profile_code = |
| + GetProfileCode(sample->At(frame_index), sample->timestamp()); |
| + ASSERT(profile_code->code_table_index() == index); |
| + code ^= profile_code->code(); |
| current = current->GetChild(index); |
| if (ShouldTickNode(sample, frame_index)) { |
| current->Tick(); |
| } |
| + current = AppendKind(code, current); |
| } |
| // Truncated tag. |
| if (sample->truncated()) { |
| @@ -1270,6 +1328,8 @@ class ProfileBuilder : public ValueObject { |
| // VM & User tags. |
| current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| + ResetKind(); |
| + |
| // Walk the sampled PCs. |
| for (intptr_t frame_index = 0; |
| frame_index < sample->length(); |
| @@ -1306,40 +1366,63 @@ class ProfileBuilder : public ValueObject { |
| } |
| if (code.IsNull() || (inlined_functions.length() == 0)) { |
| // No inlined functions. |
| + if (inclusive_tree_) { |
| + current = AppendKind(code, current); |
| + } |
| current = ProcessFunction(current, |
| sample_index, |
| sample, |
| frame_index, |
| function, |
| code_index); |
| + if (!inclusive_tree_) { |
| + current = AppendKind(code, current); |
| + } |
| return current; |
| } |
| + ASSERT(code.is_optimized()); |
| + |
| if (inclusive_tree_) { |
| - // Append the inlined children. |
| 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()); |
| + const bool inliner = i == (inlined_functions.length() - 1); |
| + if (inliner) { |
| + current = AppendKind(code, current); |
| + } |
| current = ProcessInlinedFunction(current, |
| sample_index, |
| sample, |
| frame_index, |
| inlined_function, |
| code_index); |
| + if (inliner) { |
| + current = AppendKind(kInlineStart, current); |
| + } |
| } |
| + current = AppendKind(kInlineFinish, current); |
| } else { |
| // Append the inlined children. |
| + current = AppendKind(kInlineFinish, 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 bool inliner = i == (inlined_functions.length() - 1); |
| + if (inliner) { |
| + current = AppendKind(kInlineStart, current); |
| + } |
| current = ProcessInlinedFunction(current, |
| sample_index, |
| sample, |
| frame_index + i, |
| inlined_function, |
| code_index); |
| + if (inliner) { |
| + current = AppendKind(code, current); |
| + } |
| } |
| } |
| @@ -1464,6 +1547,53 @@ class ProfileBuilder : public ValueObject { |
| return current; |
| } |
| + uword ProfileInfoKindToVMTag(ProfileInfoKind kind) { |
| + ASSERT(kNone == 0); |
| + ASSERT(kOptimized == 1); |
| + ASSERT(kUnoptimized == 2); |
| + ASSERT(kNative == 3); |
| + ASSERT(kInlineStart == 4); |
| + ASSERT(kInlineFinish == 5); |
| + ASSERT(kNumProfileInfoKind == 6); |
| + uword tag_map[] = { |
|
srdjan
2015/08/04 21:24:46
'static uword tag_map', so that it does not get co
Cutch
2015/08/04 22:00:58
Done.
|
| + VMTag::kNoneCodeTagId, |
| + VMTag::kOptimizedCodeTagId, |
| + VMTag::kUnoptimizedCodeTagId, |
| + VMTag::kNativeCodeTagId, |
| + VMTag::kInlineStartCodeTagId, |
| + VMTag::kInlineEndCodeTagId, |
| + VMTag::kInvalidTagId |
| + }; |
| + return tag_map[kind]; |
| + } |
| + |
| + ProfileCodeTrieNode* AppendKind(ProfileInfoKind kind, |
| + ProfileCodeTrieNode* current) { |
| + if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) { |
| + // Only emit if debug tags are requested. |
| + return current; |
| + } |
| + if (kind != info_kind_) { |
| + info_kind_ = kind; |
| + intptr_t tag_index = GetProfileCodeTagIndex(ProfileInfoKindToVMTag(kind)); |
| + ASSERT(tag_index >= 0); |
| + current = current->GetChild(tag_index); |
| + current->Tick(); |
| + } |
| + return current; |
| + } |
| + |
| + ProfileCodeTrieNode* AppendKind(const Code& code, |
| + ProfileCodeTrieNode* current) { |
| + if (code.IsNull()) { |
| + return AppendKind(kNone, current); |
| + } else if (code.is_optimized()) { |
| + return AppendKind(kOptimized, current); |
| + } else { |
| + return AppendKind(kUnoptimized, current); |
| + } |
| + } |
| + |
| ProfileCodeTrieNode* AppendVMTags(uword vm_tag, |
| ProfileCodeTrieNode* current) { |
| current = AppendVMTag(vm_tag, current); |
| @@ -1500,6 +1630,38 @@ class ProfileBuilder : public ValueObject { |
| } |
| // ProfileFunctionTrieNode |
| + void ResetKind() { |
| + info_kind_ = kNone; |
| + } |
| + |
| + ProfileFunctionTrieNode* AppendKind(ProfileInfoKind kind, |
| + ProfileFunctionTrieNode* current) { |
| + if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) { |
| + // Only emit if debug tags are requested. |
| + return current; |
| + } |
| + if (kind != info_kind_) { |
| + info_kind_ = kind; |
| + intptr_t tag_index = |
| + GetProfileFunctionTagIndex(ProfileInfoKindToVMTag(kind)); |
| + ASSERT(tag_index >= 0); |
| + current = current->GetChild(tag_index); |
| + current->Tick(); |
| + } |
| + return current; |
| + } |
| + |
| + ProfileFunctionTrieNode* AppendKind(const Code& code, |
| + ProfileFunctionTrieNode* current) { |
| + if (code.IsNull()) { |
| + return AppendKind(kNone, current); |
| + } else if (code.is_optimized()) { |
| + return AppendKind(kOptimized, current); |
| + } else { |
| + return AppendKind(kUnoptimized, current); |
| + } |
| + } |
| + |
| ProfileFunctionTrieNode* AppendUserTag(uword user_tag, |
| ProfileFunctionTrieNode* current) { |
| intptr_t user_tag_index = GetProfileFunctionTagIndex(user_tag); |
| @@ -1783,10 +1945,15 @@ class ProfileBuilder : public ValueObject { |
| (tag_order_ == Profile::kVM); |
| } |
| + bool TagsEnabled(intptr_t extra_tags_bits) { |
|
srdjan
2015/08/04 21:24:46
const
Cutch
2015/08/04 22:00:58
Done.
|
| + return (extra_tags_ & extra_tags_bits) != 0; |
| + } |
| + |
| Isolate* isolate_; |
| Isolate* vm_isolate_; |
| SampleFilter* filter_; |
| Profile::TagOrder tag_order_; |
| + intptr_t extra_tags_; |
| Profile* profile_; |
| DeoptimizedCodeSet* deoptimized_code_; |
| const Code& null_code_; |
| @@ -1795,6 +1962,7 @@ class ProfileBuilder : public ValueObject { |
| bool inclusive_tree_; |
| ProcessedSampleBuffer* samples_; |
| + ProfileInfoKind info_kind_; |
| }; |
| @@ -1815,8 +1983,10 @@ Profile::Profile(Isolate* isolate) |
| } |
| -void Profile::Build(SampleFilter* filter, TagOrder tag_order) { |
| - ProfileBuilder builder(isolate_, filter, tag_order, this); |
| +void Profile::Build(SampleFilter* filter, |
| + TagOrder tag_order, |
| + intptr_t extra_tags) { |
| + ProfileBuilder builder(isolate_, filter, tag_order, extra_tags, this); |
| builder.Build(); |
| } |
| @@ -2019,6 +2189,7 @@ intptr_t ProfileTrieWalker::SiblingCount() { |
| void ProfilerService::PrintJSONImpl(Isolate* isolate, |
| JSONStream* stream, |
| Profile::TagOrder tag_order, |
| + intptr_t extra_tags, |
| SampleFilter* filter) { |
| // Disable profile interrupts while processing the buffer. |
| Profiler::EndExecution(isolate); |
| @@ -2036,7 +2207,7 @@ void ProfilerService::PrintJSONImpl(Isolate* isolate, |
| StackZone zone(isolate); |
| HANDLESCOPE(isolate); |
| Profile profile(isolate); |
| - profile.Build(filter, tag_order); |
| + profile.Build(filter, tag_order, extra_tags); |
| profile.PrintJSON(stream); |
| } |
| @@ -2058,10 +2229,11 @@ class NoAllocationSampleFilter : public SampleFilter { |
| void ProfilerService::PrintJSON(JSONStream* stream, |
| - Profile::TagOrder tag_order) { |
| + Profile::TagOrder tag_order, |
| + intptr_t extra_tags) { |
| Isolate* isolate = Isolate::Current(); |
| NoAllocationSampleFilter filter(isolate); |
| - PrintJSONImpl(isolate, stream, tag_order, &filter); |
| + PrintJSONImpl(isolate, stream, tag_order, extra_tags, &filter); |
| } |
| @@ -2088,7 +2260,7 @@ void ProfilerService::PrintAllocationJSON(JSONStream* stream, |
| const Class& cls) { |
| Isolate* isolate = Isolate::Current(); |
| ClassAllocationSampleFilter filter(isolate, cls); |
| - PrintJSONImpl(isolate, stream, tag_order, &filter); |
| + PrintJSONImpl(isolate, stream, tag_order, 0, &filter); |
|
srdjan
2015/08/04 21:24:46
kNone instead of 0?
Cutch
2015/08/04 22:00:58
Done.
|
| } |