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/base/adapters.h" | 7 #include "src/base/adapters.h" |
8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
10 #include "src/global-handles.h" | 10 #include "src/global-handles.h" |
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
641 // As starting / stopping profiles is rare relatively to this | 641 // As starting / stopping profiles is rare relatively to this |
642 // method, we don't bother minimizing the duration of lock holding, | 642 // method, we don't bother minimizing the duration of lock holding, |
643 // e.g. copying contents of the list to a local vector. | 643 // e.g. copying contents of the list to a local vector. |
644 current_profiles_semaphore_.Wait(); | 644 current_profiles_semaphore_.Wait(); |
645 for (int i = 0; i < current_profiles_.length(); ++i) { | 645 for (int i = 0; i < current_profiles_.length(); ++i) { |
646 current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); | 646 current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); |
647 } | 647 } |
648 current_profiles_semaphore_.Signal(); | 648 current_profiles_semaphore_.Signal(); |
649 } | 649 } |
650 | 650 |
651 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 651 ProfileGenerator::ProfileGenerator(Isolate* isolate, |
652 : profiles_(profiles) {} | 652 CpuProfilesCollection* profiles) |
653 : isolate_(isolate), profiles_(profiles) {} | |
653 | 654 |
654 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 655 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
655 std::vector<CodeEntry*> entries; | 656 std::vector<CodeEntry*> entries; |
656 // Conservatively reserve space for stack frames + pc + function + vm-state. | 657 // Conservatively reserve space for stack frames + pc + function + vm-state. |
657 // There could in fact be more of them because of inlined entries. | 658 // There could in fact be more of them because of inlined entries. |
658 entries.reserve(sample.frames_count + 3); | 659 entries.reserve(sample.frames_count + 3); |
659 | 660 |
660 // The ProfileNode knows nothing about all versions of generated code for | 661 // The ProfileNode knows nothing about all versions of generated code for |
661 // the same JS function. The line number information associated with | 662 // the same JS function. The line number information associated with |
662 // the latest version of generated code is used to find a source line number | 663 // the latest version of generated code is used to find a source line number |
663 // for a JS function. Then, the detected source line is passed to | 664 // for a JS function. Then, the detected source line is passed to |
664 // ProfileNode to increase the tick count for this source line. | 665 // ProfileNode to increase the tick count for this source line. |
665 int src_line = v8::CpuProfileNode::kNoLineNumberInfo; | 666 int src_line = v8::CpuProfileNode::kNoLineNumberInfo; |
666 bool src_line_not_found = true; | 667 bool src_line_not_found = true; |
667 | 668 |
668 if (sample.pc != nullptr) { | 669 if (sample.pc != nullptr) { |
669 if (sample.has_external_callback && sample.state == EXTERNAL) { | 670 if (sample.has_external_callback && sample.state == EXTERNAL) { |
670 // Don't use PC when in external callback code, as it can point | 671 // Don't use PC when in external callback code, as it can point |
671 // inside callback's code, and we will erroneously report | 672 // inside callback's code, and we will erroneously report |
672 // that a callback calls itself. | 673 // that a callback calls itself. |
673 entries.push_back(code_map_.FindEntry( | 674 entries.push_back(FindEntry(sample.external_callback_entry)); |
674 reinterpret_cast<Address>(sample.external_callback_entry))); | |
675 } else { | 675 } else { |
676 CodeEntry* pc_entry = | 676 CodeEntry* pc_entry = FindEntry(sample.pc); |
677 code_map_.FindEntry(reinterpret_cast<Address>(sample.pc)); | |
678 // If there is no pc_entry we're likely in native code. | 677 // If there is no pc_entry we're likely in native code. |
679 // Find out, if top of stack was pointing inside a JS function | 678 // Find out, if top of stack was pointing inside a JS function |
680 // meaning that we have encountered a frameless invocation. | 679 // meaning that we have encountered a frameless invocation. |
681 if (!pc_entry && !sample.has_external_callback) { | 680 if (!pc_entry && !sample.has_external_callback) { |
682 pc_entry = code_map_.FindEntry(reinterpret_cast<Address>(sample.tos)); | 681 pc_entry = FindEntry(sample.tos); |
683 } | 682 } |
684 // If pc is in the function code before it set up stack frame or after the | 683 // If pc is in the function code before it set up stack frame or after the |
685 // frame was destroyed SafeStackFrameIterator incorrectly thinks that | 684 // frame was destroyed SafeStackFrameIterator incorrectly thinks that |
686 // ebp contains return address of the current function and skips caller's | 685 // ebp contains return address of the current function and skips caller's |
687 // frame. Check for this case and just skip such samples. | 686 // frame. Check for this case and just skip such samples. |
688 if (pc_entry) { | 687 if (pc_entry) { |
689 int pc_offset = static_cast<int>(reinterpret_cast<Address>(sample.pc) - | 688 int pc_offset = static_cast<int>(reinterpret_cast<Address>(sample.pc) - |
690 pc_entry->instruction_start()); | 689 pc_entry->instruction_start()); |
691 src_line = pc_entry->GetSourceLine(pc_offset); | 690 src_line = pc_entry->GetSourceLine(pc_offset); |
692 if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) { | 691 if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) { |
(...skipping 12 matching lines...) Expand all Loading... | |
705 // 'unresolved' entry. | 704 // 'unresolved' entry. |
706 if (!sample.has_external_callback) { | 705 if (!sample.has_external_callback) { |
707 entries.push_back(CodeEntry::unresolved_entry()); | 706 entries.push_back(CodeEntry::unresolved_entry()); |
708 } | 707 } |
709 } | 708 } |
710 } | 709 } |
711 } | 710 } |
712 | 711 |
713 for (unsigned i = 0; i < sample.frames_count; ++i) { | 712 for (unsigned i = 0; i < sample.frames_count; ++i) { |
714 Address stack_pos = reinterpret_cast<Address>(sample.stack[i]); | 713 Address stack_pos = reinterpret_cast<Address>(sample.stack[i]); |
715 CodeEntry* entry = code_map_.FindEntry(stack_pos); | 714 CodeEntry* entry = FindEntry(stack_pos); |
716 | |
717 if (entry) { | 715 if (entry) { |
718 // Find out if the entry has an inlining stack associated. | 716 // Find out if the entry has an inlining stack associated. |
719 int pc_offset = | 717 int pc_offset = |
720 static_cast<int>(stack_pos - entry->instruction_start()); | 718 static_cast<int>(stack_pos - entry->instruction_start()); |
721 const std::vector<CodeEntry*>* inline_stack = | 719 const std::vector<CodeEntry*>* inline_stack = |
722 entry->GetInlineStack(pc_offset); | 720 entry->GetInlineStack(pc_offset); |
723 if (inline_stack) { | 721 if (inline_stack) { |
724 entries.insert(entries.end(), inline_stack->rbegin(), | 722 entries.insert(entries.end(), inline_stack->rbegin(), |
725 inline_stack->rend()); | 723 inline_stack->rend()); |
726 } | 724 } |
(...skipping 22 matching lines...) Expand all Loading... | |
749 // If no frames were symbolized, put the VM state entry in. | 747 // If no frames were symbolized, put the VM state entry in. |
750 if (no_symbolized_entries) { | 748 if (no_symbolized_entries) { |
751 entries.push_back(EntryForVMState(sample.state)); | 749 entries.push_back(EntryForVMState(sample.state)); |
752 } | 750 } |
753 } | 751 } |
754 | 752 |
755 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, | 753 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, |
756 sample.update_stats); | 754 sample.update_stats); |
757 } | 755 } |
758 | 756 |
757 CodeEntry* ProfileGenerator::FindEntry(void* address) { | |
758 CodeEntry* entry = code_map_.FindEntry(reinterpret_cast<Address>(address)); | |
759 if (!entry) { | |
760 RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats(); | |
761 void* start = reinterpret_cast<void*>(rcs); | |
762 void* end = reinterpret_cast<void*>(rcs + 1); | |
763 if (start <= address && address < end) { | |
764 RuntimeCallCounter* counter = | |
765 reinterpret_cast<RuntimeCallCounter*>(address); | |
766 entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name, | |
fmeawad
2016/10/28 19:51:32
I don't think they should be considered as CodeEnt
alph
2016/10/28 20:15:34
I don't think we need an extra class here. CodeEnt
| |
767 CodeEntry::kEmptyNamePrefix, "native V8Runtime"); | |
768 code_map_.AddCode(reinterpret_cast<Address>(address), entry, 1); | |
769 } | |
770 } | |
771 return entry; | |
772 } | |
759 | 773 |
760 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { | 774 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { |
761 switch (tag) { | 775 switch (tag) { |
762 case GC: | 776 case GC: |
763 return CodeEntry::gc_entry(); | 777 return CodeEntry::gc_entry(); |
764 case JS: | 778 case JS: |
765 case COMPILER: | 779 case COMPILER: |
766 // DOM events handlers are reported as OTHER / EXTERNAL entries. | 780 // DOM events handlers are reported as OTHER / EXTERNAL entries. |
767 // To avoid confusing people, let's put all these entries into | 781 // To avoid confusing people, let's put all these entries into |
768 // one bucket. | 782 // one bucket. |
769 case OTHER: | 783 case OTHER: |
770 case EXTERNAL: | 784 case EXTERNAL: |
771 return CodeEntry::program_entry(); | 785 return CodeEntry::program_entry(); |
772 case IDLE: | 786 case IDLE: |
773 return CodeEntry::idle_entry(); | 787 return CodeEntry::idle_entry(); |
774 default: return NULL; | 788 default: return NULL; |
775 } | 789 } |
776 } | 790 } |
777 | 791 |
778 } // namespace internal | 792 } // namespace internal |
779 } // namespace v8 | 793 } // namespace v8 |
OLD | NEW |