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

Generated by: LCOV version 1.10