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 |