Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: runtime/vm/profiler_service.cc

Issue 1830473002: Speedup function profile by using a hash table instead of a linear scan (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698