LCOV - code coverage report
Current view: top level - src/profiler - profile-generator.h (source / functions) Hit Total Coverage
Test: app.info Lines: 35 35 100.0 %
Date: 2017-10-20 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // Copyright 2011 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             : #ifndef V8_PROFILER_PROFILE_GENERATOR_H_
       6             : #define V8_PROFILER_PROFILE_GENERATOR_H_
       7             : 
       8             : #include <map>
       9             : #include <vector>
      10             : 
      11             : #include "src/allocation.h"
      12             : #include "src/base/hashmap.h"
      13             : #include "src/log.h"
      14             : #include "src/profiler/strings-storage.h"
      15             : #include "src/source-position.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : 
      20             : struct TickSample;
      21             : 
      22             : // Provides a mapping from the offsets within generated code to
      23             : // the source line.
      24             : class JITLineInfoTable : public Malloced {
      25             :  public:
      26             :   JITLineInfoTable();
      27             :   ~JITLineInfoTable();
      28             : 
      29             :   void SetPosition(int pc_offset, int line);
      30             :   int GetSourceLineNumber(int pc_offset) const;
      31             : 
      32             :   bool empty() const { return pc_offset_map_.empty(); }
      33             : 
      34             :  private:
      35             :   // pc_offset -> source line
      36             :   typedef std::map<int, int> PcOffsetMap;
      37             :   PcOffsetMap pc_offset_map_;
      38             :   DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable);
      39             : };
      40             : 
      41             : 
      42             : class CodeEntry {
      43             :  public:
      44             :   // CodeEntry doesn't own name strings, just references them.
      45             :   inline CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
      46             :                    const char* name_prefix = CodeEntry::kEmptyNamePrefix,
      47             :                    const char* resource_name = CodeEntry::kEmptyResourceName,
      48             :                    int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
      49             :                    int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
      50             :                    JITLineInfoTable* line_info = nullptr,
      51             :                    Address instruction_start = nullptr);
      52             :   ~CodeEntry();
      53             : 
      54             :   const char* name_prefix() const { return name_prefix_; }
      55         382 :   bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
      56             :   const char* name() const { return name_; }
      57             :   const char* resource_name() const { return resource_name_; }
      58             :   int line_number() const { return line_number_; }
      59             :   int column_number() const { return column_number_; }
      60             :   const JITLineInfoTable* line_info() const { return line_info_; }
      61             :   int script_id() const { return script_id_; }
      62        1528 :   void set_script_id(int script_id) { script_id_ = script_id; }
      63             :   int position() const { return position_; }
      64        1528 :   void set_position(int position) { position_ = position; }
      65           8 :   void set_bailout_reason(const char* bailout_reason) {
      66        1536 :     bailout_reason_ = bailout_reason;
      67           8 :   }
      68             :   const char* bailout_reason() const { return bailout_reason_; }
      69             : 
      70           9 :   void set_deopt_info(const char* deopt_reason, int deopt_id) {
      71             :     DCHECK(!has_deopt_info());
      72           9 :     deopt_reason_ = deopt_reason;
      73           9 :     deopt_id_ = deopt_id;
      74           9 :   }
      75             :   CpuProfileDeoptInfo GetDeoptInfo();
      76             :   bool has_deopt_info() const { return deopt_id_ != kNoDeoptimizationId; }
      77             :   void clear_deopt_info() {
      78           6 :     deopt_reason_ = kNoDeoptReason;
      79           6 :     deopt_id_ = kNoDeoptimizationId;
      80             :   }
      81             : 
      82             :   void FillFunctionInfo(SharedFunctionInfo* shared);
      83             : 
      84             :   void SetBuiltinId(Builtins::Name id);
      85             :   Builtins::Name builtin_id() const {
      86             :     return BuiltinIdField::decode(bit_field_);
      87             :   }
      88             : 
      89             :   uint32_t GetHash() const;
      90             :   bool IsSameFunctionAs(CodeEntry* entry) const;
      91             : 
      92             :   int GetSourceLine(int pc_offset) const;
      93             : 
      94             :   void AddInlineStack(int pc_offset, std::vector<CodeEntry*> inline_stack);
      95             :   const std::vector<CodeEntry*>* GetInlineStack(int pc_offset) const;
      96             : 
      97             :   void AddDeoptInlinedFrames(int deopt_id, std::vector<CpuProfileDeoptFrame>);
      98             :   bool HasDeoptInlinedFramesFor(int deopt_id) const;
      99             : 
     100             :   Address instruction_start() const { return instruction_start_; }
     101             :   CodeEventListener::LogEventsAndTags tag() const {
     102             :     return TagField::decode(bit_field_);
     103             :   }
     104             : 
     105             :   static const char* const kEmptyNamePrefix;
     106             :   static const char* const kEmptyResourceName;
     107             :   static const char* const kEmptyBailoutReason;
     108             :   static const char* const kNoDeoptReason;
     109             : 
     110             :   static const char* const kProgramEntryName;
     111             :   static const char* const kIdleEntryName;
     112             :   static const char* const kGarbageCollectorEntryName;
     113             :   // Used to represent frames for which we have no reliable way to
     114             :   // detect function.
     115             :   static const char* const kUnresolvedFunctionName;
     116             : 
     117             :   V8_INLINE static CodeEntry* program_entry() {
     118        1807 :     return kProgramEntry.Pointer();
     119             :   }
     120          15 :   V8_INLINE static CodeEntry* idle_entry() { return kIdleEntry.Pointer(); }
     121         785 :   V8_INLINE static CodeEntry* gc_entry() { return kGCEntry.Pointer(); }
     122             :   V8_INLINE static CodeEntry* unresolved_entry() {
     123           1 :     return kUnresolvedEntry.Pointer();
     124             :   }
     125             : 
     126             :  private:
     127             :   struct ProgramEntryCreateTrait {
     128             :     static CodeEntry* Create();
     129             :   };
     130             :   struct IdleEntryCreateTrait {
     131             :     static CodeEntry* Create();
     132             :   };
     133             :   struct GCEntryCreateTrait {
     134             :     static CodeEntry* Create();
     135             :   };
     136             :   struct UnresolvedEntryCreateTrait {
     137             :     static CodeEntry* Create();
     138             :   };
     139             : 
     140             :   static base::LazyDynamicInstance<CodeEntry, ProgramEntryCreateTrait>::type
     141             :       kProgramEntry;
     142             :   static base::LazyDynamicInstance<CodeEntry, IdleEntryCreateTrait>::type
     143             :       kIdleEntry;
     144             :   static base::LazyDynamicInstance<CodeEntry, GCEntryCreateTrait>::type
     145             :       kGCEntry;
     146             :   static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type
     147             :       kUnresolvedEntry;
     148             : 
     149             :   class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {};
     150             :   class BuiltinIdField : public BitField<Builtins::Name, 8, 24> {};
     151             : 
     152             :   uint32_t bit_field_;
     153             :   const char* name_prefix_;
     154             :   const char* name_;
     155             :   const char* resource_name_;
     156             :   int line_number_;
     157             :   int column_number_;
     158             :   int script_id_;
     159             :   int position_;
     160             :   const char* bailout_reason_;
     161             :   const char* deopt_reason_;
     162             :   int deopt_id_;
     163             :   JITLineInfoTable* line_info_;
     164             :   Address instruction_start_;
     165             :   // Should be an unordered_map, but it doesn't currently work on Win & MacOS.
     166             :   std::map<int, std::vector<CodeEntry*>> inline_locations_;
     167             :   std::map<int, std::vector<CpuProfileDeoptFrame>> deopt_inlined_frames_;
     168             : 
     169             :   DISALLOW_COPY_AND_ASSIGN(CodeEntry);
     170             : };
     171             : 
     172             : 
     173             : class ProfileTree;
     174             : 
     175        6198 : class ProfileNode {
     176             :  public:
     177             :   inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent);
     178             : 
     179             :   ProfileNode* FindChild(CodeEntry* entry);
     180             :   ProfileNode* FindOrAddChild(CodeEntry* entry);
     181       32323 :   void IncrementSelfTicks() { ++self_ticks_; }
     182             :   void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
     183             :   void IncrementLineTicks(int src_line);
     184             : 
     185             :   CodeEntry* entry() const { return entry_; }
     186             :   unsigned self_ticks() const { return self_ticks_; }
     187        9525 :   const std::vector<ProfileNode*>* children() const { return &children_list_; }
     188             :   unsigned id() const { return id_; }
     189             :   unsigned function_id() const;
     190             :   ProfileNode* parent() const { return parent_; }
     191         103 :   unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
     192             :   bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
     193             :                     unsigned int length) const;
     194             :   void CollectDeoptInfo(CodeEntry* entry);
     195             :   const std::vector<CpuProfileDeoptInfo>& deopt_infos() const {
     196             :     return deopt_infos_;
     197             :   }
     198             :   Isolate* isolate() const;
     199             : 
     200             :   void Print(int indent);
     201             : 
     202       78751 :   static bool CodeEntriesMatch(void* entry1, void* entry2) {
     203             :     return reinterpret_cast<CodeEntry*>(entry1)
     204       78751 :         ->IsSameFunctionAs(reinterpret_cast<CodeEntry*>(entry2));
     205             :   }
     206             : 
     207             :  private:
     208       80989 :   static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); }
     209             : 
     210       29545 :   static bool LineTickMatch(void* a, void* b) { return a == b; }
     211             : 
     212             :   ProfileTree* tree_;
     213             :   CodeEntry* entry_;
     214             :   unsigned self_ticks_;
     215             :   // Mapping from CodeEntry* to ProfileNode*
     216             :   base::CustomMatcherHashMap children_;
     217             :   std::vector<ProfileNode*> children_list_;
     218             :   ProfileNode* parent_;
     219             :   unsigned id_;
     220             :   base::CustomMatcherHashMap line_ticks_;
     221             : 
     222             :   std::vector<CpuProfileDeoptInfo> deopt_infos_;
     223             : 
     224             :   DISALLOW_COPY_AND_ASSIGN(ProfileNode);
     225             : };
     226             : 
     227             : 
     228             : class ProfileTree {
     229             :  public:
     230             :   explicit ProfileTree(Isolate* isolate);
     231             :   ~ProfileTree();
     232             : 
     233             :   ProfileNode* AddPathFromEnd(
     234             :       const std::vector<CodeEntry*>& path,
     235             :       int src_line = v8::CpuProfileNode::kNoLineNumberInfo,
     236             :       bool update_stats = true);
     237             :   ProfileNode* root() const { return root_; }
     238        3099 :   unsigned next_node_id() { return next_node_id_++; }
     239             :   unsigned GetFunctionId(const ProfileNode* node);
     240             : 
     241             :   void Print() {
     242          59 :     root_->Print(0);
     243             :   }
     244             : 
     245             :   Isolate* isolate() const { return isolate_; }
     246             : 
     247        3099 :   void EnqueueNode(const ProfileNode* node) { pending_nodes_.push_back(node); }
     248       32434 :   size_t pending_nodes_count() const { return pending_nodes_.size(); }
     249             :   std::vector<const ProfileNode*> TakePendingNodes() {
     250             :     return std::move(pending_nodes_);
     251             :   }
     252             : 
     253             :  private:
     254             :   template <typename Callback>
     255             :   void TraverseDepthFirst(Callback* callback);
     256             : 
     257             :   std::vector<const ProfileNode*> pending_nodes_;
     258             : 
     259             :   CodeEntry root_entry_;
     260             :   unsigned next_node_id_;
     261             :   ProfileNode* root_;
     262             :   Isolate* isolate_;
     263             : 
     264             :   unsigned next_function_id_;
     265             :   base::CustomMatcherHashMap function_ids_;
     266             : 
     267             :   DISALLOW_COPY_AND_ASSIGN(ProfileTree);
     268             : };
     269             : 
     270             : 
     271        1830 : class CpuProfile {
     272             :  public:
     273             :   CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples);
     274             : 
     275             :   // Add pc -> ... -> main() call path to the profile.
     276             :   void AddPath(base::TimeTicks timestamp, const std::vector<CodeEntry*>& path,
     277             :                int src_line, bool update_stats);
     278             :   void FinishProfile();
     279             : 
     280             :   const char* title() const { return title_; }
     281             :   const ProfileTree* top_down() const { return &top_down_; }
     282             : 
     283       16004 :   int samples_count() const { return static_cast<int>(samples_.size()); }
     284       16012 :   ProfileNode* sample(int index) const { return samples_.at(index); }
     285        7988 :   base::TimeTicks sample_timestamp(int index) const {
     286       15976 :     return timestamps_.at(index);
     287             :   }
     288             : 
     289             :   base::TimeTicks start_time() const { return start_time_; }
     290             :   base::TimeTicks end_time() const { return end_time_; }
     291             :   CpuProfiler* cpu_profiler() const { return profiler_; }
     292             : 
     293             :   void UpdateTicksScale();
     294             : 
     295             :   void Print();
     296             : 
     297             :  private:
     298             :   void StreamPendingTraceEvents();
     299             : 
     300             :   const char* title_;
     301             :   bool record_samples_;
     302             :   base::TimeTicks start_time_;
     303             :   base::TimeTicks end_time_;
     304             :   std::vector<ProfileNode*> samples_;
     305             :   std::vector<base::TimeTicks> timestamps_;
     306             :   ProfileTree top_down_;
     307             :   CpuProfiler* const profiler_;
     308             :   size_t streaming_next_sample_;
     309             : 
     310             :   DISALLOW_COPY_AND_ASSIGN(CpuProfile);
     311             : };
     312             : 
     313             : class CodeMap {
     314             :  public:
     315             :   CodeMap() {}
     316             : 
     317             :   void AddCode(Address addr, CodeEntry* entry, unsigned size);
     318             :   void MoveCode(Address from, Address to);
     319             :   CodeEntry* FindEntry(Address addr);
     320             :   void Print();
     321             : 
     322             :  private:
     323             :   struct CodeEntryInfo {
     324             :     CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
     325             :         : entry(an_entry), size(a_size) { }
     326             :     CodeEntry* entry;
     327             :     unsigned size;
     328             :   };
     329             : 
     330             :   void DeleteAllCoveredCode(Address start, Address end);
     331             : 
     332             :   std::map<Address, CodeEntryInfo> code_map_;
     333             : 
     334             :   DISALLOW_COPY_AND_ASSIGN(CodeMap);
     335             : };
     336             : 
     337             : class CpuProfilesCollection {
     338             :  public:
     339             :   explicit CpuProfilesCollection(Isolate* isolate);
     340             :   ~CpuProfilesCollection();
     341             : 
     342      108863 :   void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; }
     343             :   bool StartProfiling(const char* title, bool record_samples);
     344             :   CpuProfile* StopProfiling(const char* title);
     345             :   std::vector<CpuProfile*>* profiles() { return &finished_profiles_; }
     346         392 :   const char* GetName(Name* name) { return resource_names_.GetName(name); }
     347             :   bool IsLastProfile(const char* title);
     348             :   void RemoveProfile(CpuProfile* profile);
     349             : 
     350             :   // Called from profile generator thread.
     351             :   void AddPathToCurrentProfiles(base::TimeTicks timestamp,
     352             :                                 const std::vector<CodeEntry*>& path,
     353             :                                 int src_line, bool update_stats);
     354             : 
     355             :   // Limits the number of profiles that can be simultaneously collected.
     356             :   static const int kMaxSimultaneousProfiles = 100;
     357             : 
     358             :  private:
     359             :   StringsStorage resource_names_;
     360             :   std::vector<CpuProfile*> finished_profiles_;
     361             :   CpuProfiler* profiler_;
     362             : 
     363             :   // Accessed by VM thread and profile generator thread.
     364             :   std::vector<CpuProfile*> current_profiles_;
     365             :   base::Semaphore current_profiles_semaphore_;
     366             : 
     367             :   DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
     368             : };
     369             : 
     370             : 
     371             : class ProfileGenerator {
     372             :  public:
     373             :   explicit ProfileGenerator(CpuProfilesCollection* profiles);
     374             : 
     375             :   void RecordTickSample(const TickSample& sample);
     376             : 
     377             :   CodeMap* code_map() { return &code_map_; }
     378             : 
     379             :  private:
     380             :   CodeEntry* FindEntry(void* address);
     381             :   CodeEntry* EntryForVMState(StateTag tag);
     382             : 
     383             :   CpuProfilesCollection* profiles_;
     384             :   CodeMap code_map_;
     385             : 
     386             :   DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
     387             : };
     388             : 
     389             : 
     390             : }  // namespace internal
     391             : }  // namespace v8
     392             : 
     393             : #endif  // V8_PROFILER_PROFILE_GENERATOR_H_

Generated by: LCOV version 1.10