Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "cpu-profiler-inl.h"
     31 
     32 #ifdef ENABLE_LOGGING_AND_PROFILING
     33 
     34 #include "frames-inl.h"
     35 #include "hashmap.h"
     36 #include "log-inl.h"
     37 #include "vm-state-inl.h"
     38 
     39 #include "../include/v8-profiler.h"
     40 
     41 namespace v8 {
     42 namespace internal {
     43 
     44 static const int kEventsBufferSize = 256*KB;
     45 static const int kTickSamplesBufferChunkSize = 64*KB;
     46 static const int kTickSamplesBufferChunksCount = 16;
     47 
     48 
     49 ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
     50                                                  ProfileGenerator* generator)
     51     : Thread(isolate, "v8:ProfEvntProc"),
     52       generator_(generator),
     53       running_(true),
     54       ticks_buffer_(sizeof(TickSampleEventRecord),
     55                     kTickSamplesBufferChunkSize,
     56                     kTickSamplesBufferChunksCount),
     57       enqueue_order_(0) {
     58 }
     59 
     60 
     61 void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
     62                                                   const char* prefix,
     63                                                   String* name,
     64                                                   Address start) {
     65   if (FilterOutCodeCreateEvent(tag)) return;
     66   CodeEventsContainer evt_rec;
     67   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     68   rec->type = CodeEventRecord::CODE_CREATION;
     69   rec->order = ++enqueue_order_;
     70   rec->start = start;
     71   rec->entry = generator_->NewCodeEntry(tag, prefix, name);
     72   rec->size = 1;
     73   rec->shared = NULL;
     74   events_buffer_.Enqueue(evt_rec);
     75 }
     76 
     77 
     78 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
     79                                               String* name,
     80                                               String* resource_name,
     81                                               int line_number,
     82                                               Address start,
     83                                               unsigned size,
     84                                               Address shared) {
     85   if (FilterOutCodeCreateEvent(tag)) return;
     86   CodeEventsContainer evt_rec;
     87   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
     88   rec->type = CodeEventRecord::CODE_CREATION;
     89   rec->order = ++enqueue_order_;
     90   rec->start = start;
     91   rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
     92   rec->size = size;
     93   rec->shared = shared;
     94   events_buffer_.Enqueue(evt_rec);
     95 }
     96 
     97 
     98 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
     99                                               const char* name,
    100                                               Address start,
    101                                               unsigned size) {
    102   if (FilterOutCodeCreateEvent(tag)) return;
    103   CodeEventsContainer evt_rec;
    104   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
    105   rec->type = CodeEventRecord::CODE_CREATION;
    106   rec->order = ++enqueue_order_;
    107   rec->start = start;
    108   rec->entry = generator_->NewCodeEntry(tag, name);
    109   rec->size = size;
    110   rec->shared = NULL;
    111   events_buffer_.Enqueue(evt_rec);
    112 }
    113 
    114 
    115 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
    116                                               int args_count,
    117                                               Address start,
    118                                               unsigned size) {
    119   if (FilterOutCodeCreateEvent(tag)) return;
    120   CodeEventsContainer evt_rec;
    121   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
    122   rec->type = CodeEventRecord::CODE_CREATION;
    123   rec->order = ++enqueue_order_;
    124   rec->start = start;
    125   rec->entry = generator_->NewCodeEntry(tag, args_count);
    126   rec->size = size;
    127   rec->shared = NULL;
    128   events_buffer_.Enqueue(evt_rec);
    129 }
    130 
    131 
    132 void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
    133   CodeEventsContainer evt_rec;
    134   CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
    135   rec->type = CodeEventRecord::CODE_MOVE;
    136   rec->order = ++enqueue_order_;
    137   rec->from = from;
    138   rec->to = to;
    139   events_buffer_.Enqueue(evt_rec);
    140 }
    141 
    142 
    143 void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
    144   CodeEventsContainer evt_rec;
    145   CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
    146   rec->type = CodeEventRecord::CODE_DELETE;
    147   rec->order = ++enqueue_order_;
    148   rec->start = from;
    149   events_buffer_.Enqueue(evt_rec);
    150 }
    151 
    152 
    153 void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
    154                                                           Address to) {
    155   CodeEventsContainer evt_rec;
    156   SharedFunctionInfoMoveEventRecord* rec =
    157       &evt_rec.SharedFunctionInfoMoveEventRecord_;
    158   rec->type = CodeEventRecord::SHARED_FUNC_MOVE;
    159   rec->order = ++enqueue_order_;
    160   rec->from = from;
    161   rec->to = to;
    162   events_buffer_.Enqueue(evt_rec);
    163 }
    164 
    165 
    166 void ProfilerEventsProcessor::RegExpCodeCreateEvent(
    167     Logger::LogEventsAndTags tag,
    168     const char* prefix,
    169     String* name,
    170     Address start,
    171     unsigned size) {
    172   if (FilterOutCodeCreateEvent(tag)) return;
    173   CodeEventsContainer evt_rec;
    174   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
    175   rec->type = CodeEventRecord::CODE_CREATION;
    176   rec->order = ++enqueue_order_;
    177   rec->start = start;
    178   rec->entry = generator_->NewCodeEntry(tag, prefix, name);
    179   rec->size = size;
    180   events_buffer_.Enqueue(evt_rec);
    181 }
    182 
    183 
    184 void ProfilerEventsProcessor::AddCurrentStack() {
    185   TickSampleEventRecord record;
    186   TickSample* sample = &record.sample;
    187   Isolate* isolate = Isolate::Current();
    188   sample->state = isolate->current_vm_state();
    189   sample->pc = reinterpret_cast<Address>(sample);  // Not NULL.
    190   sample->tos = NULL;
    191   sample->has_external_callback = false;
    192   sample->frames_count = 0;
    193   for (StackTraceFrameIterator it(isolate);
    194        !it.done() && sample->frames_count < TickSample::kMaxFramesCount;
    195        it.Advance()) {
    196     sample->stack[sample->frames_count++] = it.frame()->pc();
    197   }
    198   record.order = enqueue_order_;
    199   ticks_from_vm_buffer_.Enqueue(record);
    200 }
    201 
    202 
    203 bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
    204   if (!events_buffer_.IsEmpty()) {
    205     CodeEventsContainer record;
    206     events_buffer_.Dequeue(&record);
    207     switch (record.generic.type) {
    208 #define PROFILER_TYPE_CASE(type, clss)                          \
    209       case CodeEventRecord::type:                               \
    210         record.clss##_.UpdateCodeMap(generator_->code_map());   \
    211         break;
    212 
    213       CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
    214 
    215 #undef PROFILER_TYPE_CASE
    216       default: return true;  // Skip record.
    217     }
    218     *dequeue_order = record.generic.order;
    219     return true;
    220   }
    221   return false;
    222 }
    223 
    224 
    225 bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
    226   while (true) {
    227     if (!ticks_from_vm_buffer_.IsEmpty()
    228         && ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
    229       TickSampleEventRecord record;
    230       ticks_from_vm_buffer_.Dequeue(&record);
    231       generator_->RecordTickSample(record.sample);
    232     }
    233 
    234     const TickSampleEventRecord* rec =
    235         TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
    236     if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
    237     // Make a local copy of tick sample record to ensure that it won't
    238     // be modified as we are processing it. This is possible as the
    239     // sampler writes w/o any sync to the queue, so if the processor
    240     // will get far behind, a record may be modified right under its
    241     // feet.
    242     TickSampleEventRecord record = *rec;
    243     if (record.order == dequeue_order) {
    244       // A paranoid check to make sure that we don't get a memory overrun
    245       // in case of frames_count having a wild value.
    246       if (record.sample.frames_count < 0
    247           || record.sample.frames_count > TickSample::kMaxFramesCount)
    248         record.sample.frames_count = 0;
    249       generator_->RecordTickSample(record.sample);
    250       ticks_buffer_.FinishDequeue();
    251     } else {
    252       return true;
    253     }
    254   }
    255 }
    256 
    257 
    258 void ProfilerEventsProcessor::Run() {
    259   unsigned dequeue_order = 0;
    260 
    261   while (running_) {
    262     // Process ticks until we have any.
    263     if (ProcessTicks(dequeue_order)) {
    264       // All ticks of the current dequeue_order are processed,
    265       // proceed to the next code event.
    266       ProcessCodeEvent(&dequeue_order);
    267     }
    268     YieldCPU();
    269   }
    270 
    271   // Process remaining tick events.
    272   ticks_buffer_.FlushResidualRecords();
    273   // Perform processing until we have tick events, skip remaining code events.
    274   while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
    275 }
    276 
    277 
    278 void CpuProfiler::StartProfiling(const char* title) {
    279   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    280   Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
    281 }
    282 
    283 
    284 void CpuProfiler::StartProfiling(String* title) {
    285   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    286   Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
    287 }
    288 
    289 
    290 CpuProfile* CpuProfiler::StopProfiling(const char* title) {
    291   return is_profiling() ?
    292       Isolate::Current()->cpu_profiler()->StopCollectingProfile(title) : NULL;
    293 }
    294 
    295 
    296 CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
    297   return is_profiling() ?
    298       Isolate::Current()->cpu_profiler()->StopCollectingProfile(
    299           security_token, title) : NULL;
    300 }
    301 
    302 
    303 int CpuProfiler::GetProfilesCount() {
    304   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    305   // The count of profiles doesn't depend on a security token.
    306   return Isolate::Current()->cpu_profiler()->profiles_->Profiles(
    307       TokenEnumerator::kNoSecurityToken)->length();
    308 }
    309 
    310 
    311 CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
    312   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    313   CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
    314   const int token = profiler->token_enumerator_->GetTokenId(security_token);
    315   return profiler->profiles_->Profiles(token)->at(index);
    316 }
    317 
    318 
    319 CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
    320   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    321   CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
    322   const int token = profiler->token_enumerator_->GetTokenId(security_token);
    323   return profiler->profiles_->GetProfile(token, uid);
    324 }
    325 
    326 
    327 TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
    328   if (CpuProfiler::is_profiling(isolate)) {
    329     return isolate->cpu_profiler()->processor_->TickSampleEvent();
    330   } else {
    331     return NULL;
    332   }
    333 }
    334 
    335 
    336 void CpuProfiler::DeleteAllProfiles() {
    337   Isolate* isolate = Isolate::Current();
    338   ASSERT(isolate->cpu_profiler() != NULL);
    339   if (is_profiling())
    340     isolate->cpu_profiler()->StopProcessor();
    341   isolate->cpu_profiler()->ResetProfiles();
    342 }
    343 
    344 
    345 void CpuProfiler::DeleteProfile(CpuProfile* profile) {
    346   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    347   Isolate::Current()->cpu_profiler()->profiles_->RemoveProfile(profile);
    348   delete profile;
    349 }
    350 
    351 
    352 bool CpuProfiler::HasDetachedProfiles() {
    353   ASSERT(Isolate::Current()->cpu_profiler() != NULL);
    354   return Isolate::Current()->cpu_profiler()->profiles_->HasDetachedProfiles();
    355 }
    356 
    357 
    358 void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
    359   Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
    360       Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
    361 }
    362 
    363 
    364 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
    365                            Code* code, const char* comment) {
    366   Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
    367       tag, comment, code->address(), code->ExecutableSize());
    368 }
    369 
    370 
    371 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
    372                            Code* code, String* name) {
    373   Isolate* isolate = Isolate::Current();
    374   isolate->cpu_profiler()->processor_->CodeCreateEvent(
    375       tag,
    376       name,
    377       isolate->heap()->empty_string(),
    378       v8::CpuProfileNode::kNoLineNumberInfo,
    379       code->address(),
    380       code->ExecutableSize(),
    381       NULL);
    382 }
    383 
    384 
    385 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
    386                                   Code* code,
    387                                   SharedFunctionInfo* shared,
    388                                   String* name) {
    389   Isolate* isolate = Isolate::Current();
    390   isolate->cpu_profiler()->processor_->CodeCreateEvent(
    391       tag,
    392       name,
    393       isolate->heap()->empty_string(),
    394       v8::CpuProfileNode::kNoLineNumberInfo,
    395       code->address(),
    396       code->ExecutableSize(),
    397       shared->address());
    398 }
    399 
    400 
    401 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
    402                                   Code* code,
    403                                   SharedFunctionInfo* shared,
    404                                   String* source, int line) {
    405   Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
    406       tag,
    407       shared->DebugName(),
    408       source,
    409       line,
    410       code->address(),
    411       code->ExecutableSize(),
    412       shared->address());
    413 }
    414 
    415 
    416 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
    417                            Code* code, int args_count) {
    418   Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
    419       tag,
    420       args_count,
    421       code->address(),
    422       code->ExecutableSize());
    423 }
    424 
    425 
    426 void CpuProfiler::CodeMoveEvent(Address from, Address to) {
    427   Isolate::Current()->cpu_profiler()->processor_->CodeMoveEvent(from, to);
    428 }
    429 
    430 
    431 void CpuProfiler::CodeDeleteEvent(Address from) {
    432   Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
    433 }
    434 
    435 
    436 void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
    437   CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
    438   profiler->processor_->SharedFunctionInfoMoveEvent(from, to);
    439 }
    440 
    441 
    442 void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
    443   Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
    444       Logger::CALLBACK_TAG, "get ", name, entry_point);
    445 }
    446 
    447 
    448 void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
    449   Isolate::Current()->cpu_profiler()->processor_->RegExpCodeCreateEvent(
    450       Logger::REG_EXP_TAG,
    451       "RegExp: ",
    452       source,
    453       code->address(),
    454       code->ExecutableSize());
    455 }
    456 
    457 
    458 void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
    459   Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
    460       Logger::CALLBACK_TAG, "set ", name, entry_point);
    461 }
    462 
    463 
    464 CpuProfiler::CpuProfiler()
    465     : profiles_(new CpuProfilesCollection()),
    466       next_profile_uid_(1),
    467       token_enumerator_(new TokenEnumerator()),
    468       generator_(NULL),
    469       processor_(NULL),
    470       need_to_stop_sampler_(false),
    471       is_profiling_(false) {
    472 }
    473 
    474 
    475 CpuProfiler::~CpuProfiler() {
    476   delete token_enumerator_;
    477   delete profiles_;
    478 }
    479 
    480 
    481 void CpuProfiler::ResetProfiles() {
    482   delete profiles_;
    483   profiles_ = new CpuProfilesCollection();
    484 }
    485 
    486 void CpuProfiler::StartCollectingProfile(const char* title) {
    487   if (profiles_->StartProfiling(title, next_profile_uid_++)) {
    488     StartProcessorIfNotStarted();
    489   }
    490   processor_->AddCurrentStack();
    491 }
    492 
    493 
    494 void CpuProfiler::StartCollectingProfile(String* title) {
    495   StartCollectingProfile(profiles_->GetName(title));
    496 }
    497 
    498 
    499 void CpuProfiler::StartProcessorIfNotStarted() {
    500   if (processor_ == NULL) {
    501     Isolate* isolate = Isolate::Current();
    502 
    503     // Disable logging when using the new implementation.
    504     saved_logging_nesting_ = isolate->logger()->logging_nesting_;
    505     isolate->logger()->logging_nesting_ = 0;
    506     generator_ = new ProfileGenerator(profiles_);
    507     processor_ = new ProfilerEventsProcessor(isolate, generator_);
    508     NoBarrier_Store(&is_profiling_, true);
    509     processor_->Start();
    510     // Enumerate stuff we already have in the heap.
    511     if (isolate->heap()->HasBeenSetup()) {
    512       if (!FLAG_prof_browser_mode) {
    513         bool saved_log_code_flag = FLAG_log_code;
    514         FLAG_log_code = true;
    515         isolate->logger()->LogCodeObjects();
    516         FLAG_log_code = saved_log_code_flag;
    517       }
    518       isolate->logger()->LogCompiledFunctions();
    519       isolate->logger()->LogAccessorCallbacks();
    520     }
    521     // Enable stack sampling.
    522     Sampler* sampler = reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
    523     if (!sampler->IsActive()) {
    524       sampler->Start();
    525       need_to_stop_sampler_ = true;
    526     }
    527     sampler->IncreaseProfilingDepth();
    528   }
    529 }
    530 
    531 
    532 CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
    533   const double actual_sampling_rate = generator_->actual_sampling_rate();
    534   StopProcessorIfLastProfile(title);
    535   CpuProfile* result =
    536       profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
    537                                title,
    538                                actual_sampling_rate);
    539   if (result != NULL) {
    540     result->Print();
    541   }
    542   return result;
    543 }
    544 
    545 
    546 CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
    547                                                String* title) {
    548   const double actual_sampling_rate = generator_->actual_sampling_rate();
    549   const char* profile_title = profiles_->GetName(title);
    550   StopProcessorIfLastProfile(profile_title);
    551   int token = token_enumerator_->GetTokenId(security_token);
    552   return profiles_->StopProfiling(token, profile_title, actual_sampling_rate);
    553 }
    554 
    555 
    556 void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
    557   if (profiles_->IsLastProfile(title)) StopProcessor();
    558 }
    559 
    560 
    561 void CpuProfiler::StopProcessor() {
    562   Logger* logger = Isolate::Current()->logger();
    563   Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
    564   sampler->DecreaseProfilingDepth();
    565   if (need_to_stop_sampler_) {
    566     sampler->Stop();
    567     need_to_stop_sampler_ = false;
    568   }
    569   processor_->Stop();
    570   processor_->Join();
    571   delete processor_;
    572   delete generator_;
    573   processor_ = NULL;
    574   NoBarrier_Store(&is_profiling_, false);
    575   generator_ = NULL;
    576   logger->logging_nesting_ = saved_logging_nesting_;
    577 }
    578 
    579 } }  // namespace v8::internal
    580 
    581 #endif  // ENABLE_LOGGING_AND_PROFILING
    582 
    583 namespace v8 {
    584 namespace internal {
    585 
    586 void CpuProfiler::Setup() {
    587 #ifdef ENABLE_LOGGING_AND_PROFILING
    588   Isolate* isolate = Isolate::Current();
    589   if (isolate->cpu_profiler() == NULL) {
    590     isolate->set_cpu_profiler(new CpuProfiler());
    591   }
    592 #endif
    593 }
    594 
    595 
    596 void CpuProfiler::TearDown() {
    597 #ifdef ENABLE_LOGGING_AND_PROFILING
    598   Isolate* isolate = Isolate::Current();
    599   if (isolate->cpu_profiler() != NULL) {
    600     delete isolate->cpu_profiler();
    601   }
    602   isolate->set_cpu_profiler(NULL);
    603 #endif
    604 }
    605 
    606 } }  // namespace v8::internal
    607