| OLD | NEW | 
|    1 // Copyright 2012 the V8 project authors. All rights reserved. |    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 |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "src/profiler/profile-generator.h" |    5 #include "src/profiler/profile-generator.h" | 
|    6  |    6  | 
|    7 #include "src/ast/scopeinfo.h" |    7 #include "src/ast/scopeinfo.h" | 
|    8 #include "src/base/adapters.h" |    8 #include "src/base/adapters.h" | 
|    9 #include "src/debug/debug.h" |    9 #include "src/debug/debug.h" | 
|   10 #include "src/deoptimizer.h" |   10 #include "src/deoptimizer.h" | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|   41   } |   41   } | 
|   42   return it->second; |   42   return it->second; | 
|   43 } |   43 } | 
|   44  |   44  | 
|   45  |   45  | 
|   46 const char* const CodeEntry::kEmptyNamePrefix = ""; |   46 const char* const CodeEntry::kEmptyNamePrefix = ""; | 
|   47 const char* const CodeEntry::kEmptyResourceName = ""; |   47 const char* const CodeEntry::kEmptyResourceName = ""; | 
|   48 const char* const CodeEntry::kEmptyBailoutReason = ""; |   48 const char* const CodeEntry::kEmptyBailoutReason = ""; | 
|   49 const char* const CodeEntry::kNoDeoptReason = ""; |   49 const char* const CodeEntry::kNoDeoptReason = ""; | 
|   50  |   50  | 
|   51 const char* const CodeEntry::kProgramEntryName = "(program)"; |  | 
|   52 const char* const CodeEntry::kIdleEntryName = "(idle)"; |  | 
|   53 const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)"; |  | 
|   54 const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)"; |  | 
|   55  |  | 
|   56 base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type |  | 
|   57     CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |  | 
|   58  |  | 
|   59 base::LazyDynamicInstance<CodeEntry, CodeEntry::IdleEntryCreateTrait>::type |  | 
|   60     CodeEntry::kIdleEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |  | 
|   61  |  | 
|   62 base::LazyDynamicInstance<CodeEntry, CodeEntry::GCEntryCreateTrait>::type |  | 
|   63     CodeEntry::kGCEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |  | 
|   64  |  | 
|   65 base::LazyDynamicInstance<CodeEntry, |  | 
|   66                           CodeEntry::UnresolvedEntryCreateTrait>::type |  | 
|   67     CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |  | 
|   68  |  | 
|   69 CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() { |  | 
|   70   return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kProgramEntryName); |  | 
|   71 } |  | 
|   72  |  | 
|   73 CodeEntry* CodeEntry::IdleEntryCreateTrait::Create() { |  | 
|   74   return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kIdleEntryName); |  | 
|   75 } |  | 
|   76  |  | 
|   77 CodeEntry* CodeEntry::GCEntryCreateTrait::Create() { |  | 
|   78   return new CodeEntry(Logger::BUILTIN_TAG, |  | 
|   79                        CodeEntry::kGarbageCollectorEntryName); |  | 
|   80 } |  | 
|   81  |  | 
|   82 CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() { |  | 
|   83   return new CodeEntry(Logger::FUNCTION_TAG, |  | 
|   84                        CodeEntry::kUnresolvedFunctionName); |  | 
|   85 } |  | 
|   86  |   51  | 
|   87 CodeEntry::~CodeEntry() { |   52 CodeEntry::~CodeEntry() { | 
|   88   delete line_info_; |   53   delete line_info_; | 
|   89   for (auto location : inline_locations_) { |   54   for (auto location : inline_locations_) { | 
|   90     for (auto entry : location.second) { |   55     for (auto entry : location.second) { | 
|   91       delete entry; |   56       delete entry; | 
|   92     } |   57     } | 
|   93   } |   58   } | 
|   94 } |   59 } | 
|   95  |   60  | 
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  461 } |  426 } | 
|  462  |  427  | 
|  463 void CodeMap::Print() { |  428 void CodeMap::Print() { | 
|  464   for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { |  429   for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { | 
|  465     base::OS::Print("%p %5d %s\n", static_cast<void*>(it->first), |  430     base::OS::Print("%p %5d %s\n", static_cast<void*>(it->first), | 
|  466                     it->second.size, it->second.entry->name()); |  431                     it->second.size, it->second.entry->name()); | 
|  467   } |  432   } | 
|  468 } |  433 } | 
|  469  |  434  | 
|  470 CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) |  435 CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) | 
|  471     : resource_names_(isolate->heap()), |  436     : function_and_resource_names_(isolate->heap()), | 
|  472       profiler_(nullptr), |  437       profiler_(nullptr), | 
|  473       current_profiles_semaphore_(1) {} |  438       current_profiles_semaphore_(1) {} | 
|  474  |  439  | 
 |  440 static void DeleteCodeEntry(CodeEntry** entry_ptr) { | 
 |  441   delete *entry_ptr; | 
 |  442 } | 
 |  443  | 
 |  444  | 
