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

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: self review 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
« runtime/vm/profiler_service.h ('K') | « 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 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
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
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
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
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
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
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
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
OLDNEW
« runtime/vm/profiler_service.h ('K') | « runtime/vm/profiler_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698