Home | History | Annotate | Download | only in profiler
      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 "src/debug/debug.h"
      8 #include "src/deoptimizer.h"
      9 #include "src/frames-inl.h"
     10 #include "src/locked-queue-inl.h"
     11 #include "src/log-inl.h"
     12 #include "src/profiler/cpu-profiler-inl.h"
     13 #include "src/vm-state-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 static const int kProfilerStackSize = 64 * KB;
     19 
     20 class CpuSampler : public sampler::Sampler {
     21  public:
     22   CpuSampler(Isolate* isolate, ProfilerEventsProcessor* processor)
     23       : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
     24         processor_(processor) {}
     25 
     26   void SampleStack(const v8::RegisterState& regs) override {
     27     TickSample* sample = processor_->StartTickSample();
     28     if (sample == nullptr) return;
     29     Isolate* isolate = reinterpret_cast<Isolate*>(this->isolate());
     30     sample->Init(isolate, regs, TickSample::kIncludeCEntryFrame, true);
     31     if (is_counting_samples_ && !sample->timestamp.IsNull()) {
     32       if (sample->state == JS) ++js_sample_count_;
     33       if (sample->state == EXTERNAL) ++external_sample_count_;
     34     }
     35     processor_->FinishTickSample();
     36   }
     37 
     38  private:
     39   ProfilerEventsProcessor* processor_;
     40 };
     41 
     42 ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
     43                                                  ProfileGenerator* generator,
     44                                                  base::TimeDelta period)
     45     : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
     46       generator_(generator),
     47       sampler_(new CpuSampler(isolate, this)),
     48       running_(1),
     49       period_(period),
     50       last_code_event_id_(0),
     51       last_processed_code_event_id_(0) {
     52   sampler_->IncreaseProfilingDepth();
     53 }
     54 
     55 ProfilerEventsProcessor::~ProfilerEventsProcessor() {
     56   sampler_->DecreaseProfilingDepth();
     57 }
     58 
     59 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
     60   event.generic.order = last_code_event_id_.Increment(1);
     61   events_buffer_.Enqueue(event);
     62 }
     63 
     64 
     65 void ProfilerEventsProcessor::AddDeoptStack(Isolate* isolate, Address from,
     66                                             int fp_to_sp_delta) {
     67   TickSampleEventRecord record(last_code_event_id_.Value());
     68   RegisterState regs;
     69   Address fp = isolate->c_entry_fp(isolate->thread_local_top());
     70   regs.sp = fp - fp_to_sp_delta;
     71   regs.fp = fp;
     72   regs.pc = from;
     73   record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame, false, false);
     74   ticks_from_vm_buffer_.Enqueue(record);
     75 }
     76 
     77 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate,
     78                                               bool update_stats) {
     79   TickSampleEventRecord record(last_code_event_id_.Value());
     80   RegisterState regs;
     81   StackFrameIterator it(isolate);
     82   if (!it.done()) {
     83     StackFrame* frame = it.frame();
     84     regs.sp = frame->sp();
     85     regs.fp = frame->fp();
     86     regs.pc = frame->pc();
     87   }
     88   record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame, update_stats,
     89                      false);
     90   ticks_from_vm_buffer_.Enqueue(record);
     91 }
     92 
     93 
     94 void ProfilerEventsProcessor::StopSynchronously() {
     95   if (!base::NoBarrier_AtomicExchange(&running_, 0)) return;
     96   Join();
     97 }
     98 
     99 
    100 bool ProfilerEventsProcessor::ProcessCodeEvent() {
    101   CodeEventsContainer record;
    102   if (events_buffer_.Dequeue(&record)) {
    103     switch (record.generic.type) {
    104 #define PROFILER_TYPE_CASE(type, clss)                          \
    105       case CodeEventRecord::type:                               \
    106         record.clss##_.UpdateCodeMap(generator_->code_map());   \
    107         break;
    108 
    109       CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
    110 
    111 #undef PROFILER_TYPE_CASE
    112       default: return true;  // Skip record.
    113     }
    114     last_processed_code_event_id_ = record.generic.order;
    115     return true;
    116   }
    117   return false;
    118 }
    119 
    120 ProfilerEventsProcessor::SampleProcessingResult
    121     ProfilerEventsProcessor::ProcessOneSample() {
    122   TickSampleEventRecord record1;
    123   if (ticks_from_vm_buffer_.Peek(&record1) &&
    124       (record1.order == last_processed_code_event_id_)) {
    125     TickSampleEventRecord record;
    126     ticks_from_vm_buffer_.Dequeue(&record);
    127     generator_->RecordTickSample(record.sample);
    128     return OneSampleProcessed;
    129   }
    130 
    131   const TickSampleEventRecord* record = ticks_buffer_.Peek();
    132   if (record == NULL) {
    133     if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue;
    134     return FoundSampleForNextCodeEvent;
    135   }
    136   if (record->order != last_processed_code_event_id_) {
    137     return FoundSampleForNextCodeEvent;
    138   }
    139   generator_->RecordTickSample(record->sample);
    140   ticks_buffer_.Remove();
    141   return OneSampleProcessed;
    142 }
    143 
    144 
    145 void ProfilerEventsProcessor::Run() {
    146   while (!!base::NoBarrier_Load(&running_)) {
    147     base::TimeTicks nextSampleTime =
    148         base::TimeTicks::HighResolutionNow() + period_;
    149     base::TimeTicks now;
    150     SampleProcessingResult result;
    151     // Keep processing existing events until we need to do next sample
    152     // or the ticks buffer is empty.
    153     do {
    154       result = ProcessOneSample();
    155       if (result == FoundSampleForNextCodeEvent) {
    156         // All ticks of the current last_processed_code_event_id_ are
    157         // processed, proceed to the next code event.
    158         ProcessCodeEvent();
    159       }
    160       now = base::TimeTicks::HighResolutionNow();
    161     } while (result != NoSamplesInQueue && now < nextSampleTime);
    162 
    163     if (nextSampleTime > now) {
    164 #if V8_OS_WIN
    165       // Do not use Sleep on Windows as it is very imprecise.
    166       // Could be up to 16ms jitter, which is unacceptable for the purpose.
    167       while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
    168       }
    169 #else
    170       base::OS::Sleep(nextSampleTime - now);
    171 #endif
    172     }
    173 
    174     // Schedule next sample. sampler_ is NULL in tests.
    175     if (sampler_) sampler_->DoSample();
    176   }
    177 
    178   // Process remaining tick events.
    179   do {
    180     SampleProcessingResult result;
    181     do {
    182       result = ProcessOneSample();
    183     } while (result == OneSampleProcessed);
    184   } while (ProcessCodeEvent());
    185 }
    186 
    187 
    188 void* ProfilerEventsProcessor::operator new(size_t size) {
    189   return AlignedAlloc(size, V8_ALIGNOF(ProfilerEventsProcessor));
    190 }
    191 
    192 
    193 void ProfilerEventsProcessor::operator delete(void* ptr) {
    194   AlignedFree(ptr);
    195 }
    196 
    197 
    198 int CpuProfiler::GetProfilesCount() {
    199   // The count of profiles doesn't depend on a security token.
    200   return profiles_->profiles()->length();
    201 }
    202 
    203 
    204 CpuProfile* CpuProfiler::GetProfile(int index) {
    205   return profiles_->profiles()->at(index);
    206 }
    207 
    208 
    209 void CpuProfiler::DeleteAllProfiles() {
    210   if (is_profiling_) StopProcessor();
    211   ResetProfiles();
    212 }
    213 
    214 
    215 void CpuProfiler::DeleteProfile(CpuProfile* profile) {
    216   profiles_->RemoveProfile(profile);
    217   delete profile;
    218   if (profiles_->profiles()->is_empty() && !is_profiling_) {
    219     // If this was the last profile, clean up all accessory data as well.
    220     ResetProfiles();
    221   }
    222 }
    223 
    224 void CpuProfiler::CodeEventHandler(const CodeEventsContainer& evt_rec) {
    225   switch (evt_rec.generic.type) {
    226     case CodeEventRecord::CODE_CREATION:
    227     case CodeEventRecord::CODE_MOVE:
    228     case CodeEventRecord::CODE_DISABLE_OPT:
    229       processor_->Enqueue(evt_rec);
    230       break;
    231     case CodeEventRecord::CODE_DEOPT: {
    232       const CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
    233       Address pc = reinterpret_cast<Address>(rec->pc);
    234       int fp_to_sp_delta = rec->fp_to_sp_delta;
    235       processor_->Enqueue(evt_rec);
    236       processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta);
    237       break;
    238     }
    239     default:
    240       UNREACHABLE();
    241   }
    242 }
    243 
    244 CpuProfiler::CpuProfiler(Isolate* isolate)
    245     : isolate_(isolate),
    246       sampling_interval_(base::TimeDelta::FromMicroseconds(
    247           FLAG_cpu_profiler_sampling_interval)),
    248       profiles_(new CpuProfilesCollection(isolate)),
    249       is_profiling_(false) {
    250   profiles_->set_cpu_profiler(this);
    251 }
    252 
    253 CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles,
    254                          ProfileGenerator* test_generator,
    255                          ProfilerEventsProcessor* test_processor)
    256     : isolate_(isolate),
    257       sampling_interval_(base::TimeDelta::FromMicroseconds(
    258           FLAG_cpu_profiler_sampling_interval)),
    259       profiles_(test_profiles),
    260       generator_(test_generator),
    261       processor_(test_processor),
    262       is_profiling_(false) {
    263   profiles_->set_cpu_profiler(this);
    264 }
    265 
    266 CpuProfiler::~CpuProfiler() {
    267   DCHECK(!is_profiling_);
    268 }
    269 
    270 void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
    271   DCHECK(!is_profiling_);
    272   sampling_interval_ = value;
    273 }
    274 
    275 void CpuProfiler::ResetProfiles() {
    276   profiles_.reset(new CpuProfilesCollection(isolate_));
    277   profiles_->set_cpu_profiler(this);
    278 }
    279 
    280 void CpuProfiler::CreateEntriesForRuntimeCallStats() {
    281   static_entries_.clear();
    282   RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
    283   CodeMap* code_map = generator_->code_map();
    284   for (int i = 0; i < RuntimeCallStats::counters_count; ++i) {
    285     RuntimeCallCounter* counter = &(rcs->*(RuntimeCallStats::counters[i]));
    286     DCHECK(counter->name());
    287     std::unique_ptr<CodeEntry> entry(
    288         new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
    289                       CodeEntry::kEmptyNamePrefix, "native V8Runtime"));
    290     code_map->AddCode(reinterpret_cast<Address>(counter), entry.get(), 1);
    291     static_entries_.push_back(std::move(entry));
    292   }
    293 }
    294 
    295 void CpuProfiler::CollectSample() {
    296   if (processor_) {
    297     processor_->AddCurrentStack(isolate_);
    298   }
    299 }
    300 
    301 void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
    302   if (profiles_->StartProfiling(title, record_samples)) {
    303     StartProcessorIfNotStarted();
    304   }
    305 }
    306 
    307 
    308 void CpuProfiler::StartProfiling(String* title, bool record_samples) {
    309   StartProfiling(profiles_->GetName(title), record_samples);
    310   isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler);
    311 }
    312 
    313 
    314 void CpuProfiler::StartProcessorIfNotStarted() {
    315   if (processor_) {
    316     processor_->AddCurrentStack(isolate_);
    317     return;
    318   }
    319   Logger* logger = isolate_->logger();
    320   // Disable logging when using the new implementation.
    321   saved_is_logging_ = logger->is_logging_;
    322   logger->is_logging_ = false;
    323   generator_.reset(new ProfileGenerator(profiles_.get()));
    324   processor_.reset(new ProfilerEventsProcessor(isolate_, generator_.get(),
    325                                                sampling_interval_));
    326   CreateEntriesForRuntimeCallStats();
    327   logger->SetUpProfilerListener();
    328   ProfilerListener* profiler_listener = logger->profiler_listener();
    329   profiler_listener->AddObserver(this);
    330   is_profiling_ = true;
    331   isolate_->set_is_profiling(true);
    332   // Enumerate stuff we already have in the heap.
    333   DCHECK(isolate_->heap()->HasBeenSetUp());
    334   if (!FLAG_prof_browser_mode) {
    335     logger->LogCodeObjects();
    336   }
    337   logger->LogCompiledFunctions();
    338   logger->LogAccessorCallbacks();
    339   LogBuiltins();
    340   // Enable stack sampling.
    341   processor_->AddCurrentStack(isolate_);
    342   processor_->StartSynchronously();
    343 }
    344 
    345 CpuProfile* CpuProfiler::StopProfiling(const char* title) {
    346   if (!is_profiling_) return nullptr;
    347   StopProcessorIfLastProfile(title);
    348   return profiles_->StopProfiling(title);
    349 }
    350 
    351 CpuProfile* CpuProfiler::StopProfiling(String* title) {
    352   return StopProfiling(profiles_->GetName(title));
    353 }
    354 
    355 void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
    356   if (!profiles_->IsLastProfile(title)) return;
    357   StopProcessor();
    358 }
    359 
    360 void CpuProfiler::StopProcessor() {
    361   Logger* logger = isolate_->logger();
    362   is_profiling_ = false;
    363   isolate_->set_is_profiling(false);
    364   ProfilerListener* profiler_listener = logger->profiler_listener();
    365   profiler_listener->RemoveObserver(this);
    366   processor_->StopSynchronously();
    367   logger->TearDownProfilerListener();
    368   processor_.reset();
    369   generator_.reset();
    370   logger->is_logging_ = saved_is_logging_;
    371 }
    372 
    373 
    374 void CpuProfiler::LogBuiltins() {
    375   Builtins* builtins = isolate_->builtins();
    376   DCHECK(builtins->is_initialized());
    377   for (int i = 0; i < Builtins::builtin_count; i++) {
    378     CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
    379     ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
    380     Builtins::Name id = static_cast<Builtins::Name>(i);
    381     rec->start = builtins->builtin(id)->address();
    382     rec->builtin_id = id;
    383     processor_->Enqueue(evt_rec);
    384   }
    385 }
    386 
    387 }  // namespace internal
    388 }  // namespace v8
    389