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/hash_map.h" | |
8 #include "vm/log.h" | 9 #include "vm/log.h" |
9 #include "vm/native_symbol.h" | 10 #include "vm/native_symbol.h" |
10 #include "vm/object.h" | 11 #include "vm/object.h" |
11 #include "vm/os.h" | 12 #include "vm/os.h" |
12 #include "vm/profiler.h" | 13 #include "vm/profiler.h" |
13 #include "vm/reusable_handles.h" | 14 #include "vm/reusable_handles.h" |
14 #include "vm/scope_timer.h" | 15 #include "vm/scope_timer.h" |
15 | 16 |
16 namespace dart { | 17 namespace dart { |
17 | 18 |
18 DECLARE_FLAG(int, max_profile_depth); | 19 DECLARE_FLAG(int, max_profile_depth); |
19 DECLARE_FLAG(int, profile_period); | 20 DECLARE_FLAG(int, profile_period); |
20 | 21 |
21 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler."); | 22 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler."); |
Ivan Posva
2016/03/23 15:14:39
Please move these flags into the common flags file
Cutch
2016/03/23 19:34:21
Done.
| |
23 DEFINE_FLAG(bool, trace_profiler_verbose, false, "Verbose trace profiler."); | |
22 | 24 |
23 #ifndef PRODUCT | 25 #ifndef PRODUCT |
24 | 26 |
25 class DeoptimizedCodeSet : public ZoneAllocated { | 27 class DeoptimizedCodeSet : public ZoneAllocated { |
26 public: | 28 public: |
27 explicit DeoptimizedCodeSet(Isolate* isolate) | 29 explicit DeoptimizedCodeSet(Isolate* isolate) |
28 : previous_( | 30 : previous_( |
29 GrowableObjectArray::ZoneHandle(isolate->deoptimized_code_array())), | 31 GrowableObjectArray::ZoneHandle(isolate->deoptimized_code_array())), |
30 current_(GrowableObjectArray::ZoneHandle( | 32 current_(GrowableObjectArray::ZoneHandle( |
31 previous_.IsNull() ? GrowableObjectArray::null() : | 33 previous_.IsNull() ? GrowableObjectArray::null() : |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 TickSourcePosition(token_position, false); | 156 TickSourcePosition(token_position, false); |
155 } | 157 } |
156 | 158 |
157 | 159 |
158 void ProfileFunction::TickSourcePosition(TokenPosition token_position, | 160 void ProfileFunction::TickSourcePosition(TokenPosition token_position, |
159 bool exclusive) { | 161 bool exclusive) { |
160 intptr_t i = 0; | 162 intptr_t i = 0; |
161 for (; i < source_position_ticks_.length(); i++) { | 163 for (; i < source_position_ticks_.length(); i++) { |
162 ProfileFunctionSourcePosition& position = source_position_ticks_[i]; | 164 ProfileFunctionSourcePosition& position = source_position_ticks_[i]; |
163 if (position.token_pos().value() == token_position.value()) { | 165 if (position.token_pos().value() == token_position.value()) { |
164 if (FLAG_trace_profiler) { | 166 if (FLAG_trace_profiler_verbose) { |
165 OS::Print("Ticking source position %s %s\n", | 167 OS::Print("Ticking source position %s %s\n", |
166 exclusive ? "exclusive" : "inclusive", | 168 exclusive ? "exclusive" : "inclusive", |
167 token_position.ToCString()); | 169 token_position.ToCString()); |
168 } | 170 } |
169 // Found existing position, tick it. | 171 // Found existing position, tick it. |
170 position.Tick(exclusive); | 172 position.Tick(exclusive); |
171 return; | 173 return; |
172 } | 174 } |
173 if (position.token_pos().value() > token_position.value()) { | 175 if (position.token_pos().value() > token_position.value()) { |
174 break; | 176 break; |
175 } | 177 } |
176 } | 178 } |
177 | 179 |
178 // Add new one, sorted by token position value. | 180 // Add new one, sorted by token position value. |
179 ProfileFunctionSourcePosition pfsp(token_position); | 181 ProfileFunctionSourcePosition pfsp(token_position); |
180 if (FLAG_trace_profiler) { | 182 if (FLAG_trace_profiler_verbose) { |
181 OS::Print("Ticking source position %s %s\n", | 183 OS::Print("Ticking source position %s %s\n", |
182 exclusive ? "exclusive" : "inclusive", | 184 exclusive ? "exclusive" : "inclusive", |
183 token_position.ToCString()); | 185 token_position.ToCString()); |
184 } | 186 } |
185 pfsp.Tick(exclusive); | 187 pfsp.Tick(exclusive); |
186 | 188 |
187 if (i < source_position_ticks_.length()) { | 189 if (i < source_position_ticks_.length()) { |
188 source_position_ticks_.InsertAt(i, pfsp); | 190 source_position_ticks_.InsertAt(i, pfsp); |
189 } else { | 191 } else { |
190 source_position_ticks_.Add(pfsp); | 192 source_position_ticks_.Add(pfsp); |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 ticks.AddValueF("%" Pd "", entry.inclusive_ticks()); | 510 ticks.AddValueF("%" Pd "", entry.inclusive_ticks()); |
509 } | 511 } |
510 } | 512 } |
511 } | 513 } |
512 | 514 |
513 | 515 |
514 class ProfileFunctionTable : public ZoneAllocated { | 516 class ProfileFunctionTable : public ZoneAllocated { |
515 public: | 517 public: |
516 ProfileFunctionTable() | 518 ProfileFunctionTable() |
517 : null_function_(Function::ZoneHandle()), | 519 : null_function_(Function::ZoneHandle()), |
518 table_(8), | 520 unknown_function_(NULL), |
519 unknown_function_(NULL) { | 521 table_(8) { |
520 unknown_function_ = Add(ProfileFunction::kUnknownFunction, | 522 unknown_function_ = Add(ProfileFunction::kUnknownFunction, |
521 "<unknown Dart function>"); | 523 "<unknown Dart function>"); |
522 } | 524 } |
523 | 525 |
524 ProfileFunction* LookupOrAdd(const Function& function) { | 526 ProfileFunction* LookupOrAdd(const Function& function) { |
525 ASSERT(!function.IsNull()); | 527 ASSERT(!function.IsNull()); |
526 ProfileFunction* profile_function = Lookup(function); | 528 ProfileFunction* profile_function = Lookup(function); |
527 if (profile_function != NULL) { | 529 if (profile_function != NULL) { |
528 return profile_function; | 530 return profile_function; |
529 } | 531 } |
530 return Add(function); | 532 return Add(function); |
531 } | 533 } |
532 | 534 |
533 intptr_t LookupIndex(const Function& function) { | 535 ProfileFunction* Lookup(const Function& function) { |
534 ASSERT(!function.IsNull()); | 536 ASSERT(!function.IsNull()); |
535 for (intptr_t i = 0; i < table_.length(); i++) { | 537 return function_hash_.Lookup(&function); |
536 ProfileFunction* profile_function = table_[i]; | |
537 if (profile_function->function() == function.raw()) { | |
538 return i; | |
539 } | |
540 } | |
541 return -1; | |
542 } | 538 } |
543 | 539 |
544 ProfileFunction* GetUnknown() { | 540 ProfileFunction* GetUnknown() { |
545 ASSERT(unknown_function_ != NULL); | 541 ASSERT(unknown_function_ != NULL); |
546 return unknown_function_; | 542 return unknown_function_; |
547 } | 543 } |
548 | 544 |
549 // No protection against being called more than once for the same tag_id. | 545 // No protection against being called more than once for the same tag_id. |
550 ProfileFunction* AddTag(uword tag_id, const char* name) { | 546 ProfileFunction* AddTag(uword tag_id, const char* name) { |
551 // TODO(johnmccutchan): Canonicalize ProfileFunctions for tags. | 547 // TODO(johnmccutchan): Canonicalize ProfileFunctions for tags. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 } | 584 } |
589 | 585 |
590 ProfileFunction* Add(const Function& function) { | 586 ProfileFunction* Add(const Function& function) { |
591 ASSERT(Lookup(function) == NULL); | 587 ASSERT(Lookup(function) == NULL); |
592 ProfileFunction* profile_function = | 588 ProfileFunction* profile_function = |
593 new ProfileFunction(ProfileFunction::kDartFunction, | 589 new ProfileFunction(ProfileFunction::kDartFunction, |
594 NULL, | 590 NULL, |
595 function, | 591 function, |
596 table_.length()); | 592 table_.length()); |
597 table_.Add(profile_function); | 593 table_.Add(profile_function); |
594 function_hash_.Insert(profile_function); | |
598 return profile_function; | 595 return profile_function; |
599 } | 596 } |
600 | 597 |
601 ProfileFunction* Lookup(const Function& function) { | 598 // Needed for DirectChainedHashMap. |
602 ASSERT(!function.IsNull()); | 599 struct ProfileFunctionTableTrait { |
603 intptr_t index = LookupIndex(function); | 600 typedef ProfileFunction* Value; |
604 if (index == -1) { | 601 typedef const Function* Key; |
605 return NULL; | 602 typedef ProfileFunction* Pair; |
603 | |
604 static Key KeyOf(Pair kv) { | |
605 return kv->key(); | |
Ivan Posva
2016/03/23 15:14:39
Personally I find these typedefs confusing, as wel
Cutch
2016/03/23 19:34:21
I've renamed key() to function() but the typedefs
| |
606 } | 606 } |
607 return table_[index]; | 607 |
608 } | 608 static Value ValueOf(Pair kv) { |
609 return kv; | |
610 } | |
611 | |
612 static inline intptr_t Hashcode(Key key) { | |
613 return key->Hash(); | |
614 } | |
615 | |
616 static inline bool IsKeyEqual(Pair kv, Key key) { | |
617 return kv->key()->raw() == key->raw(); | |
618 } | |
619 }; | |
609 | 620 |
610 const Function& null_function_; | 621 const Function& null_function_; |
622 ProfileFunction* unknown_function_; | |
611 ZoneGrowableArray<ProfileFunction*> table_; | 623 ZoneGrowableArray<ProfileFunction*> table_; |
612 ProfileFunction* unknown_function_; | 624 DirectChainedHashMap<ProfileFunctionTableTrait> function_hash_; |
613 }; | 625 }; |
614 | 626 |
615 | 627 |
616 ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) { | 628 ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) { |
617 ASSERT(function_ == NULL); | 629 ASSERT(function_ == NULL); |
618 | 630 |
619 ProfileFunction* function = NULL; | 631 ProfileFunction* function = NULL; |
620 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) { | 632 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) { |
621 if (name() == NULL) { | 633 if (name() == NULL) { |
622 // Lazily set generated name. | 634 // Lazily set generated name. |
(...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1491 &inlined_functions, | 1503 &inlined_functions, |
1492 &inlined_token_positions); | 1504 &inlined_token_positions); |
1493 token_position = code.GetTokenPositionAt(offset); | 1505 token_position = code.GetTokenPositionAt(offset); |
1494 if (inlined_functions.length() > 0) { | 1506 if (inlined_functions.length() > 0) { |
1495 // The inlined token position table does not include the token position | 1507 // The inlined token position table does not include the token position |
1496 // of the final call. Insert it at the beginning because the table. | 1508 // of the final call. Insert it at the beginning because the table. |
1497 // is reversed. | 1509 // is reversed. |
1498 inlined_token_positions.InsertAt(0, token_position); | 1510 inlined_token_positions.InsertAt(0, token_position); |
1499 } | 1511 } |
1500 ASSERT(inlined_functions.length() <= inlined_token_positions.length()); | 1512 ASSERT(inlined_functions.length() <= inlined_token_positions.length()); |
1501 if (FLAG_trace_profiler) { | 1513 if (FLAG_trace_profiler_verbose) { |
1502 for (intptr_t i = 0; i < inlined_functions.length(); i++) { | 1514 for (intptr_t i = 0; i < inlined_functions.length(); i++) { |
1503 const String& name = | 1515 const String& name = |
1504 String::Handle(inlined_functions[i]->QualifiedScrubbedName()); | 1516 String::Handle(inlined_functions[i]->QualifiedScrubbedName()); |
1505 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", | 1517 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", |
1506 i, | 1518 i, |
1507 name.ToCString(), | 1519 name.ToCString(), |
1508 inlined_token_positions[i].ToCString()); | 1520 inlined_token_positions[i].ToCString()); |
1509 } | 1521 } |
1510 } | 1522 } |
1511 } | 1523 } |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1609 } | 1621 } |
1610 | 1622 |
1611 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, | 1623 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, |
1612 intptr_t sample_index, | 1624 intptr_t sample_index, |
1613 ProcessedSample* sample, | 1625 ProcessedSample* sample, |
1614 intptr_t frame_index, | 1626 intptr_t frame_index, |
1615 ProfileFunction* function, | 1627 ProfileFunction* function, |
1616 TokenPosition token_position, | 1628 TokenPosition token_position, |
1617 intptr_t code_index) { | 1629 intptr_t code_index) { |
1618 if (tick_functions_) { | 1630 if (tick_functions_) { |
1619 if (FLAG_trace_profiler) { | 1631 if (FLAG_trace_profiler_verbose) { |
1620 THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", | 1632 THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", |
1621 sample_index, | 1633 sample_index, |
1622 frame_index, | 1634 frame_index, |
1623 function->Name(), | 1635 function->Name(), |
1624 token_position.ToCString(), | 1636 token_position.ToCString(), |
1625 sample->At(frame_index)); | 1637 sample->At(frame_index)); |
1626 } | 1638 } |
1627 function->Tick(IsExecutingFrame(sample, frame_index), | 1639 function->Tick(IsExecutingFrame(sample, frame_index), |
1628 sample_index, | 1640 sample_index, |
1629 token_position); | 1641 token_position); |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2252 ProfileTrieNode* trie = sample->timeline_trie(); | 2264 ProfileTrieNode* trie = sample->timeline_trie(); |
2253 ASSERT(trie->frame_id() != -1); | 2265 ASSERT(trie->frame_id() != -1); |
2254 event.AddPropertyF("sf", "%" Pd "-%" Pd, | 2266 event.AddPropertyF("sf", "%" Pd "-%" Pd, |
2255 isolate_id, trie->frame_id()); | 2267 isolate_id, trie->frame_id()); |
2256 } | 2268 } |
2257 } | 2269 } |
2258 } | 2270 } |
2259 | 2271 |
2260 | 2272 |
2261 ProfileFunction* Profile::FindFunction(const Function& function) { | 2273 ProfileFunction* Profile::FindFunction(const Function& function) { |
2262 const intptr_t index = functions_->LookupIndex(function); | 2274 return functions_->Lookup(function); |
2263 if (index < 0) { | |
2264 return NULL; | |
2265 } | |
2266 return functions_->At(index); | |
2267 } | 2275 } |
2268 | 2276 |
2269 | 2277 |
2270 void Profile::PrintProfileJSON(JSONStream* stream) { | 2278 void Profile::PrintProfileJSON(JSONStream* stream) { |
2271 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); | 2279 ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler); |
2272 JSONObject obj(stream); | 2280 JSONObject obj(stream); |
2273 obj.AddProperty("type", "_CpuProfile"); | 2281 obj.AddProperty("type", "_CpuProfile"); |
2274 PrintHeaderJSON(&obj); | 2282 PrintHeaderJSON(&obj); |
2275 { | 2283 { |
2276 JSONArray codes(&obj, "codes"); | 2284 JSONArray codes(&obj, "codes"); |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2601 // Disable thread interrupts while processing the buffer. | 2609 // Disable thread interrupts while processing the buffer. |
2602 DisableThreadInterruptsScope dtis(thread); | 2610 DisableThreadInterruptsScope dtis(thread); |
2603 | 2611 |
2604 ClearProfileVisitor clear_profile(isolate); | 2612 ClearProfileVisitor clear_profile(isolate); |
2605 sample_buffer->VisitSamples(&clear_profile); | 2613 sample_buffer->VisitSamples(&clear_profile); |
2606 } | 2614 } |
2607 | 2615 |
2608 #endif // !PRODUCT | 2616 #endif // !PRODUCT |
2609 | 2617 |
2610 } // namespace dart | 2618 } // namespace dart |
OLD | NEW |