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

Side by Side Diff: src/profiler/profile-generator.cc

Issue 2461003002: [profiler] Emit runtime call stats into sampling profile (Closed)
Patch Set: Created 4 years, 1 month 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 | « src/profiler/profile-generator.h ('k') | src/profiler/tick-sample.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/profiler/profile-generator.h ('k') | src/profiler/tick-sample.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698