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::PrintHeaderJSON(JSONObject* obj) { |
2038 ScopeTimer sw("Profile::PrintJSON", FLAG_trace_profiler); | 2044 obj->AddProperty("samplePeriod", |
| 2045 static_cast<intptr_t>(FLAG_profile_period)); |
| 2046 obj->AddProperty("stackDepth", |
| 2047 static_cast<intptr_t>(FLAG_max_profile_depth)); |
| 2048 obj->AddProperty("sampleCount", sample_count()); |
| 2049 obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); |
| 2050 } |
| 2051 |
| 2052 |
| 2053 void Profile::PrintTimelineFrameJSON(JSONObject* frames, |
| 2054 ProfileTrieNode* current, |
| 2055 ProfileTrieNode* parent, |
| 2056 intptr_t* next_id) { |
| 2057 ASSERT(current->frame_id() == -1); |
| 2058 const intptr_t id = *next_id; |
| 2059 *next_id = id + 1; |
| 2060 current->set_frame_id(id); |
| 2061 ASSERT(current->frame_id() != -1); |
| 2062 |
| 2063 { |
| 2064 // The samples from many isolates may be merged into a single timeline, |
| 2065 // so prefix frames id with the isolate. |
| 2066 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); |
| 2067 const char* key = zone_->PrintToString("%" Pd "-%" Pd, |
| 2068 isolate_id, current->frame_id()); |
| 2069 JSONObject frame(frames, key); |
| 2070 frame.AddProperty("category", "Dart"); |
| 2071 ProfileFunction* func = GetFunction(current->table_index()); |
| 2072 frame.AddProperty("name", func->Name()); |
| 2073 if (parent != NULL) { |
| 2074 ASSERT(parent->frame_id() != -1); |
| 2075 frame.AddPropertyF("parent", "%" Pd "-%" Pd, |
| 2076 isolate_id, parent->frame_id()); |
| 2077 } |
| 2078 } |
| 2079 |
| 2080 for (intptr_t i = 0; i < current->NumChildren(); i++) { |
| 2081 ProfileTrieNode* child = current->At(i); |
| 2082 PrintTimelineFrameJSON(frames, child, current, next_id); |
| 2083 } |
| 2084 } |
| 2085 |
| 2086 |
| 2087 void Profile::PrintTimelineJSON(JSONStream* stream) { |
| 2088 ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); |
| 2089 JSONObject obj(stream); |
| 2090 obj.AddProperty("type", "_CpuProfileTimeline"); |
| 2091 PrintHeaderJSON(&obj); |
| 2092 { |
| 2093 JSONObject frames(&obj, "stackFrames"); |
| 2094 ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); |
| 2095 intptr_t next_id = 0; |
| 2096 PrintTimelineFrameJSON(&frames, root, NULL, &next_id); |
| 2097 } |
| 2098 { |
| 2099 JSONArray events(&obj, "traceEvents"); |
| 2100 intptr_t pid = OS::ProcessId(); |
| 2101 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); |
| 2102 for (intptr_t sample_index = 0; |
| 2103 sample_index < samples_->length(); |
| 2104 sample_index++) { |
| 2105 ProcessedSample* sample = samples_->At(sample_index); |
| 2106 JSONObject event(&events); |
| 2107 event.AddProperty("ph", "P"); // kind = sample event |
| 2108 event.AddProperty64("pid", pid); |
| 2109 event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid())); |
| 2110 event.AddPropertyTimeMicros("ts", sample->timestamp()); |
| 2111 event.AddProperty("cat", "Dart"); |
| 2112 |
| 2113 ProfileTrieNode* trie = sample->timeline_trie(); |
| 2114 ASSERT(trie->frame_id() != -1); |
| 2115 event.AddPropertyF("sf", "%" Pd "-%" Pd, |
| 2116 isolate_id, trie->frame_id()); |
| 2117 } |
| 2118 } |
| 2119 } |
| 2120 |
| 2121 |
| 2122 void Profile::PrintProfileJSON(JSONStream* stream) { |
| 2123 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); |
2039 JSONObject obj(stream); | 2124 JSONObject obj(stream); |
2040 obj.AddProperty("type", "_CpuProfile"); | 2125 obj.AddProperty("type", "_CpuProfile"); |
2041 obj.AddProperty("samplePeriod", | 2126 PrintHeaderJSON(&obj); |
2042 static_cast<intptr_t>(FLAG_profile_period)); | |
2043 obj.AddProperty("stackDepth", | |
2044 static_cast<intptr_t>(FLAG_max_profile_depth)); | |
2045 obj.AddProperty("sampleCount", sample_count()); | |
2046 obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); | |
2047 { | 2127 { |
2048 JSONArray codes(&obj, "codes"); | 2128 JSONArray codes(&obj, "codes"); |
2049 for (intptr_t i = 0; i < live_code_->length(); i++) { | 2129 for (intptr_t i = 0; i < live_code_->length(); i++) { |
2050 ProfileCode* code = live_code_->At(i); | 2130 ProfileCode* code = live_code_->At(i); |
2051 ASSERT(code != NULL); | 2131 ASSERT(code != NULL); |
2052 code->PrintToJSONArray(&codes); | 2132 code->PrintToJSONArray(&codes); |
2053 } | 2133 } |
2054 for (intptr_t i = 0; i < dead_code_->length(); i++) { | 2134 for (intptr_t i = 0; i < dead_code_->length(); i++) { |
2055 ProfileCode* code = dead_code_->At(i); | 2135 ProfileCode* code = dead_code_->At(i); |
2056 ASSERT(code != NULL); | 2136 ASSERT(code != NULL); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2189 intptr_t ProfileTrieWalker::SiblingCount() { | 2269 intptr_t ProfileTrieWalker::SiblingCount() { |
2190 ASSERT(parent_ != NULL); | 2270 ASSERT(parent_ != NULL); |
2191 return parent_->NumChildren(); | 2271 return parent_->NumChildren(); |
2192 } | 2272 } |
2193 | 2273 |
2194 | 2274 |
2195 void ProfilerService::PrintJSONImpl(Thread* thread, | 2275 void ProfilerService::PrintJSONImpl(Thread* thread, |
2196 JSONStream* stream, | 2276 JSONStream* stream, |
2197 Profile::TagOrder tag_order, | 2277 Profile::TagOrder tag_order, |
2198 intptr_t extra_tags, | 2278 intptr_t extra_tags, |
2199 SampleFilter* filter) { | 2279 SampleFilter* filter, |
| 2280 bool as_timeline) { |
2200 Isolate* isolate = thread->isolate(); | 2281 Isolate* isolate = thread->isolate(); |
2201 // Disable thread interrupts while processing the buffer. | 2282 // Disable thread interrupts while processing the buffer. |
2202 DisableThreadInterruptsScope dtis(thread); | 2283 DisableThreadInterruptsScope dtis(thread); |
2203 | 2284 |
2204 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 2285 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
2205 if (sample_buffer == NULL) { | 2286 if (sample_buffer == NULL) { |
2206 stream->PrintError(kFeatureDisabled, NULL); | 2287 stream->PrintError(kFeatureDisabled, NULL); |
2207 return; | 2288 return; |
2208 } | 2289 } |
2209 | 2290 |
2210 { | 2291 { |
2211 StackZone zone(thread); | 2292 StackZone zone(thread); |
2212 HANDLESCOPE(thread); | 2293 HANDLESCOPE(thread); |
2213 Profile profile(isolate); | 2294 Profile profile(isolate); |
2214 profile.Build(thread, filter, tag_order, extra_tags); | 2295 profile.Build(thread, filter, tag_order, extra_tags); |
2215 profile.PrintJSON(stream); | 2296 if (as_timeline) { |
| 2297 profile.PrintTimelineJSON(stream); |
| 2298 } else { |
| 2299 profile.PrintProfileJSON(stream); |
| 2300 } |
2216 } | 2301 } |
2217 } | 2302 } |
2218 | 2303 |
2219 | 2304 |
2220 class NoAllocationSampleFilter : public SampleFilter { | 2305 class NoAllocationSampleFilter : public SampleFilter { |
2221 public: | 2306 public: |
2222 explicit NoAllocationSampleFilter(Isolate* isolate) | 2307 explicit NoAllocationSampleFilter(Isolate* isolate) |
2223 : SampleFilter(isolate) { | 2308 : SampleFilter(isolate) { |
2224 } | 2309 } |
2225 | 2310 |
2226 bool FilterSample(Sample* sample) { | 2311 bool FilterSample(Sample* sample) { |
2227 return !sample->is_allocation_sample(); | 2312 return !sample->is_allocation_sample(); |
2228 } | 2313 } |
2229 }; | 2314 }; |
2230 | 2315 |
2231 | 2316 |
2232 void ProfilerService::PrintJSON(JSONStream* stream, | 2317 void ProfilerService::PrintJSON(JSONStream* stream, |
2233 Profile::TagOrder tag_order, | 2318 Profile::TagOrder tag_order, |
2234 intptr_t extra_tags) { | 2319 intptr_t extra_tags) { |
2235 Thread* thread = Thread::Current(); | 2320 Thread* thread = Thread::Current(); |
2236 Isolate* isolate = thread->isolate(); | 2321 Isolate* isolate = thread->isolate(); |
2237 NoAllocationSampleFilter filter(isolate); | 2322 NoAllocationSampleFilter filter(isolate); |
2238 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter); | 2323 const bool as_timeline = false; |
| 2324 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, as_timeline); |
2239 } | 2325 } |
2240 | 2326 |
2241 | 2327 |
2242 class ClassAllocationSampleFilter : public SampleFilter { | 2328 class ClassAllocationSampleFilter : public SampleFilter { |
2243 public: | 2329 public: |
2244 ClassAllocationSampleFilter(Isolate* isolate, const Class& cls) | 2330 ClassAllocationSampleFilter(Isolate* isolate, const Class& cls) |
2245 : SampleFilter(isolate), | 2331 : SampleFilter(isolate), |
2246 cls_(Class::Handle(cls.raw())) { | 2332 cls_(Class::Handle(cls.raw())) { |
2247 ASSERT(!cls_.IsNull()); | 2333 ASSERT(!cls_.IsNull()); |
2248 } | 2334 } |
2249 | 2335 |
2250 bool FilterSample(Sample* sample) { | 2336 bool FilterSample(Sample* sample) { |
2251 return sample->is_allocation_sample() && | 2337 return sample->is_allocation_sample() && |
2252 (sample->allocation_cid() == cls_.id()); | 2338 (sample->allocation_cid() == cls_.id()); |
2253 } | 2339 } |
2254 | 2340 |
2255 private: | 2341 private: |
2256 const Class& cls_; | 2342 const Class& cls_; |
2257 }; | 2343 }; |
2258 | 2344 |
2259 | 2345 |
2260 void ProfilerService::PrintAllocationJSON(JSONStream* stream, | 2346 void ProfilerService::PrintAllocationJSON(JSONStream* stream, |
2261 Profile::TagOrder tag_order, | 2347 Profile::TagOrder tag_order, |
2262 const Class& cls) { | 2348 const Class& cls) { |
2263 Thread* thread = Thread::Current(); | 2349 Thread* thread = Thread::Current(); |
2264 Isolate* isolate = thread->isolate(); | 2350 Isolate* isolate = thread->isolate(); |
2265 ClassAllocationSampleFilter filter(isolate, cls); | 2351 ClassAllocationSampleFilter filter(isolate, cls); |
2266 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter); | 2352 const bool as_timeline = false; |
| 2353 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); |
2267 } | 2354 } |
2268 | 2355 |
2269 | 2356 |
| 2357 void ProfilerService::PrintTimelineJSON(JSONStream* stream, |
| 2358 Profile::TagOrder tag_order) { |
| 2359 Thread* thread = Thread::Current(); |
| 2360 Isolate* isolate = thread->isolate(); |
| 2361 NoAllocationSampleFilter filter(isolate); |
| 2362 const bool as_timeline = true; |
| 2363 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); |
| 2364 } |
| 2365 |
| 2366 |
2270 void ProfilerService::ClearSamples() { | 2367 void ProfilerService::ClearSamples() { |
2271 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 2368 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
2272 if (sample_buffer == NULL) { | 2369 if (sample_buffer == NULL) { |
2273 return; | 2370 return; |
2274 } | 2371 } |
2275 | 2372 |
2276 Thread* thread = Thread::Current(); | 2373 Thread* thread = Thread::Current(); |
2277 Isolate* isolate = thread->isolate(); | 2374 Isolate* isolate = thread->isolate(); |
2278 | 2375 |
2279 // Disable thread interrupts while processing the buffer. | 2376 // Disable thread interrupts while processing the buffer. |
2280 DisableThreadInterruptsScope dtis(thread); | 2377 DisableThreadInterruptsScope dtis(thread); |
2281 | 2378 |
2282 ClearProfileVisitor clear_profile(isolate); | 2379 ClearProfileVisitor clear_profile(isolate); |
2283 sample_buffer->VisitSamples(&clear_profile); | 2380 sample_buffer->VisitSamples(&clear_profile); |
2284 } | 2381 } |
2285 | 2382 |
2286 } // namespace dart | 2383 } // namespace dart |
OLD | NEW |