LCOV - code coverage report
Current view: top level - src/profiler - profiler-listener.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 118 135 87.4 %
Date: 2019-04-18 Functions: 14 17 82.4 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/profiler/profiler-listener.h"
       6             : 
       7             : #include "src/deoptimizer.h"
       8             : #include "src/handles-inl.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/objects/code-inl.h"
      11             : #include "src/objects/script-inl.h"
      12             : #include "src/objects/shared-function-info-inl.h"
      13             : #include "src/objects/string-inl.h"
      14             : #include "src/profiler/cpu-profiler.h"
      15             : #include "src/profiler/profile-generator-inl.h"
      16             : #include "src/reloc-info.h"
      17             : #include "src/source-position-table.h"
      18             : #include "src/wasm/wasm-code-manager.h"
      19             : 
      20             : namespace v8 {
      21             : namespace internal {
      22             : 
      23         787 : ProfilerListener::ProfilerListener(Isolate* isolate,
      24             :                                    CodeEventObserver* observer)
      25         787 :     : isolate_(isolate), observer_(observer) {}
      26             : 
      27             : ProfilerListener::~ProfilerListener() = default;
      28             : 
      29       15660 : void ProfilerListener::CallbackEvent(Name name, Address entry_point) {
      30             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      31             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      32       15660 :   rec->instruction_start = entry_point;
      33       31320 :   rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name));
      34       15660 :   rec->instruction_size = 1;
      35             :   DispatchCodeEvent(evt_rec);
      36       15660 : }
      37             : 
      38       26233 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      39             :                                        AbstractCode code, const char* name) {
      40             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      41             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      42       26233 :   rec->instruction_start = code->InstructionStart();
      43             :   rec->entry = new CodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
      44             :                              CpuProfileNode::kNoLineNumberInfo,
      45             :                              CpuProfileNode::kNoColumnNumberInfo, nullptr,
      46       52466 :                              code->InstructionStart());
      47       26233 :   rec->instruction_size = code->InstructionSize();
      48             :   DispatchCodeEvent(evt_rec);
      49       26233 : }
      50             : 
      51           9 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      52             :                                        AbstractCode code, Name name) {
      53             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      54             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      55           9 :   rec->instruction_start = code->InstructionStart();
      56             :   rec->entry = new CodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
      57             :                              CpuProfileNode::kNoLineNumberInfo,
      58             :                              CpuProfileNode::kNoColumnNumberInfo, nullptr,
      59          18 :                              code->InstructionStart());
      60           9 :   rec->instruction_size = code->InstructionSize();
      61             :   DispatchCodeEvent(evt_rec);
      62           9 : }
      63             : 
      64           0 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      65             :                                        AbstractCode code,
      66             :                                        SharedFunctionInfo shared,
      67             :                                        Name script_name) {
      68             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      69             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      70           0 :   rec->instruction_start = code->InstructionStart();
      71           0 :   rec->entry = new CodeEntry(tag, GetName(shared->DebugName()),
      72           0 :                              GetName(InferScriptName(script_name, shared)),
      73             :                              CpuProfileNode::kNoLineNumberInfo,
      74             :                              CpuProfileNode::kNoColumnNumberInfo, nullptr,
      75           0 :                              code->InstructionStart());
      76             :   DCHECK(!code->IsCode());
      77           0 :   rec->entry->FillFunctionInfo(shared);
      78           0 :   rec->instruction_size = code->InstructionSize();
      79             :   DispatchCodeEvent(evt_rec);
      80           0 : }
      81             : 
      82             : namespace {
      83             : 
      84         152 : CodeEntry* GetOrInsertCachedEntry(
      85             :     std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
      86             :                        CodeEntry::Equals>* entries,
      87             :     std::unique_ptr<CodeEntry> search_value) {
      88             :   auto it = entries->find(search_value);
      89         265 :   if (it != entries->end()) return it->get();
      90             :   CodeEntry* ret = search_value.get();
      91             :   entries->insert(std::move(search_value));
      92          39 :   return ret;
      93             : }
      94             : 
      95             : }  // namespace
      96             : 
      97      603822 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      98             :                                        AbstractCode abstract_code,
      99             :                                        SharedFunctionInfo shared,
     100             :                                        Name script_name, int line, int column) {
     101             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     102             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     103      603822 :   rec->instruction_start = abstract_code->InstructionStart();
     104             :   std::unique_ptr<SourcePositionTable> line_table;
     105             :   std::unordered_map<int, std::vector<CodeEntryAndLineNumber>> inline_stacks;
     106             :   std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
     107             :                      CodeEntry::Equals>
     108             :       cached_inline_entries;
     109             :   bool is_shared_cross_origin = false;
     110     1207644 :   if (shared->script()->IsScript()) {
     111      603822 :     Script script = Script::cast(shared->script());
     112      603822 :     line_table.reset(new SourcePositionTable());
     113      603822 :     HandleScope scope(isolate_);
     114             : 
     115             :     is_shared_cross_origin = script.origin_options().IsSharedCrossOrigin();
     116             : 
     117             :     // Add each position to the source position table and store inlining stacks
     118             :     // for inline positions. We store almost the same information in the
     119             :     // profiler as is stored on the code object, except that we transform source
     120             :     // positions to line numbers here, because we only care about attributing
     121             :     // ticks to a given line.
     122     3317570 :     for (SourcePositionTableIterator it(abstract_code->source_position_table());
     123     2713748 :          !it.done(); it.Advance()) {
     124             :       int position = it.source_position().ScriptOffset();
     125     2713748 :       int line_number = script->GetLineNumber(position) + 1;
     126     2713748 :       int inlining_id = it.source_position().InliningId();
     127             : 
     128             :       // TODO(953309): Fix this.
     129     2713748 :       if (line_number == 0) continue;
     130             : 
     131     2713748 :       line_table->SetPosition(it.code_offset(), line_number, inlining_id);
     132             : 
     133     2713748 :       if (inlining_id != SourcePosition::kNotInlined) {
     134             :         DCHECK(abstract_code->IsCode());
     135          54 :         Code code = abstract_code->GetCode();
     136             :         std::vector<SourcePositionInfo> stack =
     137         108 :             it.source_position().InliningStack(handle(code, isolate_));
     138             :         DCHECK(!stack.empty());
     139             : 
     140             :         std::vector<CodeEntryAndLineNumber> inline_stack;
     141         206 :         for (SourcePositionInfo& pos_info : stack) {
     142         152 :           if (pos_info.position.ScriptOffset() == kNoSourcePosition) continue;
     143         152 :           if (pos_info.script.is_null()) continue;
     144             : 
     145             :           int line_number =
     146         304 :               pos_info.script->GetLineNumber(pos_info.position.ScriptOffset()) +
     147         152 :               1;
     148             : 
     149             :           const char* resource_name =
     150             :               (pos_info.script->name()->IsName())
     151             :                   ? GetName(Name::cast(pos_info.script->name()))
     152         227 :                   : CodeEntry::kEmptyResourceName;
     153             : 
     154             :           bool inline_is_shared_cross_origin =
     155         152 :               pos_info.script->origin_options().IsSharedCrossOrigin();
     156             : 
     157             :           // We need the start line number and column number of the function for
     158             :           // kLeafNodeLineNumbers mode. Creating a SourcePositionInfo is a handy
     159             :           // way of getting both easily.
     160             :           SourcePositionInfo start_pos_info(
     161             :               SourcePosition(pos_info.shared->StartPosition()),
     162         304 :               pos_info.shared);
     163             : 
     164             :           std::unique_ptr<CodeEntry> inline_entry =
     165             :               base::make_unique<CodeEntry>(
     166         304 :                   tag, GetName(pos_info.shared->DebugName()), resource_name,
     167         304 :                   start_pos_info.line + 1, start_pos_info.column + 1, nullptr,
     168         912 :                   code->InstructionStart(), inline_is_shared_cross_origin);
     169         152 :           inline_entry->FillFunctionInfo(*pos_info.shared);
     170             : 
     171             :           // Create a canonical CodeEntry for each inlined frame and then re-use
     172             :           // them for subsequent inline stacks to avoid a lot of duplication.
     173         152 :           CodeEntry* cached_entry = GetOrInsertCachedEntry(
     174         152 :               &cached_inline_entries, std::move(inline_entry));
     175             : 
     176         304 :           inline_stack.push_back(
     177             :               CodeEntryAndLineNumber{cached_entry, line_number});
     178             :         }
     179             :         DCHECK(!inline_stack.empty());
     180             :         inline_stacks.emplace(inlining_id, std::move(inline_stack));
     181             :       }
     182             :     }
     183             :   }
     184             :   rec->entry =
     185     1207644 :       new CodeEntry(tag, GetName(shared->DebugName()),
     186      603822 :                     GetName(InferScriptName(script_name, shared)), line, column,
     187             :                     std::move(line_table), abstract_code->InstructionStart(),
     188     1207644 :                     is_shared_cross_origin);
     189      603822 :   if (!inline_stacks.empty()) {
     190          39 :     rec->entry->SetInlineStacks(std::move(cached_inline_entries),
     191          13 :                                 std::move(inline_stacks));
     192             :   }
     193             : 
     194      603822 :   rec->entry->FillFunctionInfo(shared);
     195      603822 :   rec->instruction_size = abstract_code->InstructionSize();
     196             :   DispatchCodeEvent(evt_rec);
     197      603822 : }
     198             : 
     199          11 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
     200             :                                        const wasm::WasmCode* code,
     201             :                                        wasm::WasmName name) {
     202             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     203             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     204          11 :   rec->instruction_start = code->instruction_start();
     205             :   rec->entry = new CodeEntry(
     206             :       tag, GetName(name.start()), CodeEntry::kWasmResourceNamePrefix,
     207             :       CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
     208          22 :       nullptr, code->instruction_start(), true);
     209          11 :   rec->instruction_size = code->instructions().length();
     210             :   DispatchCodeEvent(evt_rec);
     211          11 : }
     212             : 
     213           5 : void ProfilerListener::CodeMoveEvent(AbstractCode from, AbstractCode to) {
     214             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
     215             :   CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
     216           5 :   rec->from_instruction_start = from->InstructionStart();
     217           5 :   rec->to_instruction_start = to->InstructionStart();
     218             :   DispatchCodeEvent(evt_rec);
     219           5 : }
     220             : 
     221           0 : void ProfilerListener::CodeDisableOptEvent(AbstractCode code,
     222             :                                            SharedFunctionInfo shared) {
     223             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
     224             :   CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
     225           0 :   rec->instruction_start = code->InstructionStart();
     226           0 :   rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason());
     227             :   DispatchCodeEvent(evt_rec);
     228           0 : }
     229             : 
     230           6 : void ProfilerListener::CodeDeoptEvent(Code code, DeoptimizeKind kind,
     231             :                                       Address pc, int fp_to_sp_delta) {
     232             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
     233             :   CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
     234           6 :   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
     235           6 :   rec->instruction_start = code->InstructionStart();
     236           6 :   rec->deopt_reason = DeoptimizeReasonToString(info.deopt_reason);
     237           6 :   rec->deopt_id = info.deopt_id;
     238           6 :   rec->pc = pc;
     239           6 :   rec->fp_to_sp_delta = fp_to_sp_delta;
     240             : 
     241             :   // When a function is deoptimized, we store the deoptimized frame information
     242             :   // for the use of GetDeoptInfos().
     243           6 :   AttachDeoptInlinedFrames(code, rec);
     244             :   DispatchCodeEvent(evt_rec);
     245           6 : }
     246             : 
     247        9113 : void ProfilerListener::GetterCallbackEvent(Name name, Address entry_point) {
     248             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     249             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     250        9113 :   rec->instruction_start = entry_point;
     251             :   rec->entry =
     252       18226 :       new CodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName("get ", name));
     253        9113 :   rec->instruction_size = 1;
     254             :   DispatchCodeEvent(evt_rec);
     255        9113 : }
     256             : 
     257           0 : void ProfilerListener::RegExpCodeCreateEvent(AbstractCode code, String source) {
     258             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     259             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     260           0 :   rec->instruction_start = code->InstructionStart();
     261             :   rec->entry = new CodeEntry(
     262             :       CodeEventListener::REG_EXP_TAG, GetConsName("RegExp: ", source),
     263             :       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
     264           0 :       CpuProfileNode::kNoColumnNumberInfo, nullptr, code->InstructionStart());
     265           0 :   rec->instruction_size = code->InstructionSize();
     266             :   DispatchCodeEvent(evt_rec);
     267           0 : }
     268             : 
     269        9113 : void ProfilerListener::SetterCallbackEvent(Name name, Address entry_point) {
     270             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     271             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     272        9113 :   rec->instruction_start = entry_point;
     273             :   rec->entry =
     274       18226 :       new CodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName("set ", name));
     275        9113 :   rec->instruction_size = 1;
     276             :   DispatchCodeEvent(evt_rec);
     277        9113 : }
     278             : 
     279      603822 : Name ProfilerListener::InferScriptName(Name name, SharedFunctionInfo info) {
     280     1207644 :   if (name->IsString() && String::cast(name)->length()) return name;
     281     1206422 :   if (!info->script()->IsScript()) return name;
     282      603211 :   Object source_url = Script::cast(info->script())->source_url();
     283      603211 :   return source_url->IsName() ? Name::cast(source_url) : name;
     284             : }
     285             : 
     286           6 : void ProfilerListener::AttachDeoptInlinedFrames(Code code,
     287             :                                                 CodeDeoptEventRecord* rec) {
     288           6 :   int deopt_id = rec->deopt_id;
     289           6 :   SourcePosition last_position = SourcePosition::Unknown();
     290             :   int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
     291             :              RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) |
     292             :              RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID);
     293             : 
     294           6 :   rec->deopt_frames = nullptr;
     295           6 :   rec->deopt_frame_count = 0;
     296             : 
     297           9 :   for (RelocIterator it(code, mask); !it.done(); it.next()) {
     298             :     RelocInfo* info = it.rinfo();
     299           6 :     if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) {
     300           3 :       int script_offset = static_cast<int>(info->data());
     301           3 :       it.next();
     302             :       DCHECK(it.rinfo()->rmode() == RelocInfo::DEOPT_INLINING_ID);
     303           3 :       int inlining_id = static_cast<int>(it.rinfo()->data());
     304           3 :       last_position = SourcePosition(script_offset, inlining_id);
     305           3 :       continue;
     306             :     }
     307           3 :     if (info->rmode() == RelocInfo::DEOPT_ID) {
     308           3 :       if (deopt_id != static_cast<int>(info->data())) continue;
     309             :       DCHECK(last_position.IsKnown());
     310             : 
     311             :       // SourcePosition::InliningStack allocates a handle for the SFI of each
     312             :       // frame. These don't escape this function, but quickly add up. This
     313             :       // scope limits their lifetime.
     314           3 :       HandleScope scope(isolate_);
     315             :       std::vector<SourcePositionInfo> stack =
     316           6 :           last_position.InliningStack(handle(code, isolate_));
     317             :       CpuProfileDeoptFrame* deopt_frames =
     318           3 :           new CpuProfileDeoptFrame[stack.size()];
     319             : 
     320             :       int deopt_frame_count = 0;
     321          12 :       for (SourcePositionInfo& pos_info : stack) {
     322           9 :         if (pos_info.position.ScriptOffset() == kNoSourcePosition) continue;
     323           9 :         if (pos_info.script.is_null()) continue;
     324             :         int script_id = pos_info.script->id();
     325           9 :         size_t offset = static_cast<size_t>(pos_info.position.ScriptOffset());
     326           9 :         deopt_frames[deopt_frame_count++] = {script_id, offset};
     327             :       }
     328           3 :       rec->deopt_frames = deopt_frames;
     329           3 :       rec->deopt_frame_count = deopt_frame_count;
     330             :       break;
     331             :     }
     332             :   }
     333           6 : }
     334             : 
     335             : }  // namespace internal
     336      122036 : }  // namespace v8

Generated by: LCOV version 1.10