Chromium Code Reviews| Index: runtime/vm/profiler_service.cc |
| diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc |
| index a4e6b835ce7a6fdda2704a892a7588a8ff677145..f79836917fba9b2c13b1bdbff50fe22f222468d0 100644 |
| --- a/runtime/vm/profiler_service.cc |
| +++ b/runtime/vm/profiler_service.cc |
| @@ -797,7 +797,8 @@ class ProfileCodeTable : public ZoneAllocated { |
| ProfileTrieNode::ProfileTrieNode(intptr_t table_index) |
| : table_index_(table_index), |
| count_(0), |
| - children_(0) { |
| + children_(0), |
| + frame_id_(-1) { |
| ASSERT(table_index_ >= 0); |
| } |
| @@ -1056,6 +1057,7 @@ class ProfileBuilder : public ValueObject { |
| return; |
| } |
| samples_ = sample_buffer->BuildProcessedSampleBuffer(filter_); |
| + profile_->samples_ = samples_; |
| profile_->sample_count_ = samples_->length(); |
| } |
| @@ -1333,6 +1335,8 @@ class ProfileBuilder : public ValueObject { |
| ASSERT(sample->At(frame_index) != 0); |
| current = ProcessFrame(current, sample_index, sample, frame_index); |
| } |
| + |
| + sample->set_timeline_trie(current); |
| } |
| } |
| @@ -1973,6 +1977,8 @@ class ProfileBuilder : public ValueObject { |
| Profile::Profile(Isolate* isolate) |
| : isolate_(isolate), |
| + zone_(Thread::Current()->zone()), |
| + samples_(NULL), |
| live_code_(NULL), |
| dead_code_(NULL), |
| tag_code_(NULL), |
| @@ -2034,8 +2040,83 @@ ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { |
| } |
| -void Profile::PrintJSON(JSONStream* stream) { |
| - ScopeTimer sw("Profile::PrintJSON", FLAG_trace_profiler); |
| +void Profile::PrintTimelineFrameJSON(JSONObject* frames, |
| + ProfileTrieNode* current, |
| + ProfileTrieNode* parent, |
| + intptr_t* next_id) { |
| + ASSERT(current->frame_id() == -1); |
| + intptr_t id = *next_id; |
|
Cutch
2015/12/15 21:54:59
const intptr_t id = *next_id++;
rmacnak
2015/12/16 00:14:21
Doesn't mean the same thing. Led to the crashes.
|
| + *next_id = id + 1; |
| + current->set_frame_id(id); |
| + ASSERT(current->frame_id() != -1); |
| + |
| + { |
| + // The samples from many isolates may be merged into a single timeline, |
| + // so prefix frames id with the isolate. |
| + intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); |
| + const char* key = zone_->PrintToString("f%" Pd "-%" Pd, |
| + isolate_id, current->frame_id()); |
| + JSONObject frame(frames, key); |
| + frame.AddProperty("category", "Dart"); |
|
Cutch
2015/12/15 21:54:59
Do we need to emit a category for each stack frame
rmacnak
2015/12/16 00:14:20
The samples all have random looking colors if this
|
| + ProfileFunction* func = GetFunction(current->table_index()); |
| + frame.AddProperty("name", func->Name()); |
| + if (parent != NULL) { |
| + ASSERT(parent->frame_id() != -1); |
| + frame.AddPropertyF("parent", "f%" Pd "-%" Pd, |
| + isolate_id, parent->frame_id()); |
| + } |
| + } |
| + |
| + for (intptr_t i = 0; i < current->NumChildren(); i++) { |
| + ProfileTrieNode* child = current->At(i); |
| + PrintTimelineFrameJSON(frames, child, current, next_id); |
| + } |
| +} |
| + |
| + |
| +void Profile::PrintTimelineJSON(JSONStream* stream) { |
| + ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); |
| + JSONObject obj(stream); |
| + obj.AddProperty("type", "_CpuProfileTimeline"); |
| + obj.AddProperty("samplePeriod", |
| + static_cast<intptr_t>(FLAG_profile_period)); |
| + obj.AddProperty("stackDepth", |
|
Cutch
2015/12/15 21:54:59
Factor this out into a PrintProfileHeaderJson() an
|
| + static_cast<intptr_t>(FLAG_max_profile_depth)); |
| + obj.AddProperty("sampleCount", sample_count()); |
| + obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); |
| + { |
| + JSONObject frames(&obj, "stackFrames"); |
| + ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); |
| + intptr_t next_id = 0; |
| + PrintTimelineFrameJSON(&frames, root, NULL, &next_id); |
| + } |
| + { |
| + JSONArray events(&obj, "traceEvents"); |
| + intptr_t pid = OS::ProcessId(); |
| + intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); |
| + for (intptr_t sample_index = 0; |
| + sample_index < samples_->length(); |
| + sample_index++) { |
| + ProcessedSample* sample = samples_->At(sample_index); |
| + JSONObject event(&events); |
| + event.AddProperty("name", "DartSample"); |
|
Cutch
2015/12/15 21:54:59
Can we shorten the name to be "DS" or even drop it
rmacnak
2015/12/16 00:14:20
Works when dropped.
|
| + event.AddProperty("ph", "P"); // kind = sample event |
| + event.AddProperty64("pid", pid); |
| + event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid())); |
| + event.AddPropertyTimeMicros("ts", sample->timestamp()); |
| + event.AddProperty("cat", VMTag::TagName(sample->vm_tag())); |
|
Cutch
2015/12/15 21:54:59
cat should be hard coded to "Dart"
rmacnak
2015/12/16 00:14:20
Done.
|
| + |
| + ProfileTrieNode* trie = sample->timeline_trie(); |
| + ASSERT(trie->frame_id() != -1); |
| + event.AddPropertyF("sf", "f%" Pd "-%" Pd, |
| + isolate_id, trie->frame_id()); |
| + } |
| + } |
| +} |
| + |
| + |
| +void Profile::PrintProfileJSON(JSONStream* stream) { |
| + ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); |
| JSONObject obj(stream); |
| obj.AddProperty("type", "_CpuProfile"); |
| obj.AddProperty("samplePeriod", |
| @@ -2196,7 +2277,8 @@ void ProfilerService::PrintJSONImpl(Thread* thread, |
| JSONStream* stream, |
| Profile::TagOrder tag_order, |
| intptr_t extra_tags, |
| - SampleFilter* filter) { |
| + SampleFilter* filter, |
| + bool as_timeline) { |
| Isolate* isolate = thread->isolate(); |
| // Disable thread interrupts while processing the buffer. |
| DisableThreadInterruptsScope dtis(thread); |
| @@ -2212,7 +2294,11 @@ void ProfilerService::PrintJSONImpl(Thread* thread, |
| HANDLESCOPE(thread); |
| Profile profile(isolate); |
| profile.Build(thread, filter, tag_order, extra_tags); |
| - profile.PrintJSON(stream); |
| + if (as_timeline) { |
| + profile.PrintTimelineJSON(stream); |
| + } else { |
| + profile.PrintProfileJSON(stream); |
| + } |
| } |
| } |
| @@ -2235,7 +2321,8 @@ void ProfilerService::PrintJSON(JSONStream* stream, |
| Thread* thread = Thread::Current(); |
| Isolate* isolate = thread->isolate(); |
| NoAllocationSampleFilter filter(isolate); |
| - PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter); |
| + const bool as_timeline = false; |
| + PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, as_timeline); |
| } |
| @@ -2263,7 +2350,18 @@ void ProfilerService::PrintAllocationJSON(JSONStream* stream, |
| Thread* thread = Thread::Current(); |
| Isolate* isolate = thread->isolate(); |
| ClassAllocationSampleFilter filter(isolate, cls); |
| - PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter); |
| + const bool as_timeline = false; |
| + PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); |
| +} |
| + |
| + |
| +void ProfilerService::PrintTimelineJSON(JSONStream* stream, |
| + Profile::TagOrder tag_order) { |
| + Thread* thread = Thread::Current(); |
| + Isolate* isolate = thread->isolate(); |
| + NoAllocationSampleFilter filter(isolate); |
| + const bool as_timeline = true; |
| + PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); |
| } |