LCOV - code coverage report
Current view: top level - src/profiler - profiler-listener.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 82 142 57.7 %
Date: 2019-01-20 Functions: 12 19 63.2 %

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

Generated by: LCOV version 1.10