OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/profiler_service.h" | 5 #include "vm/profiler_service.h" |
6 | 6 |
7 #include "vm/growable_array.h" | 7 #include "vm/growable_array.h" |
8 #include "vm/native_symbol.h" | 8 #include "vm/native_symbol.h" |
9 #include "vm/object.h" | 9 #include "vm/object.h" |
10 #include "vm/os.h" | 10 #include "vm/os.h" |
(...skipping 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
790 } | 790 } |
791 } | 791 } |
792 | 792 |
793 ZoneGrowableArray<ProfileCode*> table_; | 793 ZoneGrowableArray<ProfileCode*> table_; |
794 }; | 794 }; |
795 | 795 |
796 | 796 |
797 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) | 797 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) |
798 : table_index_(table_index), | 798 : table_index_(table_index), |
799 count_(0), | 799 count_(0), |
800 children_(0) { | 800 children_(0), |
801 frame_id_(-1) { | |
801 ASSERT(table_index_ >= 0); | 802 ASSERT(table_index_ >= 0); |
802 } | 803 } |
803 | 804 |
804 | 805 |
805 ProfileTrieNode::~ProfileTrieNode() { | 806 ProfileTrieNode::~ProfileTrieNode() { |
806 } | 807 } |
807 | 808 |
808 | 809 |
809 void ProfileTrieNode::SortChildren() { | 810 void ProfileTrieNode::SortChildren() { |
810 children_.Sort(ProfileTrieNodeCompare); | 811 children_.Sort(ProfileTrieNodeCompare); |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1049 RegisterProfileCodeTag(VMTag::kInlineEndCodeTagId); | 1050 RegisterProfileCodeTag(VMTag::kInlineEndCodeTagId); |
1050 } | 1051 } |
1051 | 1052 |
1052 void FilterSamples() { | 1053 void FilterSamples() { |
1053 ScopeTimer sw("ProfileBuilder::FilterSamples", FLAG_trace_profiler); | 1054 ScopeTimer sw("ProfileBuilder::FilterSamples", FLAG_trace_profiler); |
1054 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 1055 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
1055 if (sample_buffer == NULL) { | 1056 if (sample_buffer == NULL) { |
1056 return; | 1057 return; |
1057 } | 1058 } |
1058 samples_ = sample_buffer->BuildProcessedSampleBuffer(filter_); | 1059 samples_ = sample_buffer->BuildProcessedSampleBuffer(filter_); |
1060 profile_->samples_ = samples_; | |
1059 profile_->sample_count_ = samples_->length(); | 1061 profile_->sample_count_ = samples_->length(); |
1060 } | 1062 } |
1061 | 1063 |
1062 void UpdateMinMaxTimes(int64_t timestamp) { | 1064 void UpdateMinMaxTimes(int64_t timestamp) { |
1063 profile_->min_time_ = | 1065 profile_->min_time_ = |
1064 timestamp < profile_->min_time_ ? timestamp : profile_->min_time_; | 1066 timestamp < profile_->min_time_ ? timestamp : profile_->min_time_; |
1065 profile_->max_time_ = | 1067 profile_->max_time_ = |
1066 timestamp > profile_->max_time_ ? timestamp : profile_->max_time_; | 1068 timestamp > profile_->max_time_ ? timestamp : profile_->max_time_; |
1067 } | 1069 } |
1068 | 1070 |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1326 current = AppendTruncatedTag(current); | 1328 current = AppendTruncatedTag(current); |
1327 } | 1329 } |
1328 | 1330 |
1329 // Walk the sampled PCs. | 1331 // Walk the sampled PCs. |
1330 for (intptr_t frame_index = sample->length() - 1; | 1332 for (intptr_t frame_index = sample->length() - 1; |
1331 frame_index >= 0; | 1333 frame_index >= 0; |
1332 frame_index--) { | 1334 frame_index--) { |
1333 ASSERT(sample->At(frame_index) != 0); | 1335 ASSERT(sample->At(frame_index) != 0); |
1334 current = ProcessFrame(current, sample_index, sample, frame_index); | 1336 current = ProcessFrame(current, sample_index, sample, frame_index); |
1335 } | 1337 } |
1338 | |
1339 sample->set_timeline_trie(current); | |
1336 } | 1340 } |
1337 } | 1341 } |
1338 | 1342 |
1339 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) { | 1343 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) { |
1340 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie", | 1344 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie", |
1341 FLAG_trace_profiler); | 1345 FLAG_trace_profiler); |
1342 ASSERT(tick_functions_); | 1346 ASSERT(tick_functions_); |
1343 for (intptr_t sample_index = 0; | 1347 for (intptr_t sample_index = 0; |
1344 sample_index < samples_->length(); | 1348 sample_index < samples_->length(); |
1345 sample_index++) { | 1349 sample_index++) { |
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1966 bool tick_functions_; | 1970 bool tick_functions_; |
1967 bool inclusive_tree_; | 1971 bool inclusive_tree_; |
1968 | 1972 |
1969 ProcessedSampleBuffer* samples_; | 1973 ProcessedSampleBuffer* samples_; |
1970 ProfileInfoKind info_kind_; | 1974 ProfileInfoKind info_kind_; |
1971 }; // ProfileBuilder. | 1975 }; // ProfileBuilder. |
1972 | 1976 |
1973 | 1977 |
1974 Profile::Profile(Isolate* isolate) | 1978 Profile::Profile(Isolate* isolate) |
1975 : isolate_(isolate), | 1979 : isolate_(isolate), |
1980 zone_(Thread::Current()->zone()), | |
1981 samples_(NULL), | |
1976 live_code_(NULL), | 1982 live_code_(NULL), |
1977 dead_code_(NULL), | 1983 dead_code_(NULL), |
1978 tag_code_(NULL), | 1984 tag_code_(NULL), |
1979 functions_(NULL), | 1985 functions_(NULL), |
1980 dead_code_index_offset_(-1), | 1986 dead_code_index_offset_(-1), |
1981 tag_code_index_offset_(-1), | 1987 tag_code_index_offset_(-1), |
1982 min_time_(kMaxInt64), | 1988 min_time_(kMaxInt64), |
1983 max_time_(0) { | 1989 max_time_(0) { |
1984 ASSERT(isolate_ != NULL); | 1990 ASSERT(isolate_ != NULL); |
1985 for (intptr_t i = 0; i < kNumTrieKinds; i++) { | 1991 for (intptr_t i = 0; i < kNumTrieKinds; i++) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2027 index -= tag_code_index_offset_; | 2033 index -= tag_code_index_offset_; |
2028 return tag_code_->At(index); | 2034 return tag_code_->At(index); |
2029 } | 2035 } |
2030 | 2036 |
2031 | 2037 |
2032 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { | 2038 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { |
2033 return roots_[static_cast<intptr_t>(trie_kind)]; | 2039 return roots_[static_cast<intptr_t>(trie_kind)]; |
2034 } | 2040 } |
2035 | 2041 |
2036 | 2042 |
2037 void Profile::PrintJSON(JSONStream* stream) { | 2043 void Profile::PrintTimelineFrameJSON(JSONObject* frames, |
2038 ScopeTimer sw("Profile::PrintJSON", FLAG_trace_profiler); | 2044 ProfileTrieNode* current, |
2045 ProfileTrieNode* parent, | |
2046 intptr_t* next_id) { | |
2047 ASSERT(current->frame_id() == -1); | |
2048 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.
| |
2049 *next_id = id + 1; | |
2050 current->set_frame_id(id); | |
2051 ASSERT(current->frame_id() != -1); | |
2052 | |
2053 { | |
2054 // The samples from many isolates may be merged into a single timeline, | |
2055 // so prefix frames id with the isolate. | |
2056 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); | |
2057 const char* key = zone_->PrintToString("f%" Pd "-%" Pd, | |
2058 isolate_id, current->frame_id()); | |
2059 JSONObject frame(frames, key); | |
2060 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
| |
2061 ProfileFunction* func = GetFunction(current->table_index()); | |
2062 frame.AddProperty("name", func->Name()); | |
2063 if (parent != NULL) { | |
2064 ASSERT(parent->frame_id() != -1); | |
2065 frame.AddPropertyF("parent", "f%" Pd "-%" Pd, | |
2066 isolate_id, parent->frame_id()); | |
2067 } | |
2068 } | |
2069 | |
2070 for (intptr_t i = 0; i < current->NumChildren(); i++) { | |
2071 ProfileTrieNode* child = current->At(i); | |
2072 PrintTimelineFrameJSON(frames, child, current, next_id); | |
2073 } | |
2074 } | |
2075 | |
2076 | |
2077 void Profile::PrintTimelineJSON(JSONStream* stream) { | |
2078 ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); | |
2079 JSONObject obj(stream); | |
2080 obj.AddProperty("type", "_CpuProfileTimeline"); | |
2081 obj.AddProperty("samplePeriod", | |
2082 static_cast<intptr_t>(FLAG_profile_period)); | |
2083 obj.AddProperty("stackDepth", | |
Cutch
2015/12/15 21:54:59
Factor this out into a PrintProfileHeaderJson() an
| |
2084 static_cast<intptr_t>(FLAG_max_profile_depth)); | |
2085 obj.AddProperty("sampleCount", sample_count()); | |
2086 obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); | |
2087 { | |
2088 JSONObject frames(&obj, "stackFrames"); | |
2089 ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); | |
2090 intptr_t next_id = 0; | |
2091 PrintTimelineFrameJSON(&frames, root, NULL, &next_id); | |
2092 } | |
2093 { | |
2094 JSONArray events(&obj, "traceEvents"); | |
2095 intptr_t pid = OS::ProcessId(); | |
2096 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); | |
2097 for (intptr_t sample_index = 0; | |
2098 sample_index < samples_->length(); | |
2099 sample_index++) { | |
2100 ProcessedSample* sample = samples_->At(sample_index); | |
2101 JSONObject event(&events); | |
2102 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.
| |
2103 event.AddProperty("ph", "P"); // kind = sample event | |
2104 event.AddProperty64("pid", pid); | |
2105 event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid())); | |
2106 event.AddPropertyTimeMicros("ts", sample->timestamp()); | |
2107 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.
| |
2108 | |
2109 ProfileTrieNode* trie = sample->timeline_trie(); | |
2110 ASSERT(trie->frame_id() != -1); | |
2111 event.AddPropertyF("sf", "f%" Pd "-%" Pd, | |
2112 isolate_id, trie->frame_id()); | |
2113 } | |
2114 } | |
2115 } | |
2116 | |
2117 | |
2118 void Profile::PrintProfileJSON(JSONStream* stream) { | |
2119 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); | |
2039 JSONObject obj(stream); | 2120 JSONObject obj(stream); |
2040 obj.AddProperty("type", "_CpuProfile"); | 2121 obj.AddProperty("type", "_CpuProfile"); |
2041 obj.AddProperty("samplePeriod", | 2122 obj.AddProperty("samplePeriod", |
2042 static_cast<intptr_t>(FLAG_profile_period)); | 2123 static_cast<intptr_t>(FLAG_profile_period)); |
2043 obj.AddProperty("stackDepth", | 2124 obj.AddProperty("stackDepth", |
2044 static_cast<intptr_t>(FLAG_max_profile_depth)); | 2125 static_cast<intptr_t>(FLAG_max_profile_depth)); |
2045 obj.AddProperty("sampleCount", sample_count()); | 2126 obj.AddProperty("sampleCount", sample_count()); |
2046 obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); | 2127 obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); |
2047 { | 2128 { |
2048 JSONArray codes(&obj, "codes"); | 2129 JSONArray codes(&obj, "codes"); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2189 intptr_t ProfileTrieWalker::SiblingCount() { | 2270 intptr_t ProfileTrieWalker::SiblingCount() { |
2190 ASSERT(parent_ != NULL); | 2271 ASSERT(parent_ != NULL); |
2191 return parent_->NumChildren(); | 2272 return parent_->NumChildren(); |
2192 } | 2273 } |
2193 | 2274 |
2194 | 2275 |
2195 void ProfilerService::PrintJSONImpl(Thread* thread, | 2276 void ProfilerService::PrintJSONImpl(Thread* thread, |
2196 JSONStream* stream, | 2277 JSONStream* stream, |
2197 Profile::TagOrder tag_order, | 2278 Profile::TagOrder tag_order, |
2198 intptr_t extra_tags, | 2279 intptr_t extra_tags, |
2199 SampleFilter* filter) { | 2280 SampleFilter* filter, |
2281 bool as_timeline) { | |
2200 Isolate* isolate = thread->isolate(); | 2282 Isolate* isolate = thread->isolate(); |
2201 // Disable thread interrupts while processing the buffer. | 2283 // Disable thread interrupts while processing the buffer. |
2202 DisableThreadInterruptsScope dtis(thread); | 2284 DisableThreadInterruptsScope dtis(thread); |
2203 | 2285 |
2204 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 2286 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
2205 if (sample_buffer == NULL) { | 2287 if (sample_buffer == NULL) { |
2206 stream->PrintError(kFeatureDisabled, NULL); | 2288 stream->PrintError(kFeatureDisabled, NULL); |
2207 return; | 2289 return; |
2208 } | 2290 } |
2209 | 2291 |
2210 { | 2292 { |
2211 StackZone zone(thread); | 2293 StackZone zone(thread); |
2212 HANDLESCOPE(thread); | 2294 HANDLESCOPE(thread); |
2213 Profile profile(isolate); | 2295 Profile profile(isolate); |
2214 profile.Build(thread, filter, tag_order, extra_tags); | 2296 profile.Build(thread, filter, tag_order, extra_tags); |
2215 profile.PrintJSON(stream); | 2297 if (as_timeline) { |
2298 profile.PrintTimelineJSON(stream); | |
2299 } else { | |
2300 profile.PrintProfileJSON(stream); | |
2301 } | |
2216 } | 2302 } |
2217 } | 2303 } |
2218 | 2304 |
2219 | 2305 |
2220 class NoAllocationSampleFilter : public SampleFilter { | 2306 class NoAllocationSampleFilter : public SampleFilter { |
2221 public: | 2307 public: |
2222 explicit NoAllocationSampleFilter(Isolate* isolate) | 2308 explicit NoAllocationSampleFilter(Isolate* isolate) |
2223 : SampleFilter(isolate) { | 2309 : SampleFilter(isolate) { |
2224 } | 2310 } |
2225 | 2311 |
2226 bool FilterSample(Sample* sample) { | 2312 bool FilterSample(Sample* sample) { |
2227 return !sample->is_allocation_sample(); | 2313 return !sample->is_allocation_sample(); |
2228 } | 2314 } |
2229 }; | 2315 }; |
2230 | 2316 |
2231 | 2317 |
2232 void ProfilerService::PrintJSON(JSONStream* stream, | 2318 void ProfilerService::PrintJSON(JSONStream* stream, |
2233 Profile::TagOrder tag_order, | 2319 Profile::TagOrder tag_order, |
2234 intptr_t extra_tags) { | 2320 intptr_t extra_tags) { |
2235 Thread* thread = Thread::Current(); | 2321 Thread* thread = Thread::Current(); |
2236 Isolate* isolate = thread->isolate(); | 2322 Isolate* isolate = thread->isolate(); |
2237 NoAllocationSampleFilter filter(isolate); | 2323 NoAllocationSampleFilter filter(isolate); |
2238 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter); | 2324 const bool as_timeline = false; |
2325 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, as_timeline); | |
2239 } | 2326 } |
2240 | 2327 |
2241 | 2328 |
2242 class ClassAllocationSampleFilter : public SampleFilter { | 2329 class ClassAllocationSampleFilter : public SampleFilter { |
2243 public: | 2330 public: |
2244 ClassAllocationSampleFilter(Isolate* isolate, const Class& cls) | 2331 ClassAllocationSampleFilter(Isolate* isolate, const Class& cls) |
2245 : SampleFilter(isolate), | 2332 : SampleFilter(isolate), |
2246 cls_(Class::Handle(cls.raw())) { | 2333 cls_(Class::Handle(cls.raw())) { |
2247 ASSERT(!cls_.IsNull()); | 2334 ASSERT(!cls_.IsNull()); |
2248 } | 2335 } |
2249 | 2336 |
2250 bool FilterSample(Sample* sample) { | 2337 bool FilterSample(Sample* sample) { |
2251 return sample->is_allocation_sample() && | 2338 return sample->is_allocation_sample() && |
2252 (sample->allocation_cid() == cls_.id()); | 2339 (sample->allocation_cid() == cls_.id()); |
2253 } | 2340 } |
2254 | 2341 |
2255 private: | 2342 private: |
2256 const Class& cls_; | 2343 const Class& cls_; |
2257 }; | 2344 }; |
2258 | 2345 |
2259 | 2346 |
2260 void ProfilerService::PrintAllocationJSON(JSONStream* stream, | 2347 void ProfilerService::PrintAllocationJSON(JSONStream* stream, |
2261 Profile::TagOrder tag_order, | 2348 Profile::TagOrder tag_order, |
2262 const Class& cls) { | 2349 const Class& cls) { |
2263 Thread* thread = Thread::Current(); | 2350 Thread* thread = Thread::Current(); |
2264 Isolate* isolate = thread->isolate(); | 2351 Isolate* isolate = thread->isolate(); |
2265 ClassAllocationSampleFilter filter(isolate, cls); | 2352 ClassAllocationSampleFilter filter(isolate, cls); |
2266 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter); | 2353 const bool as_timeline = false; |
2354 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); | |
2267 } | 2355 } |
2268 | 2356 |
2269 | 2357 |
2358 void ProfilerService::PrintTimelineJSON(JSONStream* stream, | |
2359 Profile::TagOrder tag_order) { | |
2360 Thread* thread = Thread::Current(); | |
2361 Isolate* isolate = thread->isolate(); | |
2362 NoAllocationSampleFilter filter(isolate); | |
2363 const bool as_timeline = true; | |
2364 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); | |
2365 } | |
2366 | |
2367 | |
2270 void ProfilerService::ClearSamples() { | 2368 void ProfilerService::ClearSamples() { |
2271 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 2369 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
2272 if (sample_buffer == NULL) { | 2370 if (sample_buffer == NULL) { |
2273 return; | 2371 return; |
2274 } | 2372 } |
2275 | 2373 |
2276 Thread* thread = Thread::Current(); | 2374 Thread* thread = Thread::Current(); |
2277 Isolate* isolate = thread->isolate(); | 2375 Isolate* isolate = thread->isolate(); |
2278 | 2376 |
2279 // Disable thread interrupts while processing the buffer. | 2377 // Disable thread interrupts while processing the buffer. |
2280 DisableThreadInterruptsScope dtis(thread); | 2378 DisableThreadInterruptsScope dtis(thread); |
2281 | 2379 |
2282 ClearProfileVisitor clear_profile(isolate); | 2380 ClearProfileVisitor clear_profile(isolate); |
2283 sample_buffer->VisitSamples(&clear_profile); | 2381 sample_buffer->VisitSamples(&clear_profile); |
2284 } | 2382 } |
2285 | 2383 |
2286 } // namespace dart | 2384 } // namespace dart |
OLD | NEW |