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