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