|  475 static void DeleteCpuProfile(CpuProfile** profile_ptr) { |  445 static void DeleteCpuProfile(CpuProfile** profile_ptr) { | 
|  476   delete *profile_ptr; |  446   delete *profile_ptr; | 
|  477 } |  447 } | 
|  478  |  448  | 
|  479  |  449  | 
|  480 CpuProfilesCollection::~CpuProfilesCollection() { |  450 CpuProfilesCollection::~CpuProfilesCollection() { | 
|  481   finished_profiles_.Iterate(DeleteCpuProfile); |  451   finished_profiles_.Iterate(DeleteCpuProfile); | 
|  482   current_profiles_.Iterate(DeleteCpuProfile); |  452   current_profiles_.Iterate(DeleteCpuProfile); | 
 |  453   code_entries_.Iterate(DeleteCodeEntry); | 
|  483 } |  454 } | 
|  484  |  455  | 
|  485  |  456  | 
|  486 bool CpuProfilesCollection::StartProfiling(const char* title, |  457 bool CpuProfilesCollection::StartProfiling(const char* title, | 
|  487                                            bool record_samples) { |  458                                            bool record_samples) { | 
|  488   current_profiles_semaphore_.Wait(); |  459   current_profiles_semaphore_.Wait(); | 
|  489   if (current_profiles_.length() >= kMaxSimultaneousProfiles) { |  460   if (current_profiles_.length() >= kMaxSimultaneousProfiles) { | 
|  490     current_profiles_semaphore_.Signal(); |  461     current_profiles_semaphore_.Signal(); | 
|  491     return false; |  462     return false; | 
|  492   } |  463   } | 
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  549   // As starting / stopping profiles is rare relatively to this |  520   // As starting / stopping profiles is rare relatively to this | 
|  550   // method, we don't bother minimizing the duration of lock holding, |  521   // method, we don't bother minimizing the duration of lock holding, | 
|  551   // e.g. copying contents of the list to a local vector. |  522   // e.g. copying contents of the list to a local vector. | 
|  552   current_profiles_semaphore_.Wait(); |  523   current_profiles_semaphore_.Wait(); | 
|  553   for (int i = 0; i < current_profiles_.length(); ++i) { |  524   for (int i = 0; i < current_profiles_.length(); ++i) { | 
|  554     current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); |  525     current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); | 
|  555   } |  526   } | 
|  556   current_profiles_semaphore_.Signal(); |  527   current_profiles_semaphore_.Signal(); | 
|  557 } |  528 } | 
|  558  |  529  | 
 |  530 CodeEntry* CpuProfilesCollection::NewCodeEntry( | 
 |  531     CodeEventListener::LogEventsAndTags tag, const char* name, | 
 |  532     const char* name_prefix, const char* resource_name, int line_number, | 
 |  533     int column_number, JITLineInfoTable* line_info, Address instruction_start) { | 
 |  534   CodeEntry* code_entry = | 
 |  535       new CodeEntry(tag, name, name_prefix, resource_name, line_number, | 
 |  536                     column_number, line_info, instruction_start); | 
 |  537   code_entries_.Add(code_entry); | 
 |  538   return code_entry; | 
 |  539 } | 
 |  540  | 
 |  541  | 
 |  542 const char* const ProfileGenerator::kProgramEntryName = | 
 |  543     "(program)"; | 
 |  544 const char* const ProfileGenerator::kIdleEntryName = | 
 |  545     "(idle)"; | 
 |  546 const char* const ProfileGenerator::kGarbageCollectorEntryName = | 
 |  547     "(garbage collector)"; | 
 |  548 const char* const ProfileGenerator::kUnresolvedFunctionName = | 
 |  549     "(unresolved function)"; | 
 |  550  | 
|  559 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |  551 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 
|  560     : profiles_(profiles) {} |  552     : profiles_(profiles), | 
 |  553       program_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG, | 
 |  554                                             kProgramEntryName)), | 
 |  555       idle_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG, | 
 |  556                                          kIdleEntryName)), | 
 |  557       gc_entry_(profiles->NewCodeEntry(CodeEventListener::BUILTIN_TAG, | 
 |  558                                        kGarbageCollectorEntryName)), | 
 |  559       unresolved_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG, | 
 |  560                                                kUnresolvedFunctionName)) {} | 
