LCOV - code coverage report
Current view: top level - src/profiler - profiler-listener.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 142 147 96.6 %
Date: 2017-04-26 Functions: 20 21 95.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/source-position-table.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16         288 : ProfilerListener::ProfilerListener(Isolate* isolate)
      17         576 :     : function_and_resource_names_(isolate->heap()) {}
      18             : 
      19        1042 : ProfilerListener::~ProfilerListener() {
      20      181603 :   for (auto code_entry : code_entries_) {
      21      181067 :     delete code_entry;
      22             :   }
      23         506 : }
      24             : 
      25        6950 : void ProfilerListener::CallbackEvent(Name* name, Address entry_point) {
      26             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      27             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      28        6950 :   rec->start = entry_point;
      29       13900 :   rec->entry = NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name));
      30        6950 :   rec->size = 1;
      31             :   DispatchCodeEvent(evt_rec);
      32        6950 : }
      33             : 
      34       29485 : 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       29485 :   rec->start = code->address();
      39             :   rec->entry = NewCodeEntry(
      40             :       tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
      41             :       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
      42       58970 :       CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
      43       29485 :   RecordInliningInfo(rec->entry, code);
      44       29485 :   rec->size = code->ExecutableSize();
      45             :   DispatchCodeEvent(evt_rec);
      46       29485 : }
      47             : 
      48           6 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      49             :                                        AbstractCode* code, Name* name) {
      50             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      51             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      52           6 :   rec->start = code->address();
      53             :   rec->entry = NewCodeEntry(
      54             :       tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
      55             :       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
      56          12 :       CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
      57           6 :   RecordInliningInfo(rec->entry, code);
      58           6 :   rec->size = code->ExecutableSize();
      59             :   DispatchCodeEvent(evt_rec);
      60           6 : }
      61             : 
      62      129802 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      63             :                                        AbstractCode* code,
      64             :                                        SharedFunctionInfo* shared,
      65             :                                        Name* script_name) {
      66             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      67             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      68      129802 :   rec->start = code->address();
      69             :   rec->entry = NewCodeEntry(
      70      129802 :       tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix,
      71             :       GetName(InferScriptName(script_name, shared)),
      72             :       CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
      73      389406 :       NULL, code->instruction_start());
      74      129802 :   RecordInliningInfo(rec->entry, code);
      75      129802 :   rec->entry->FillFunctionInfo(shared);
      76      129802 :   rec->size = code->ExecutableSize();
      77             :   DispatchCodeEvent(evt_rec);
      78      129802 : }
      79             : 
      80        3476 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
      81             :                                        AbstractCode* abstract_code,
      82             :                                        SharedFunctionInfo* shared,
      83             :                                        Name* script_name, int line,
      84             :                                        int column) {
      85             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
      86             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
      87        3476 :   rec->start = abstract_code->address();
      88             :   JITLineInfoTable* line_table = NULL;
      89        3476 :   if (shared->script()->IsScript()) {
      90             :     Script* script = Script::cast(shared->script());
      91        3476 :     line_table = new JITLineInfoTable();
      92             :     int offset = abstract_code->IsCode() ? Code::kHeaderSize
      93        3476 :                                          : BytecodeArray::kHeaderSize;
      94       62268 :     for (SourcePositionTableIterator it(abstract_code->source_position_table());
      95       55316 :          !it.done(); it.Advance()) {
      96             :       // TODO(alph,tebbi) Skipping inlined positions for now, because they might
      97             :       // refer to a different script.
      98      110632 :       if (it.source_position().InliningId() != SourcePosition::kNotInlined)
      99             :         continue;
     100             :       int position = it.source_position().ScriptOffset();
     101       55284 :       int line_number = script->GetLineNumber(position) + 1;
     102       55284 :       int pc_offset = it.code_offset() + offset;
     103       55284 :       line_table->SetPosition(pc_offset, line_number);
     104             :     }
     105             :   }
     106             :   rec->entry = NewCodeEntry(
     107        3476 :       tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix,
     108             :       GetName(InferScriptName(script_name, shared)), line, column, line_table,
     109       10428 :       abstract_code->instruction_start());
     110        3476 :   RecordInliningInfo(rec->entry, abstract_code);
     111        3476 :   RecordDeoptInlinedFrames(rec->entry, abstract_code);
     112        3476 :   rec->entry->FillFunctionInfo(shared);
     113        3476 :   rec->size = abstract_code->ExecutableSize();
     114             :   DispatchCodeEvent(evt_rec);
     115        3476 : }
     116             : 
     117          24 : void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
     118             :                                        AbstractCode* code, int args_count) {
     119             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     120             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     121          24 :   rec->start = code->address();
     122             :   rec->entry = NewCodeEntry(
     123             :       tag, GetName(args_count), "args_count: ", CodeEntry::kEmptyResourceName,
     124             :       CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
     125          48 :       NULL, code->instruction_start());
     126          24 :   RecordInliningInfo(rec->entry, code);
     127          24 :   rec->size = code->ExecutableSize();
     128             :   DispatchCodeEvent(evt_rec);
     129          24 : }
     130             : 
     131           6 : void ProfilerListener::CodeMoveEvent(AbstractCode* from, Address to) {
     132             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
     133             :   CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
     134           6 :   rec->from = from->address();
     135           6 :   rec->to = to;
     136             :   DispatchCodeEvent(evt_rec);
     137           6 : }
     138             : 
     139          22 : void ProfilerListener::CodeDisableOptEvent(AbstractCode* code,
     140             :                                            SharedFunctionInfo* shared) {
     141             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
     142             :   CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
     143          22 :   rec->start = code->address();
     144          22 :   rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason());
     145             :   DispatchCodeEvent(evt_rec);
     146          22 : }
     147             : 
     148          41 : void ProfilerListener::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
     149             :                                       int fp_to_sp_delta) {
     150             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
     151             :   CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
     152          41 :   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
     153          41 :   rec->start = code->address();
     154          41 :   rec->deopt_reason = DeoptimizeReasonToString(info.deopt_reason);
     155          41 :   rec->deopt_id = info.deopt_id;
     156          41 :   rec->pc = reinterpret_cast<void*>(pc);
     157          41 :   rec->fp_to_sp_delta = fp_to_sp_delta;
     158             :   DispatchCodeEvent(evt_rec);
     159          41 : }
     160             : 
     161       17442 : void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) {
     162             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     163             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     164       17442 :   rec->start = entry_point;
     165             :   rec->entry =
     166       34884 :       NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "get ");
     167       17442 :   rec->size = 1;
     168             :   DispatchCodeEvent(evt_rec);
     169       17442 : }
     170             : 
     171           0 : void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code,
     172             :                                              String* source) {
     173             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     174             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     175           0 :   rec->start = code->address();
     176             :   rec->entry = NewCodeEntry(
     177             :       CodeEventListener::REG_EXP_TAG, GetName(source), "RegExp: ",
     178             :       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
     179           0 :       CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
     180           0 :   rec->size = code->ExecutableSize();
     181             :   DispatchCodeEvent(evt_rec);
     182           0 : }
     183             : 
     184       17442 : void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) {
     185             :   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
     186             :   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     187       17442 :   rec->start = entry_point;
     188             :   rec->entry =
     189       34884 :       NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "set ");
     190       17442 :   rec->size = 1;
     191             :   DispatchCodeEvent(evt_rec);
     192       17442 : }
     193             : 
     194      133278 : Name* ProfilerListener::InferScriptName(Name* name, SharedFunctionInfo* info) {
     195      266556 :   if (name->IsString() && String::cast(name)->length()) return name;
     196      132203 :   if (!info->script()->IsScript()) return name;
     197             :   Object* source_url = Script::cast(info->script())->source_url();
     198        2652 :   return source_url->IsName() ? Name::cast(source_url) : name;
     199             : }
     200             : 
     201      163059 : void ProfilerListener::RecordInliningInfo(CodeEntry* entry,
     202             :                                           AbstractCode* abstract_code) {
     203      162793 :   if (!abstract_code->IsCode()) return;
     204             :   Code* code = abstract_code->GetCode();
     205      160902 :   if (code->kind() != Code::OPTIMIZED_FUNCTION) return;
     206             :   DeoptimizationInputData* deopt_input_data =
     207             :       DeoptimizationInputData::cast(code->deoptimization_data());
     208             :   int deopt_count = deopt_input_data->DeoptCount();
     209       10359 :   for (int i = 0; i < deopt_count; i++) {
     210        9692 :     int pc_offset = deopt_input_data->Pc(i)->value();
     211       12947 :     if (pc_offset == -1) continue;
     212        6437 :     int translation_index = deopt_input_data->TranslationIndex(i)->value();
     213             :     TranslationIterator it(deopt_input_data->TranslationByteArray(),
     214             :                            translation_index);
     215        6437 :     Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
     216             :     DCHECK_EQ(Translation::BEGIN, opcode);
     217        6437 :     it.Skip(Translation::NumberOfOperandsFor(opcode));
     218             :     int depth = 0;
     219             :     std::vector<CodeEntry*> inline_stack;
     220      264868 :     while (it.HasNext() &&
     221             :            Translation::BEGIN !=
     222       87920 :                (opcode = static_cast<Translation::Opcode>(it.Next()))) {
     223       82037 :       if (opcode != Translation::JS_FRAME &&
     224             :           opcode != Translation::INTERPRETED_FRAME) {
     225       75467 :         it.Skip(Translation::NumberOfOperandsFor(opcode));
     226       81904 :         continue;
     227             :       }
     228        6570 :       it.Next();  // Skip ast_id
     229        6570 :       int shared_info_id = it.Next();
     230        6570 :       it.Next();  // Skip height
     231             :       SharedFunctionInfo* shared_info = SharedFunctionInfo::cast(
     232             :           deopt_input_data->LiteralArray()->get(shared_info_id));
     233        6570 :       if (!depth++) continue;  // Skip the current function itself.
     234             :       CodeEntry* inline_entry = new CodeEntry(
     235         133 :           entry->tag(), GetFunctionName(shared_info->DebugName()),
     236             :           CodeEntry::kEmptyNamePrefix, entry->resource_name(),
     237             :           CpuProfileNode::kNoLineNumberInfo,
     238         266 :           CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
     239         133 :       inline_entry->FillFunctionInfo(shared_info);
     240         133 :       inline_stack.push_back(inline_entry);
     241             :     }
     242        6437 :     if (!inline_stack.empty()) {
     243         220 :       entry->AddInlineStack(pc_offset, std::move(inline_stack));
     244             :     }
     245             :   }
     246             : }
     247             : 
     248        3476 : void ProfilerListener::RecordDeoptInlinedFrames(CodeEntry* entry,
     249             :                                                 AbstractCode* abstract_code) {
     250        6295 :   if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return;
     251             :   Handle<Code> code(abstract_code->GetCode());
     252             : 
     253         657 :   SourcePosition last_position = SourcePosition::Unknown();
     254             :   int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
     255             :              RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) |
     256             :              RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID);
     257        1289 :   for (RelocIterator it(*code, mask); !it.done(); it.next()) {
     258        1264 :     RelocInfo* info = it.rinfo();
     259         632 :     if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) {
     260         316 :       int script_offset = static_cast<int>(info->data());
     261         316 :       it.next();
     262             :       DCHECK(it.rinfo()->rmode() == RelocInfo::DEOPT_INLINING_ID);
     263         316 :       int inlining_id = static_cast<int>(it.rinfo()->data());
     264         316 :       last_position = SourcePosition(script_offset, inlining_id);
     265         316 :       continue;
     266             :     }
     267         316 :     if (info->rmode() == RelocInfo::DEOPT_ID) {
     268         316 :       int deopt_id = static_cast<int>(info->data());
     269             :       DCHECK(last_position.IsKnown());
     270             :       std::vector<CpuProfileDeoptFrame> inlined_frames;
     271        1312 :       for (SourcePositionInfo& pos_info : last_position.InliningStack(code)) {
     272             :         DCHECK(pos_info.position.ScriptOffset() != kNoSourcePosition);
     273         364 :         if (!pos_info.function->script()->IsScript()) continue;
     274             :         int script_id = Script::cast(pos_info.function->script())->id();
     275         364 :         size_t offset = static_cast<size_t>(pos_info.position.ScriptOffset());
     276         728 :         inlined_frames.push_back(CpuProfileDeoptFrame({script_id, offset}));
     277             :       }
     278         632 :       if (!inlined_frames.empty() &&
     279         316 :           !entry->HasDeoptInlinedFramesFor(deopt_id)) {
     280         520 :         entry->AddDeoptInlinedFrames(deopt_id, std::move(inlined_frames));
     281             :       }
     282             :     }
     283             :   }
     284             : }
     285             : 
     286      204627 : CodeEntry* ProfilerListener::NewCodeEntry(
     287             :     CodeEventListener::LogEventsAndTags tag, const char* name,
     288             :     const char* name_prefix, const char* resource_name, int line_number,
     289             :     int column_number, JITLineInfoTable* line_info, Address instruction_start) {
     290             :   CodeEntry* code_entry =
     291             :       new CodeEntry(tag, name, name_prefix, resource_name, line_number,
     292      409254 :                     column_number, line_info, instruction_start);
     293      204627 :   code_entries_.push_back(code_entry);
     294      204627 :   return code_entry;
     295             : }
     296             : 
     297         324 : void ProfilerListener::AddObserver(CodeEventObserver* observer) {
     298         324 :   base::LockGuard<base::Mutex> guard(&mutex_);
     299         324 :   if (std::find(observers_.begin(), observers_.end(), observer) !=
     300             :       observers_.end())
     301         324 :     return;
     302         324 :   observers_.push_back(observer);
     303             : }
     304             : 
     305         324 : void ProfilerListener::RemoveObserver(CodeEventObserver* observer) {
     306         324 :   base::LockGuard<base::Mutex> guard(&mutex_);
     307             :   auto it = std::find(observers_.begin(), observers_.end(), observer);
     308         648 :   if (it == observers_.end()) return;
     309         324 :   observers_.erase(it);
     310             : }
     311             : 
     312             : }  // namespace internal
     313             : }  // namespace v8

Generated by: LCOV version 1.10