OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/profiler/profile-generator.h" | 5 #include "src/profiler/profile-generator.h" |
6 | 6 |
7 #include "src/ast/scopeinfo.h" | 7 #include "src/ast/scopeinfo.h" |
8 #include "src/base/adapters.h" | 8 #include "src/base/adapters.h" |
9 #include "src/debug/debug.h" | 9 #include "src/debug/debug.h" |
10 #include "src/deoptimizer.h" | 10 #include "src/deoptimizer.h" |
(...skipping 30 matching lines...) Expand all Loading... |
41 } | 41 } |
42 return it->second; | 42 return it->second; |
43 } | 43 } |
44 | 44 |
45 | 45 |
46 const char* const CodeEntry::kEmptyNamePrefix = ""; | 46 const char* const CodeEntry::kEmptyNamePrefix = ""; |
47 const char* const CodeEntry::kEmptyResourceName = ""; | 47 const char* const CodeEntry::kEmptyResourceName = ""; |
48 const char* const CodeEntry::kEmptyBailoutReason = ""; | 48 const char* const CodeEntry::kEmptyBailoutReason = ""; |
49 const char* const CodeEntry::kNoDeoptReason = ""; | 49 const char* const CodeEntry::kNoDeoptReason = ""; |
50 | 50 |
51 const char* const CodeEntry::kProgramEntryName = "(program)"; | |
52 const char* const CodeEntry::kIdleEntryName = "(idle)"; | |
53 const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)"; | |
54 const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)"; | |
55 | |
56 base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type | |
57 CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
58 | |
59 base::LazyDynamicInstance<CodeEntry, CodeEntry::IdleEntryCreateTrait>::type | |
60 CodeEntry::kIdleEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
61 | |
62 base::LazyDynamicInstance<CodeEntry, CodeEntry::GCEntryCreateTrait>::type | |
63 CodeEntry::kGCEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
64 | |
65 base::LazyDynamicInstance<CodeEntry, | |
66 CodeEntry::UnresolvedEntryCreateTrait>::type | |
67 CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
68 | |
69 CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() { | |
70 return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kProgramEntryName); | |
71 } | |
72 | |
73 CodeEntry* CodeEntry::IdleEntryCreateTrait::Create() { | |
74 return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kIdleEntryName); | |
75 } | |
76 | |
77 CodeEntry* CodeEntry::GCEntryCreateTrait::Create() { | |
78 return new CodeEntry(Logger::BUILTIN_TAG, | |
79 CodeEntry::kGarbageCollectorEntryName); | |
80 } | |
81 | |
82 CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() { | |
83 return new CodeEntry(Logger::FUNCTION_TAG, | |
84 CodeEntry::kUnresolvedFunctionName); | |
85 } | |
86 | 51 |
87 CodeEntry::~CodeEntry() { | 52 CodeEntry::~CodeEntry() { |
88 delete line_info_; | 53 delete line_info_; |
89 for (auto location : inline_locations_) { | 54 for (auto location : inline_locations_) { |
90 for (auto entry : location.second) { | 55 for (auto entry : location.second) { |
91 delete entry; | 56 delete entry; |
92 } | 57 } |
93 } | 58 } |
94 } | 59 } |
95 | 60 |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 } | 426 } |
462 | 427 |
463 void CodeMap::Print() { | 428 void CodeMap::Print() { |
464 for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { | 429 for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { |
465 base::OS::Print("%p %5d %s\n", static_cast<void*>(it->first), | 430 base::OS::Print("%p %5d %s\n", static_cast<void*>(it->first), |
466 it->second.size, it->second.entry->name()); | 431 it->second.size, it->second.entry->name()); |
467 } | 432 } |
468 } | 433 } |
469 | 434 |
470 CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) | 435 CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) |
471 : resource_names_(isolate->heap()), | 436 : function_and_resource_names_(isolate->heap()), |
472 profiler_(nullptr), | 437 profiler_(nullptr), |
473 current_profiles_semaphore_(1) {} | 438 current_profiles_semaphore_(1) {} |
474 | 439 |
| 440 static void DeleteCodeEntry(CodeEntry** entry_ptr) { |
| 441 delete *entry_ptr; |
| 442 } |
| 443 |
| 444 |
475 static void DeleteCpuProfile(CpuProfile** profile_ptr) { | 445 static void DeleteCpuProfile(CpuProfile** profile_ptr) { |
476 delete *profile_ptr; | 446 delete *profile_ptr; |
477 } | 447 } |
478 | 448 |
479 | 449 |
480 CpuProfilesCollection::~CpuProfilesCollection() { | 450 CpuProfilesCollection::~CpuProfilesCollection() { |
481 finished_profiles_.Iterate(DeleteCpuProfile); | 451 finished_profiles_.Iterate(DeleteCpuProfile); |
482 current_profiles_.Iterate(DeleteCpuProfile); | 452 current_profiles_.Iterate(DeleteCpuProfile); |
| 453 code_entries_.Iterate(DeleteCodeEntry); |
483 } | 454 } |
484 | 455 |
485 | 456 |
486 bool CpuProfilesCollection::StartProfiling(const char* title, | 457 bool CpuProfilesCollection::StartProfiling(const char* title, |
487 bool record_samples) { | 458 bool record_samples) { |
488 current_profiles_semaphore_.Wait(); | 459 current_profiles_semaphore_.Wait(); |
489 if (current_profiles_.length() >= kMaxSimultaneousProfiles) { | 460 if (current_profiles_.length() >= kMaxSimultaneousProfiles) { |
490 current_profiles_semaphore_.Signal(); | 461 current_profiles_semaphore_.Signal(); |
491 return false; | 462 return false; |
492 } | 463 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 // As starting / stopping profiles is rare relatively to this | 520 // As starting / stopping profiles is rare relatively to this |
550 // method, we don't bother minimizing the duration of lock holding, | 521 // method, we don't bother minimizing the duration of lock holding, |
551 // e.g. copying contents of the list to a local vector. | 522 // e.g. copying contents of the list to a local vector. |
552 current_profiles_semaphore_.Wait(); | 523 current_profiles_semaphore_.Wait(); |
553 for (int i = 0; i < current_profiles_.length(); ++i) { | 524 for (int i = 0; i < current_profiles_.length(); ++i) { |
554 current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); | 525 current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); |
555 } | 526 } |
556 current_profiles_semaphore_.Signal(); | 527 current_profiles_semaphore_.Signal(); |
557 } | 528 } |
558 | 529 |
| 530 CodeEntry* CpuProfilesCollection::NewCodeEntry( |
| 531 CodeEventListener::LogEventsAndTags tag, const char* name, |
| 532 const char* name_prefix, const char* resource_name, int line_number, |
| 533 int column_number, JITLineInfoTable* line_info, Address instruction_start) { |
| 534 CodeEntry* code_entry = |
| 535 new CodeEntry(tag, name, name_prefix, resource_name, line_number, |
| 536 column_number, line_info, instruction_start); |
| 537 code_entries_.Add(code_entry); |
| 538 return code_entry; |
| 539 } |
| 540 |
| 541 |
| 542 const char* const ProfileGenerator::kProgramEntryName = |
| 543 "(program)"; |
| 544 const char* const ProfileGenerator::kIdleEntryName = |
| 545 "(idle)"; |
| 546 const char* const ProfileGenerator::kGarbageCollectorEntryName = |
| 547 "(garbage collector)"; |
| 548 const char* const ProfileGenerator::kUnresolvedFunctionName = |
| 549 "(unresolved function)"; |
| 550 |
559 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 551 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |
560 : profiles_(profiles) {} | 552 : profiles_(profiles), |
| 553 program_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG, |
| 554 kProgramEntryName)), |
| 555 idle_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG, |
| 556 kIdleEntryName)), |
| 557 gc_entry_(profiles->NewCodeEntry(CodeEventListener::BUILTIN_TAG, |
| 558 kGarbageCollectorEntryName)), |
| 559 unresolved_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG, |
| 560 kUnresolvedFunctionName)) {} |
561 | 561 |
562 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 562 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
563 std::vector<CodeEntry*> entries; | 563 std::vector<CodeEntry*> entries; |
564 // Conservatively reserve space for stack frames + pc + function + vm-state. | 564 // Conservatively reserve space for stack frames + pc + function + vm-state. |
565 // There could in fact be more of them because of inlined entries. | 565 // There could in fact be more of them because of inlined entries. |
566 entries.reserve(sample.frames_count + 3); | 566 entries.reserve(sample.frames_count + 3); |
567 | 567 |
568 // The ProfileNode knows nothing about all versions of generated code for | 568 // The ProfileNode knows nothing about all versions of generated code for |
569 // the same JS function. The line number information associated with | 569 // the same JS function. The line number information associated with |
570 // the latest version of generated code is used to find a source line number | 570 // the latest version of generated code is used to find a source line number |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 | 603 |
604 if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || | 604 if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || |
605 pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { | 605 pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { |
606 // When current function is either the Function.prototype.apply or the | 606 // When current function is either the Function.prototype.apply or the |
607 // Function.prototype.call builtin the top frame is either frame of | 607 // Function.prototype.call builtin the top frame is either frame of |
608 // the calling JS function or internal frame. | 608 // the calling JS function or internal frame. |
609 // In the latter case we know the caller for sure but in the | 609 // In the latter case we know the caller for sure but in the |
610 // former case we don't so we simply replace the frame with | 610 // former case we don't so we simply replace the frame with |
611 // 'unresolved' entry. | 611 // 'unresolved' entry. |
612 if (!sample.has_external_callback) { | 612 if (!sample.has_external_callback) { |
613 entries.push_back(CodeEntry::unresolved_entry()); | 613 entries.push_back(unresolved_entry_); |
614 } | 614 } |
615 } | 615 } |
616 } | 616 } |
617 } | 617 } |
618 | 618 |
619 for (const Address *stack_pos = sample.stack, | 619 for (const Address *stack_pos = sample.stack, |
620 *stack_end = stack_pos + sample.frames_count; | 620 *stack_end = stack_pos + sample.frames_count; |
621 stack_pos != stack_end; ++stack_pos) { | 621 stack_pos != stack_end; ++stack_pos) { |
622 CodeEntry* entry = code_map_.FindEntry(*stack_pos); | 622 CodeEntry* entry = code_map_.FindEntry(*stack_pos); |
623 | 623 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 } | 660 } |
661 | 661 |
662 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, | 662 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, |
663 sample.update_stats); | 663 sample.update_stats); |
664 } | 664 } |
665 | 665 |
666 | 666 |
667 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { | 667 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { |
668 switch (tag) { | 668 switch (tag) { |
669 case GC: | 669 case GC: |
670 return CodeEntry::gc_entry(); | 670 return gc_entry_; |
671 case JS: | 671 case JS: |
672 case COMPILER: | 672 case COMPILER: |
673 // DOM events handlers are reported as OTHER / EXTERNAL entries. | 673 // DOM events handlers are reported as OTHER / EXTERNAL entries. |
674 // To avoid confusing people, let's put all these entries into | 674 // To avoid confusing people, let's put all these entries into |
675 // one bucket. | 675 // one bucket. |
676 case OTHER: | 676 case OTHER: |
677 case EXTERNAL: | 677 case EXTERNAL: |
678 return CodeEntry::program_entry(); | 678 return program_entry_; |
679 case IDLE: | 679 case IDLE: |
680 return CodeEntry::idle_entry(); | 680 return idle_entry_; |
681 default: return NULL; | 681 default: return NULL; |
682 } | 682 } |
683 } | 683 } |
684 | 684 |
685 } // namespace internal | 685 } // namespace internal |
686 } // namespace v8 | 686 } // namespace v8 |
OLD | NEW |