Chromium Code Reviews| 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 |