|  561  |  561  | 
|  562 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |  562 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 
|  563   std::vector<CodeEntry*> entries; |  563   std::vector<CodeEntry*> entries; | 
|  564   // Conservatively reserve space for stack frames + pc + function + vm-state. |  564   // Conservatively reserve space for stack frames + pc + function + vm-state. | 
|  565   // There could in fact be more of them because of inlined entries. |  565   // There could in fact be more of them because of inlined entries. | 
|  566   entries.reserve(sample.frames_count + 3); |  566   entries.reserve(sample.frames_count + 3); | 
|  567  |  567  | 
|  568   // The ProfileNode knows nothing about all versions of generated code for |  568   // The ProfileNode knows nothing about all versions of generated code for | 
|  569   // the same JS function. The line number information associated with |  569   // the same JS function. The line number information associated with | 
|  570   // the latest version of generated code is used to find a source line number |  570   // the latest version of generated code is used to find a source line number | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  603  |  603  | 
|  604         if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || |  604         if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || | 
|  605             pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { |  605             pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { | 
|  606           // When current function is either the Function.prototype.apply or the |  606           // When current function is either the Function.prototype.apply or the | 
|  607           // Function.prototype.call builtin the top frame is either frame of |  607           // Function.prototype.call builtin the top frame is either frame of | 
|  608           // the calling JS function or internal frame. |  608           // the calling JS function or internal frame. | 
|  609           // In the latter case we know the caller for sure but in the |  609           // In the latter case we know the caller for sure but in the | 
|  610           // former case we don't so we simply replace the frame with |  610           // former case we don't so we simply replace the frame with | 
|  611           // 'unresolved' entry. |  611           // 'unresolved' entry. | 
|  612           if (!sample.has_external_callback) { |  612           if (!sample.has_external_callback) { | 
|  613             entries.push_back(CodeEntry::unresolved_entry()); |  613             entries.push_back(unresolved_entry_); | 
|  614           } |  614           } | 
|  615         } |  615         } | 
|  616       } |  616       } | 
|  617     } |  617     } | 
|  618  |  618  | 
|  619     for (const Address *stack_pos = sample.stack, |  619     for (const Address *stack_pos = sample.stack, | 
|  620                        *stack_end = stack_pos + sample.frames_count; |  620                        *stack_end = stack_pos + sample.frames_count; | 
|  621          stack_pos != stack_end; ++stack_pos) { |  621          stack_pos != stack_end; ++stack_pos) { | 
|  622       CodeEntry* entry = code_map_.FindEntry(*stack_pos); |  622       CodeEntry* entry = code_map_.FindEntry(*stack_pos); | 
|  623  |  623  | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  660   } |  660   } | 
|  661  |  661  | 
|  662   profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, |  662   profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, | 
|  663                                       sample.update_stats); |  663                                       sample.update_stats); | 
|  664 } |  664 } | 
|  665  |  665  | 
|  666  |  666  | 
|  667 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { |  667 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { | 
|  668   switch (tag) { |  668   switch (tag) { | 
|  669     case GC: |  669     case GC: | 
|  670       return CodeEntry::gc_entry(); |  670       return gc_entry_; | 
|  671     case JS: |  671     case JS: | 
|  672     case COMPILER: |  672     case COMPILER: | 
|  673     // DOM events handlers are reported as OTHER / EXTERNAL entries. |  673     // DOM events handlers are reported as OTHER / EXTERNAL entries. | 
|  674     // To avoid confusing people, let's put all these entries into |  674     // To avoid confusing people, let's put all these entries into | 
|  675     // one bucket. |  675     // one bucket. | 
|  676     case OTHER: |  676     case OTHER: | 
|  677     case EXTERNAL: |  677     case EXTERNAL: | 
|  678       return CodeEntry::program_entry(); |  678       return program_entry_; | 
|  679     case IDLE: |  679     case IDLE: | 
|  680       return CodeEntry::idle_entry(); |  680       return idle_entry_; | 
|  681     default: return NULL; |  681     default: return NULL; | 
|  682   } |  682   } | 
|  683 } |  683 } | 
|  684  |  684  | 
|  685 }  // namespace internal |  685 }  // namespace internal | 
|  686 }  // namespace v8 |  686 }  // namespace v8 | 
| OLD | NEW |