LCOV - code coverage report
Current view: top level - src/profiler - cpu-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 204 222 91.9 %
Date: 2019-02-19 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/template-utils.h"
      12             : #include "src/debug/debug.h"
      13             : #include "src/deoptimizer.h"
      14             : #include "src/frames-inl.h"
      15             : #include "src/locked-queue-inl.h"
      16             : #include "src/log.h"
      17             : #include "src/profiler/cpu-profiler-inl.h"
      18             : #include "src/vm-state-inl.h"
      19             : #include "src/wasm/wasm-engine.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : 
      24             : static const int kProfilerStackSize = 64 * KB;
      25             : 
      26         752 : class CpuSampler : public sampler::Sampler {
      27             :  public:
      28             :   CpuSampler(Isolate* isolate, SamplingEventsProcessor* processor)
      29             :       : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
      30         757 :         processor_(processor) {}
      31             : 
      32       27286 :   void SampleStack(const v8::RegisterState& regs) override {
      33       27286 :     TickSample* sample = processor_->StartTickSample();
      34       54572 :     if (sample == nullptr) return;
      35       27286 :     Isolate* isolate = reinterpret_cast<Isolate*>(this->isolate());
      36       27286 :     sample->Init(isolate, regs, TickSample::kIncludeCEntryFrame, true);
      37       46792 :     if (is_counting_samples_ && !sample->timestamp.IsNull()) {
      38       19506 :       if (sample->state == JS) ++js_sample_count_;
      39       19506 :       if (sample->state == EXTERNAL) ++external_sample_count_;
      40             :     }
      41       27286 :     processor_->FinishTickSample();
      42             :   }
      43             : 
      44             :  private:
      45             :   SamplingEventsProcessor* processor_;
      46             : };
      47             : 
      48         757 : 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        1514 :       isolate_(isolate) {}
      56             : 
      57         757 : SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
      58             :                                                  ProfileGenerator* generator,
      59             :                                                  base::TimeDelta period)
      60             :     : ProfilerEventsProcessor(isolate, generator),
      61             :       sampler_(new CpuSampler(isolate, this)),
      62        2271 :       period_(period) {
      63         757 :   sampler_->Start();
      64         757 : }
      65             : 
      66        3760 : SamplingEventsProcessor::~SamplingEventsProcessor() { sampler_->Stop(); }
      67             : 
      68             : ProfilerEventsProcessor::~ProfilerEventsProcessor() = default;
      69             : 
      70     1741661 : void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
      71     1741661 :   event.generic.order = ++last_code_event_id_;
      72     1741661 :   events_buffer_.Enqueue(event);
      73     1741661 : }
      74             : 
      75           0 : void ProfilerEventsProcessor::AddDeoptStack(Address from, int fp_to_sp_delta) {
      76             :   TickSampleEventRecord record(last_code_event_id_);
      77             :   RegisterState regs;
      78           0 :   Address fp = isolate_->c_entry_fp(isolate_->thread_local_top());
      79           0 :   regs.sp = reinterpret_cast<void*>(fp - fp_to_sp_delta);
      80           0 :   regs.fp = reinterpret_cast<void*>(fp);
      81           0 :   regs.pc = reinterpret_cast<void*>(from);
      82             :   record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, false,
      83           0 :                      false);
      84           0 :   ticks_from_vm_buffer_.Enqueue(record);
      85           0 : }
      86             : 
      87         803 : void ProfilerEventsProcessor::AddCurrentStack(bool update_stats) {
      88             :   TickSampleEventRecord record(last_code_event_id_);
      89             :   RegisterState regs;
      90         803 :   StackFrameIterator it(isolate_);
      91         803 :   if (!it.done()) {
      92         146 :     StackFrame* frame = it.frame();
      93          73 :     regs.sp = reinterpret_cast<void*>(frame->sp());
      94          73 :     regs.fp = reinterpret_cast<void*>(frame->fp());
      95          73 :     regs.pc = reinterpret_cast<void*>(frame->pc());
      96             :   }
      97             :   record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, update_stats,
      98         803 :                      false);
      99         803 :   ticks_from_vm_buffer_.Enqueue(record);
     100         803 : }
     101             : 
     102          34 : void ProfilerEventsProcessor::AddSample(TickSample sample) {
     103             :   TickSampleEventRecord record(last_code_event_id_);
     104          34 :   record.sample = sample;
     105          34 :   ticks_from_vm_buffer_.Enqueue(record);
     106          34 : }
     107             : 
     108         762 : void ProfilerEventsProcessor::StopSynchronously() {
     109        2286 :   if (!base::Relaxed_AtomicExchange(&running_, 0)) return;
     110             :   {
     111         757 :     base::MutexGuard guard(&running_mutex_);
     112         757 :     running_cond_.NotifyOne();
     113             :   }
     114         757 :   Join();
     115             : }
     116             : 
     117             : 
     118     1742414 : bool ProfilerEventsProcessor::ProcessCodeEvent() {
     119             :   CodeEventsContainer record;
     120     1742414 :   if (events_buffer_.Dequeue(&record)) {
     121     1741660 :     switch (record.generic.type) {
     122             : #define PROFILER_TYPE_CASE(type, clss)                          \
     123             :       case CodeEventRecord::type:                               \
     124             :         record.clss##_.UpdateCodeMap(generator_->code_map());   \
     125             :         break;
     126             : 
     127     1741661 :       CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
     128             : 
     129             : #undef PROFILER_TYPE_CASE
     130             :       default: return true;  // Skip record.
     131             :     }
     132     1741650 :     last_processed_code_event_id_ = record.generic.order;
     133     1741650 :     return true;
     134             :   }
     135             :   return false;
     136             : }
     137             : 
     138      661071 : void ProfilerEventsProcessor::CodeEventHandler(
     139             :     const CodeEventsContainer& evt_rec) {
     140      661071 :   switch (evt_rec.generic.type) {
     141             :     case CodeEventRecord::CODE_CREATION:
     142             :     case CodeEventRecord::CODE_MOVE:
     143             :     case CodeEventRecord::CODE_DISABLE_OPT:
     144      661071 :       Enqueue(evt_rec);
     145      661071 :       break;
     146             :     case CodeEventRecord::CODE_DEOPT: {
     147             :       const CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
     148           0 :       Address pc = rec->pc;
     149           0 :       int fp_to_sp_delta = rec->fp_to_sp_delta;
     150           0 :       Enqueue(evt_rec);
     151           0 :       AddDeoptStack(pc, fp_to_sp_delta);
     152           0 :       break;
     153             :     }
     154             :     case CodeEventRecord::NONE:
     155             :     case CodeEventRecord::REPORT_BUILTIN:
     156           0 :       UNREACHABLE();
     157             :   }
     158      661071 : }
     159             : 
     160             : ProfilerEventsProcessor::SampleProcessingResult
     161     1798276 : SamplingEventsProcessor::ProcessOneSample() {
     162             :   TickSampleEventRecord record1;
     163     3540187 :   if (ticks_from_vm_buffer_.Peek(&record1) &&
     164     1741911 :       (record1.order == last_processed_code_event_id_)) {
     165             :     TickSampleEventRecord record;
     166         837 :     ticks_from_vm_buffer_.Dequeue(&record);
     167         837 :     generator_->RecordTickSample(record.sample);
     168             :     return OneSampleProcessed;
     169             :   }
     170             : 
     171     1797443 :   const TickSampleEventRecord* record = ticks_buffer_.Peek();
     172     1797448 :   if (record == nullptr) {
     173     1103785 :     if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue;
     174     1074866 :     return FoundSampleForNextCodeEvent;
     175             :   }
     176      693663 :   if (record->order != last_processed_code_event_id_) {
     177             :     return FoundSampleForNextCodeEvent;
     178             :   }
     179       27127 :   generator_->RecordTickSample(record->sample);
     180       27127 :   ticks_buffer_.Remove();
     181       27127 :   return OneSampleProcessed;
     182             : }
     183             : 
     184         757 : void SamplingEventsProcessor::Run() {
     185         757 :   base::MutexGuard guard(&running_mutex_);
     186       59310 :   while (!!base::Relaxed_Load(&running_)) {
     187             :     base::TimeTicks nextSampleTime =
     188       57796 :         base::TimeTicks::HighResolutionNow() + period_;
     189             :     base::TimeTicks now;
     190             :     SampleProcessingResult result;
     191             :     // Keep processing existing events until we need to do next sample
     192             :     // or the ticks buffer is empty.
     193      441034 :     do {
     194      441034 :       result = ProcessOneSample();
     195      441034 :       if (result == FoundSampleForNextCodeEvent) {
     196             :         // All ticks of the current last_processed_code_event_id_ are
     197             :         // processed, proceed to the next code event.
     198      386221 :         ProcessCodeEvent();
     199             :       }
     200      441034 :       now = base::TimeTicks::HighResolutionNow();
     201      441034 :     } while (result != NoSamplesInQueue && now < nextSampleTime);
     202             : 
     203       28898 :     if (nextSampleTime > now) {
     204             : #if V8_OS_WIN
     205             :       if (nextSampleTime - now < base::TimeDelta::FromMilliseconds(100)) {
     206             :         // Do not use Sleep on Windows as it is very imprecise, with up to 16ms
     207             :         // jitter, which is unacceptable for short profile intervals.
     208             :         while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
     209             :         }
     210             :       } else  // NOLINT
     211             : #endif
     212             :       {
     213             :         // Allow another thread to interrupt the delay between samples in the
     214             :         // event of profiler shutdown.
     215       83715 :         while (now < nextSampleTime &&
     216       83715 :                running_cond_.WaitFor(&running_mutex_, nextSampleTime - now)) {
     217             :           // If true was returned, we got interrupted before the timeout
     218             :           // elapsed. If this was not due to a change in running state, a
     219             :           // spurious wakeup occurred (thus we should continue to wait).
     220         178 :           if (!base::Relaxed_Load(&running_)) {
     221             :             break;
     222             :           }
     223           0 :           now = base::TimeTicks::HighResolutionNow();
     224             :         }
     225             :       }
     226             :     }
     227             : 
     228             :     // Schedule next sample.
     229       28898 :     sampler_->DoSample();
     230             :   }
     231             : 
     232             :   // Process remaining tick events.
     233     1356197 :   do {
     234             :     SampleProcessingResult result;
     235     1357253 :     do {
     236     1357253 :       result = ProcessOneSample();
     237             :     } while (result == OneSampleProcessed);
     238     1356197 :   } while (ProcessCodeEvent());
     239         757 : }
     240             : 
     241          29 : void* SamplingEventsProcessor::operator new(size_t size) {
     242         757 :   return AlignedAlloc(size, alignof(SamplingEventsProcessor));
     243             : }
     244             : 
     245         752 : void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
     246             : 
     247         155 : int CpuProfiler::GetProfilesCount() {
     248             :   // The count of profiles doesn't depend on a security token.
     249         310 :   return static_cast<int>(profiles_->profiles()->size());
     250             : }
     251             : 
     252             : 
     253          35 : CpuProfile* CpuProfiler::GetProfile(int index) {
     254          70 :   return profiles_->profiles()->at(index).get();
     255             : }
     256             : 
     257             : 
     258          50 : void CpuProfiler::DeleteAllProfiles() {
     259          50 :   if (is_profiling_) StopProcessor();
     260          50 :   ResetProfiles();
     261          50 : }
     262             : 
     263             : 
     264         630 : void CpuProfiler::DeleteProfile(CpuProfile* profile) {
     265         630 :   profiles_->RemoveProfile(profile);
     266         630 :   if (profiles_->profiles()->empty() && !is_profiling_) {
     267             :     // If this was the last profile, clean up all accessory data as well.
     268         600 :     ResetProfiles();
     269             :   }
     270         630 : }
     271             : 
     272             : namespace {
     273             : 
     274         444 : class CpuProfilersManager {
     275             :  public:
     276         247 :   void AddProfiler(Isolate* isolate, CpuProfiler* profiler) {
     277         247 :     base::MutexGuard lock(&mutex_);
     278             :     profilers_.emplace(isolate, profiler);
     279         247 :   }
     280             : 
     281         247 :   void RemoveProfiler(Isolate* isolate, CpuProfiler* profiler) {
     282         247 :     base::MutexGuard lock(&mutex_);
     283             :     auto range = profilers_.equal_range(isolate);
     284         494 :     for (auto it = range.first; it != range.second; ++it) {
     285         247 :       if (it->second != profiler) continue;
     286             :       profilers_.erase(it);
     287         247 :       return;
     288             :     }
     289           0 :     UNREACHABLE();
     290             :   }
     291             : 
     292           5 :   void CallCollectSample(Isolate* isolate) {
     293           5 :     base::MutexGuard lock(&mutex_);
     294             :     auto range = profilers_.equal_range(isolate);
     295          15 :     for (auto it = range.first; it != range.second; ++it) {
     296           5 :       it->second->CollectSample();
     297             :     }
     298           5 :   }
     299             : 
     300             :  private:
     301             :   std::unordered_multimap<Isolate*, CpuProfiler*> profilers_;
     302             :   base::Mutex mutex_;
     303             : };
     304             : 
     305         499 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager)
     306             : 
     307             : }  // namespace
     308             : 
     309         228 : CpuProfiler::CpuProfiler(Isolate* isolate)
     310         228 :     : CpuProfiler(isolate, new CpuProfilesCollection(isolate), nullptr,
     311         456 :                   nullptr) {}
     312             : 
     313         247 : CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles,
     314             :                          ProfileGenerator* test_generator,
     315             :                          ProfilerEventsProcessor* test_processor)
     316             :     : isolate_(isolate),
     317             :       sampling_interval_(base::TimeDelta::FromMicroseconds(
     318         247 :           FLAG_cpu_profiler_sampling_interval)),
     319             :       profiles_(test_profiles),
     320             :       generator_(test_generator),
     321             :       processor_(test_processor),
     322         741 :       is_profiling_(false) {
     323             :   profiles_->set_cpu_profiler(this);
     324         247 :   GetProfilersManager()->AddProfiler(isolate, this);
     325         247 : }
     326             : 
     327         247 : CpuProfiler::~CpuProfiler() {
     328             :   DCHECK(!is_profiling_);
     329         247 :   GetProfilersManager()->RemoveProfiler(isolate_, this);
     330         247 : }
     331             : 
     332         545 : void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
     333             :   DCHECK(!is_profiling_);
     334         545 :   sampling_interval_ = value;
     335         545 : }
     336             : 
     337         650 : void CpuProfiler::ResetProfiles() {
     338         650 :   profiles_.reset(new CpuProfilesCollection(isolate_));
     339             :   profiles_->set_cpu_profiler(this);
     340             :   profiler_listener_.reset();
     341             :   generator_.reset();
     342         650 : }
     343             : 
     344         718 : void CpuProfiler::CreateEntriesForRuntimeCallStats() {
     345         718 :   RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
     346         718 :   CodeMap* code_map = generator_->code_map();
     347      819238 :   for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
     348      818520 :     RuntimeCallCounter* counter = rcs->GetCounter(i);
     349             :     DCHECK(counter->name());
     350             :     auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
     351      818520 :                                "native V8Runtime");
     352      818520 :     code_map->AddCode(reinterpret_cast<Address>(counter), entry, 1);
     353             :   }
     354         718 : }
     355             : 
     356             : // static
     357           5 : void CpuProfiler::CollectSample(Isolate* isolate) {
     358           5 :   GetProfilersManager()->CallCollectSample(isolate);
     359           5 : }
     360             : 
     361           0 : void CpuProfiler::CollectSample() {
     362           5 :   if (processor_) {
     363           5 :     processor_->AddCurrentStack();
     364             :   }
     365           0 : }
     366             : 
     367         773 : void CpuProfiler::StartProfiling(const char* title, bool record_samples,
     368             :                                  ProfilingMode mode) {
     369        1546 :   if (profiles_->StartProfiling(title, record_samples, mode)) {
     370        1546 :     TRACE_EVENT0("v8", "CpuProfiler::StartProfiling");
     371         773 :     StartProcessorIfNotStarted();
     372             :   }
     373         773 : }
     374             : 
     375         703 : void CpuProfiler::StartProfiling(String title, bool record_samples,
     376             :                                  ProfilingMode mode) {
     377        1406 :   StartProfiling(profiles_->GetName(title), record_samples, mode);
     378         703 :   isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler);
     379         703 : }
     380             : 
     381         773 : void CpuProfiler::StartProcessorIfNotStarted() {
     382         773 :   if (processor_) {
     383          45 :     processor_->AddCurrentStack();
     384         818 :     return;
     385             :   }
     386        2184 :   isolate_->wasm_engine()->EnableCodeLogging(isolate_);
     387        1456 :   Logger* logger = isolate_->logger();
     388             :   // Disable logging when using the new implementation.
     389         728 :   saved_is_logging_ = logger->is_logging();
     390             :   logger->set_is_logging(false);
     391             : 
     392             :   bool codemap_needs_initialization = false;
     393         728 :   if (!generator_) {
     394         718 :     generator_.reset(new ProfileGenerator(profiles_.get()));
     395             :     codemap_needs_initialization = true;
     396         718 :     CreateEntriesForRuntimeCallStats();
     397             :   }
     398             :   processor_.reset(new SamplingEventsProcessor(isolate_, generator_.get(),
     399        2184 :                                                sampling_interval_));
     400         728 :   if (profiler_listener_) {
     401          10 :     profiler_listener_->set_observer(processor_.get());
     402             :   } else {
     403         718 :     profiler_listener_.reset(new ProfilerListener(isolate_, processor_.get()));
     404             :   }
     405         728 :   logger->AddCodeEventListener(profiler_listener_.get());
     406         728 :   is_profiling_ = true;
     407         728 :   isolate_->set_is_profiling(true);
     408             :   // Enumerate stuff we already have in the heap.
     409             :   DCHECK(isolate_->heap()->HasBeenSetUp());
     410         728 :   if (codemap_needs_initialization) {
     411         718 :     if (!FLAG_prof_browser_mode) {
     412          25 :       logger->LogCodeObjects();
     413             :     }
     414         718 :     logger->LogCompiledFunctions();
     415         718 :     logger->LogAccessorCallbacks();
     416         718 :     LogBuiltins();
     417             :   }
     418             :   // Enable stack sampling.
     419         728 :   processor_->AddCurrentStack();
     420         728 :   processor_->StartSynchronously();
     421             : }
     422             : 
     423         728 : CpuProfile* CpuProfiler::StopProfiling(const char* title) {
     424         728 :   if (!is_profiling_) return nullptr;
     425         728 :   StopProcessorIfLastProfile(title);
     426         728 :   return profiles_->StopProfiling(title);
     427             : }
     428             : 
     429         668 : CpuProfile* CpuProfiler::StopProfiling(String title) {
     430         668 :   return StopProfiling(profiles_->GetName(title));
     431             : }
     432             : 
     433         728 : void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
     434        1456 :   if (!profiles_->IsLastProfile(title)) return;
     435         693 :   StopProcessor();
     436             : }
     437             : 
     438         728 : void CpuProfiler::StopProcessor() {
     439         728 :   Logger* logger = isolate_->logger();
     440         728 :   is_profiling_ = false;
     441             :   isolate_->set_is_profiling(false);
     442         728 :   logger->RemoveCodeEventListener(profiler_listener_.get());
     443         728 :   processor_->StopSynchronously();
     444             :   processor_.reset();
     445         728 :   logger->set_is_logging(saved_is_logging_);
     446         728 : }
     447             : 
     448             : 
     449         718 : void CpuProfiler::LogBuiltins() {
     450         718 :   Builtins* builtins = isolate_->builtins();
     451             :   DCHECK(builtins->is_initialized());
     452     1081308 :   for (int i = 0; i < Builtins::builtin_count; i++) {
     453             :     CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
     454             :     ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
     455             :     Builtins::Name id = static_cast<Builtins::Name>(i);
     456     1080590 :     rec->instruction_start = builtins->builtin(id)->InstructionStart();
     457     1080590 :     rec->builtin_id = id;
     458     1080590 :     processor_->Enqueue(evt_rec);
     459             :   }
     460         718 : }
     461             : 
     462             : }  // namespace internal
     463      178779 : }  // namespace v8

Generated by: LCOV version 1.10