LCOV - code coverage report
Current view: top level - src/profiler - cpu-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 201 218 92.2 %
Date: 2019-01-20 Functions: 41 45 91.1 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/profiler/cpu-profiler.h"
       6             : 
       7             : #include <unordered_map>
       8             : #include <utility>
       9             : 
      10             : #include "src/base/lazy-instance.h"
      11             : #include "src/base/platform/mutex.h"
      12             : #include "src/base/template-utils.h"
      13             : #include "src/debug/debug.h"
      14             : #include "src/deoptimizer.h"
      15             : #include "src/frames-inl.h"
      16             : #include "src/locked-queue-inl.h"
      17             : #include "src/log-inl.h"
      18             : #include "src/profiler/cpu-profiler-inl.h"
      19             : #include "src/vm-state-inl.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : 
      24             : static const int kProfilerStackSize = 64 * KB;
      25             : 
      26         773 : class CpuSampler : public sampler::Sampler {
      27             :  public:
      28             :   CpuSampler(Isolate* isolate, SamplingEventsProcessor* processor)
      29             :       : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
      30         778 :         processor_(processor) {}
      31             : 
      32       27002 :   void SampleStack(const v8::RegisterState& regs) override {
      33       27002 :     TickSample* sample = processor_->StartTickSample();
      34       54004 :     if (sample == nullptr) return;
      35       27002 :     Isolate* isolate = reinterpret_cast<Isolate*>(this->isolate());
      36       27002 :     sample->Init(isolate, regs, TickSample::kIncludeCEntryFrame, true);
      37       45829 :     if (is_counting_samples_ && !sample->timestamp.IsNull()) {
      38       18827 :       if (sample->state == JS) ++js_sample_count_;
      39       18827 :       if (sample->state == EXTERNAL) ++external_sample_count_;
      40             :     }
      41       27002 :     processor_->FinishTickSample();
      42             :   }
      43             : 
      44             :  private:
      45             :   SamplingEventsProcessor* processor_;
      46             : };
      47             : 
      48         778 : ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
      49             :                                                  ProfileGenerator* generator)
      50             :     : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
      51             :       generator_(generator),
      52             :       running_(1),
      53             :       last_code_event_id_(0),
      54             :       last_processed_code_event_id_(0),
      55        1556 :       isolate_(isolate) {}
      56             : 
      57         778 : SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
      58             :                                                  ProfileGenerator* generator,
      59             :                                                  base::TimeDelta period)
      60             :     : ProfilerEventsProcessor(isolate, generator),
      61             :       sampler_(new CpuSampler(isolate, this)),
      62        2334 :       period_(period) {
      63         778 :   sampler_->IncreaseProfilingDepth();
      64         778 : }
      65             : 
      66        2319 : SamplingEventsProcessor::~SamplingEventsProcessor() {
      67         773 :   sampler_->DecreaseProfilingDepth();
      68         773 :   sampler_->UnregisterIfRegistered();
      69        2319 : }
      70             : 
      71             : ProfilerEventsProcessor::~ProfilerEventsProcessor() = default;
      72             : 
      73     1787895 : void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
      74     1787895 :   event.generic.order = ++last_code_event_id_;
      75     1787895 :   events_buffer_.Enqueue(event);
      76     1787896 : }
      77             : 
      78           0 : void ProfilerEventsProcessor::AddDeoptStack(Address from, int fp_to_sp_delta) {
      79             :   TickSampleEventRecord record(last_code_event_id_);
      80             :   RegisterState regs;
      81           0 :   Address fp = isolate_->c_entry_fp(isolate_->thread_local_top());
      82           0 :   regs.sp = reinterpret_cast<void*>(fp - fp_to_sp_delta);
      83           0 :   regs.fp = reinterpret_cast<void*>(fp);
      84           0 :   regs.pc = reinterpret_cast<void*>(from);
      85             :   record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, false,
      86           0 :                      false);
      87           0 :   ticks_from_vm_buffer_.Enqueue(record);
      88           0 : }
      89             : 
      90         823 : void ProfilerEventsProcessor::AddCurrentStack(bool update_stats) {
      91             :   TickSampleEventRecord record(last_code_event_id_);
      92             :   RegisterState regs;
      93         823 :   StackFrameIterator it(isolate_);
      94         823 :   if (!it.done()) {
      95         146 :     StackFrame* frame = it.frame();
      96          73 :     regs.sp = reinterpret_cast<void*>(frame->sp());
      97          73 :     regs.fp = reinterpret_cast<void*>(frame->fp());
      98          73 :     regs.pc = reinterpret_cast<void*>(frame->pc());
      99             :   }
     100             :   record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, update_stats,
     101         823 :                      false);
     102         823 :   ticks_from_vm_buffer_.Enqueue(record);
     103         823 : }
     104             : 
     105          35 : void ProfilerEventsProcessor::AddSample(TickSample sample) {
     106             :   TickSampleEventRecord record(last_code_event_id_);
     107          35 :   record.sample = sample;
     108          35 :   ticks_from_vm_buffer_.Enqueue(record);
     109          35 : }
     110             : 
     111         783 : void ProfilerEventsProcessor::StopSynchronously() {
     112        2349 :   if (!base::Relaxed_AtomicExchange(&running_, 0)) return;
     113         778 :   Join();
     114             : }
     115             : 
     116             : 
     117     1788629 : bool ProfilerEventsProcessor::ProcessCodeEvent() {
     118             :   CodeEventsContainer record;
     119     1788629 :   if (events_buffer_.Dequeue(&record)) {
     120     1787875 :     switch (record.generic.type) {
     121             : #define PROFILER_TYPE_CASE(type, clss)                          \
     122             :       case CodeEventRecord::type:                               \
     123             :         record.clss##_.UpdateCodeMap(generator_->code_map());   \
     124             :         break;
     125             : 
     126     1787875 :       CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
     127             : 
     128             : #undef PROFILER_TYPE_CASE
     129             :       default: return true;  // Skip record.
     130             :     }
     131     1787849 :     last_processed_code_event_id_ = record.generic.order;
     132     1787849 :     return true;
     133             :   }
     134             :   return false;
     135             : }
     136             : 
     137      665223 : void ProfilerEventsProcessor::CodeEventHandler(
     138             :     const CodeEventsContainer& evt_rec) {
     139      665223 :   switch (evt_rec.generic.type) {
     140             :     case CodeEventRecord::CODE_CREATION:
     141             :     case CodeEventRecord::CODE_MOVE:
     142             :     case CodeEventRecord::CODE_DISABLE_OPT:
     143      665223 :       Enqueue(evt_rec);
     144      665223 :       break;
     145             :     case CodeEventRecord::CODE_DEOPT: {
     146             :       const CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
     147           0 :       Address pc = rec->pc;
     148           0 :       int fp_to_sp_delta = rec->fp_to_sp_delta;
     149           0 :       Enqueue(evt_rec);
     150           0 :       AddDeoptStack(pc, fp_to_sp_delta);
     151           0 :       break;
     152             :     }
     153             :     case CodeEventRecord::NONE:
     154             :     case CodeEventRecord::REPORT_BUILTIN:
     155           0 :       UNREACHABLE();
     156             :   }
     157      665223 : }
     158             : 
     159             : ProfilerEventsProcessor::SampleProcessingResult
     160     1844143 : SamplingEventsProcessor::ProcessOneSample() {
     161             :   TickSampleEventRecord record1;
     162     3632383 :   if (ticks_from_vm_buffer_.Peek(&record1) &&
     163     1788240 :       (record1.order == last_processed_code_event_id_)) {
     164             :     TickSampleEventRecord record;
     165         858 :     ticks_from_vm_buffer_.Dequeue(&record);
     166         858 :     generator_->RecordTickSample(record.sample);
     167             :     return OneSampleProcessed;
     168             :   }
     169             : 
     170     1843345 :   const TickSampleEventRecord* record = ticks_buffer_.Peek();
     171     1843368 :   if (record == nullptr) {
     172     1276898 :     if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue;
     173     1248035 :     return FoundSampleForNextCodeEvent;
     174             :   }
     175      566470 :   if (record->order != last_processed_code_event_id_) {
     176             :     return FoundSampleForNextCodeEvent;
     177             :   }
     178       26796 :   generator_->RecordTickSample(record->sample);
     179       26796 :   ticks_buffer_.Remove();
     180       26796 :   return OneSampleProcessed;
     181             : }
     182             : 
     183         778 : void SamplingEventsProcessor::Run() {
     184       60612 :   while (!!base::Relaxed_Load(&running_)) {
     185             :     base::TimeTicks nextSampleTime =
     186       58278 :         base::TimeTicks::HighResolutionNow() + period_;
     187             :     base::TimeTicks now;
     188             :     SampleProcessingResult result;
     189             :     // Keep processing existing events until we need to do next sample
     190             :     // or the ticks buffer is empty.
     191      525645 :     do {
     192      525645 :       result = ProcessOneSample();
     193      525660 :       if (result == FoundSampleForNextCodeEvent) {
     194             :         // All ticks of the current last_processed_code_event_id_ are
     195             :         // processed, proceed to the next code event.
     196      471089 :         ProcessCodeEvent();
     197             :       }
     198      525665 :       now = base::TimeTicks::HighResolutionNow();
     199      525645 :     } while (result != NoSamplesInQueue && now < nextSampleTime);
     200             : 
     201       29139 :     if (nextSampleTime > now) {
     202             : #if V8_OS_WIN
     203             :       if (nextSampleTime - now < base::TimeDelta::FromMilliseconds(100)) {
     204             :         // Do not use Sleep on Windows as it is very imprecise, with up to 16ms
     205             :         // jitter, which is unacceptable for short profile intervals.
     206             :         while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
     207             :         }
     208             :       } else  // NOLINT
     209             : #endif
     210             :       {
     211       27929 :         base::OS::Sleep(nextSampleTime - now);
     212             :       }
     213             :     }
     214             : 
     215             :     // Schedule next sample.
     216       29139 :     sampler_->DoSample();
     217             :   }
     218             : 
     219             :   // Process remaining tick events.
     220     1317567 :   do {
     221             :     SampleProcessingResult result;
     222     1318580 :     do {
     223     1318580 :       result = ProcessOneSample();
     224             :     } while (result == OneSampleProcessed);
     225     1317567 :   } while (ProcessCodeEvent());
     226         778 : }
     227             : 
     228          30 : void* SamplingEventsProcessor::operator new(size_t size) {
     229         778 :   return AlignedAlloc(size, alignof(SamplingEventsProcessor));
     230             : }
     231             : 
     232         773 : void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
     233             : 
     234         155 : int CpuProfiler::GetProfilesCount() {
     235             :   // The count of profiles doesn't depend on a security token.
     236         310 :   return static_cast<int>(profiles_->profiles()->size());
     237             : }
     238             : 
     239             : 
     240          35 : CpuProfile* CpuProfiler::GetProfile(int index) {
     241          70 :   return profiles_->profiles()->at(index).get();
     242             : }
     243             : 
     244             : 
     245          95 : void CpuProfiler::DeleteAllProfiles() {
     246          95 :   if (is_profiling_) StopProcessor();
     247          95 :   ResetProfiles();
     248          95 : }
     249             : 
     250             : 
     251         630 : void CpuProfiler::DeleteProfile(CpuProfile* profile) {
     252         630 :   profiles_->RemoveProfile(profile);
     253         630 :   if (profiles_->profiles()->empty() && !is_profiling_) {
     254             :     // If this was the last profile, clean up all accessory data as well.
     255         600 :     ResetProfiles();
     256             :   }
     257         630 : }
     258             : 
     259             : namespace {
     260             : 
     261         506 : class CpuProfilersManager {
     262             :  public:
     263         273 :   void AddProfiler(Isolate* isolate, CpuProfiler* profiler) {
     264         273 :     base::MutexGuard lock(&mutex_);
     265             :     profilers_.emplace(isolate, profiler);
     266         273 :   }
     267             : 
     268         273 :   void RemoveProfiler(Isolate* isolate, CpuProfiler* profiler) {
     269         273 :     base::MutexGuard lock(&mutex_);
     270             :     auto range = profilers_.equal_range(isolate);
     271         546 :     for (auto it = range.first; it != range.second; ++it) {
     272         273 :       if (it->second != profiler) continue;
     273             :       profilers_.erase(it);
     274         273 :       return;
     275             :     }
     276           0 :     UNREACHABLE();
     277             :   }
     278             : 
     279           5 :   void CallCollectSample(Isolate* isolate) {
     280           5 :     base::MutexGuard lock(&mutex_);
     281             :     auto range = profilers_.equal_range(isolate);
     282          15 :     for (auto it = range.first; it != range.second; ++it) {
     283           5 :       it->second->CollectSample();
     284             :     }
     285           5 :   }
     286             : 
     287             :  private:
     288             :   std::unordered_multimap<Isolate*, CpuProfiler*> profilers_;
     289             :   base::Mutex mutex_;
     290             : };
     291             : 
     292         551 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager);
     293             : 
     294             : }  // namespace
     295             : 
     296         253 : CpuProfiler::CpuProfiler(Isolate* isolate)
     297         253 :     : CpuProfiler(isolate, new CpuProfilesCollection(isolate), nullptr,
     298         506 :                   nullptr) {}
     299             : 
     300         273 : CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles,
     301             :                          ProfileGenerator* test_generator,
     302             :                          ProfilerEventsProcessor* test_processor)
     303             :     : isolate_(isolate),
     304             :       sampling_interval_(base::TimeDelta::FromMicroseconds(
     305         273 :           FLAG_cpu_profiler_sampling_interval)),
     306             :       profiles_(test_profiles),
     307             :       generator_(test_generator),
     308             :       processor_(test_processor),
     309         819 :       is_profiling_(false) {
     310             :   profiles_->set_cpu_profiler(this);
     311         273 :   GetProfilersManager()->AddProfiler(isolate, this);
     312         273 : }
     313             : 
     314         273 : CpuProfiler::~CpuProfiler() {
     315             :   DCHECK(!is_profiling_);
     316         273 :   GetProfilersManager()->RemoveProfiler(isolate_, this);
     317         273 : }
     318             : 
     319         530 : void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
     320             :   DCHECK(!is_profiling_);
     321         530 :   sampling_interval_ = value;
     322         530 : }
     323             : 
     324         695 : void CpuProfiler::ResetProfiles() {
     325         695 :   profiles_.reset(new CpuProfilesCollection(isolate_));
     326             :   profiles_->set_cpu_profiler(this);
     327             :   profiler_listener_.reset();
     328             :   generator_.reset();
     329         695 : }
     330             : 
     331         743 : void CpuProfiler::CreateEntriesForRuntimeCallStats() {
     332         743 :   RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
     333         743 :   CodeMap* code_map = generator_->code_map();
     334      846277 :   for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
     335      845534 :     RuntimeCallCounter* counter = rcs->GetCounter(i);
     336             :     DCHECK(counter->name());
     337             :     auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
     338      845534 :                                "native V8Runtime");
     339      845534 :     code_map->AddCode(reinterpret_cast<Address>(counter), entry, 1);
     340             :   }
     341         743 : }
     342             : 
     343             : // static
     344           5 : void CpuProfiler::CollectSample(Isolate* isolate) {
     345           5 :   GetProfilersManager()->CallCollectSample(isolate);
     346           5 : }
     347             : 
     348           0 : void CpuProfiler::CollectSample() {
     349           5 :   if (processor_) {
     350           5 :     processor_->AddCurrentStack();
     351             :   }
     352           0 : }
     353             : 
     354         793 : void CpuProfiler::StartProfiling(const char* title, bool record_samples,
     355             :                                  ProfilingMode mode) {
     356        1586 :   if (profiles_->StartProfiling(title, record_samples, mode)) {
     357        1586 :     TRACE_EVENT0("v8", "CpuProfiler::StartProfiling");
     358         793 :     StartProcessorIfNotStarted();
     359             :   }
     360         793 : }
     361             : 
     362         743 : void CpuProfiler::StartProfiling(String title, bool record_samples,
     363             :                                  ProfilingMode mode) {
     364        1486 :   StartProfiling(profiles_->GetName(title), record_samples, mode);
     365         743 :   isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler);
     366         743 : }
     367             : 
     368         793 : void CpuProfiler::StartProcessorIfNotStarted() {
     369         793 :   if (processor_) {
     370          45 :     processor_->AddCurrentStack();
     371         838 :     return;
     372             :   }
     373         748 :   Logger* logger = isolate_->logger();
     374             :   // Disable logging when using the new implementation.
     375         748 :   saved_is_logging_ = logger->is_logging_;
     376         748 :   logger->is_logging_ = false;
     377             : 
     378             :   bool codemap_needs_initialization = false;
     379         748 :   if (!generator_) {
     380         743 :     generator_.reset(new ProfileGenerator(profiles_.get()));
     381             :     codemap_needs_initialization = true;
     382         743 :     CreateEntriesForRuntimeCallStats();
     383             :   }
     384             :   processor_.reset(new SamplingEventsProcessor(isolate_, generator_.get(),
     385        2244 :                                                sampling_interval_));
     386         748 :   if (!profiler_listener_) {
     387         743 :     profiler_listener_.reset(new ProfilerListener(isolate_, processor_.get()));
     388             :   }
     389         748 :   logger->AddCodeEventListener(profiler_listener_.get());
     390         748 :   is_profiling_ = true;
     391         748 :   isolate_->set_is_profiling(true);
     392             :   // Enumerate stuff we already have in the heap.
     393             :   DCHECK(isolate_->heap()->HasBeenSetUp());
     394         748 :   if (codemap_needs_initialization) {
     395         743 :     if (!FLAG_prof_browser_mode) {
     396          25 :       logger->LogCodeObjects();
     397             :     }
     398         743 :     logger->LogCompiledFunctions();
     399         743 :     logger->LogAccessorCallbacks();
     400         743 :     LogBuiltins();
     401             :   }
     402             :   // Enable stack sampling.
     403         748 :   processor_->AddCurrentStack();
     404         748 :   processor_->StartSynchronously();
     405             : }
     406             : 
     407         703 : CpuProfile* CpuProfiler::StopProfiling(const char* title) {
     408         703 :   if (!is_profiling_) return nullptr;
     409         703 :   StopProcessorIfLastProfile(title);
     410         703 :   return profiles_->StopProfiling(title);
     411             : }
     412             : 
     413         663 : CpuProfile* CpuProfiler::StopProfiling(String title) {
     414         663 :   return StopProfiling(profiles_->GetName(title));
     415             : }
     416             : 
     417         703 : void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
     418        1406 :   if (!profiles_->IsLastProfile(title)) return;
     419         668 :   StopProcessor();
     420             : }
     421             : 
     422         748 : void CpuProfiler::StopProcessor() {
     423         748 :   Logger* logger = isolate_->logger();
     424         748 :   is_profiling_ = false;
     425             :   isolate_->set_is_profiling(false);
     426         748 :   logger->RemoveCodeEventListener(profiler_listener_.get());
     427         748 :   processor_->StopSynchronously();
     428             :   processor_.reset();
     429         748 :   logger->is_logging_ = saved_is_logging_;
     430         748 : }
     431             : 
     432             : 
     433         743 : void CpuProfiler::LogBuiltins() {
     434         743 :   Builtins* builtins = isolate_->builtins();
     435             :   DCHECK(builtins->is_initialized());
     436     1123416 :   for (int i = 0; i < Builtins::builtin_count; i++) {
     437             :     CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
     438             :     ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
     439             :     Builtins::Name id = static_cast<Builtins::Name>(i);
     440     1122673 :     rec->instruction_start = builtins->builtin(id)->InstructionStart();
     441     1122673 :     rec->builtin_id = id;
     442     1122673 :     processor_->Enqueue(evt_rec);
     443             :   }
     444         743 : }
     445             : 
     446             : }  // namespace internal
     447      183867 : }  // namespace v8

Generated by: LCOV version 1.10