• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef V8_PROFILER_CPU_PROFILER_H_
6 #define V8_PROFILER_CPU_PROFILER_H_
7 
8 #include <memory>
9 
10 #include "src/allocation.h"
11 #include "src/base/atomic-utils.h"
12 #include "src/base/atomicops.h"
13 #include "src/base/platform/time.h"
14 #include "src/isolate.h"
15 #include "src/libsampler/sampler.h"
16 #include "src/locked-queue.h"
17 #include "src/profiler/circular-queue.h"
18 #include "src/profiler/profiler-listener.h"
19 #include "src/profiler/tick-sample.h"
20 
21 namespace v8 {
22 namespace internal {
23 
24 // Forward declarations.
25 class CodeEntry;
26 class CodeMap;
27 class CpuProfile;
28 class CpuProfilesCollection;
29 class ProfileGenerator;
30 
31 #define CODE_EVENTS_TYPE_LIST(V)                         \
32   V(CODE_CREATION, CodeCreateEventRecord)                \
33   V(CODE_MOVE, CodeMoveEventRecord)                      \
34   V(CODE_DISABLE_OPT, CodeDisableOptEventRecord)         \
35   V(CODE_DEOPT, CodeDeoptEventRecord)                    \
36   V(REPORT_BUILTIN, ReportBuiltinEventRecord)
37 
38 
39 class CodeEventRecord {
40  public:
41 #define DECLARE_TYPE(type, ignore) type,
42   enum Type {
43     NONE = 0,
44     CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
45     NUMBER_OF_TYPES
46   };
47 #undef DECLARE_TYPE
48 
49   Type type;
50   mutable unsigned order;
51 };
52 
53 
54 class CodeCreateEventRecord : public CodeEventRecord {
55  public:
56   Address instruction_start;
57   CodeEntry* entry;
58   unsigned instruction_size;
59 
60   V8_INLINE void UpdateCodeMap(CodeMap* code_map);
61 };
62 
63 
64 class CodeMoveEventRecord : public CodeEventRecord {
65  public:
66   Address from_instruction_start;
67   Address to_instruction_start;
68 
69   V8_INLINE void UpdateCodeMap(CodeMap* code_map);
70 };
71 
72 
73 class CodeDisableOptEventRecord : public CodeEventRecord {
74  public:
75   Address instruction_start;
76   const char* bailout_reason;
77 
78   V8_INLINE void UpdateCodeMap(CodeMap* code_map);
79 };
80 
81 
82 class CodeDeoptEventRecord : public CodeEventRecord {
83  public:
84   Address instruction_start;
85   const char* deopt_reason;
86   int deopt_id;
87   Address pc;
88   int fp_to_sp_delta;
89   CpuProfileDeoptFrame* deopt_frames;
90   int deopt_frame_count;
91 
92   V8_INLINE void UpdateCodeMap(CodeMap* code_map);
93 };
94 
95 
96 class ReportBuiltinEventRecord : public CodeEventRecord {
97  public:
98   Address instruction_start;
99   Builtins::Name builtin_id;
100 
101   V8_INLINE void UpdateCodeMap(CodeMap* code_map);
102 };
103 
104 
105 class TickSampleEventRecord {
106  public:
107   // The parameterless constructor is used when we dequeue data from
108   // the ticks buffer.
TickSampleEventRecord()109   TickSampleEventRecord() { }
TickSampleEventRecord(unsigned order)110   explicit TickSampleEventRecord(unsigned order) : order(order) { }
111 
112   unsigned order;
113   TickSample sample;
114 };
115 
116 
117 class CodeEventsContainer {
118  public:
119   explicit CodeEventsContainer(
120       CodeEventRecord::Type type = CodeEventRecord::NONE) {
121     generic.type = type;
122   }
123   union  {
124     CodeEventRecord generic;
125 #define DECLARE_CLASS(ignore, type) type type##_;
126     CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
127 #undef DECLARE_CLASS
128   };
129 };
130 
131 
132 // This class implements both the profile events processor thread and
133 // methods called by event producers: VM and stack sampler threads.
134 class ProfilerEventsProcessor : public base::Thread {
135  public:
136   ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
137                           base::TimeDelta period);
138   virtual ~ProfilerEventsProcessor();
139 
140   // Thread control.
141   virtual void Run();
142   void StopSynchronously();
running()143   V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); }
144   void Enqueue(const CodeEventsContainer& event);
145 
146   // Puts current stack into tick sample events buffer.
147   void AddCurrentStack(Isolate* isolate, bool update_stats = false);
148   void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta);
149 
150   // Tick sample events are filled directly in the buffer of the circular
151   // queue (because the structure is of fixed width, but usually not all
152   // stack frame entries are filled.) This method returns a pointer to the
153   // next record of the buffer.
154   inline TickSample* StartTickSample();
155   inline void FinishTickSample();
156 
157   // SamplingCircularQueue has stricter alignment requirements than a normal new
158   // can fulfil, so we need to provide our own new/delete here.
159   void* operator new(size_t size);
160   void operator delete(void* ptr);
161 
sampler()162   sampler::Sampler* sampler() { return sampler_.get(); }
163 
164  private:
165   // Called from events processing thread (Run() method.)
166   bool ProcessCodeEvent();
167 
168   enum SampleProcessingResult {
169     OneSampleProcessed,
170     FoundSampleForNextCodeEvent,
171     NoSamplesInQueue
172   };
173   SampleProcessingResult ProcessOneSample();
174 
175   ProfileGenerator* generator_;
176   std::unique_ptr<sampler::Sampler> sampler_;
177   base::Atomic32 running_;
178   const base::TimeDelta period_;  // Samples & code events processing period.
179   LockedQueue<CodeEventsContainer> events_buffer_;
180   static const size_t kTickSampleBufferSize = 1 * MB;
181   static const size_t kTickSampleQueueLength =
182       kTickSampleBufferSize / sizeof(TickSampleEventRecord);
183   SamplingCircularQueue<TickSampleEventRecord,
184                         kTickSampleQueueLength> ticks_buffer_;
185   LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
186   std::atomic<unsigned> last_code_event_id_;
187   unsigned last_processed_code_event_id_;
188 };
189 
190 class CpuProfiler : public CodeEventObserver {
191  public:
192   explicit CpuProfiler(Isolate* isolate);
193 
194   CpuProfiler(Isolate* isolate, CpuProfilesCollection* profiles,
195               ProfileGenerator* test_generator,
196               ProfilerEventsProcessor* test_processor);
197 
198   ~CpuProfiler() override;
199 
200   static void CollectSample(Isolate* isolate);
201 
202   typedef v8::CpuProfilingMode ProfilingMode;
203 
204   void set_sampling_interval(base::TimeDelta value);
205   void CollectSample();
206   void StartProfiling(const char* title, bool record_samples = false,
207                       ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
208   void StartProfiling(String* title, bool record_samples, ProfilingMode mode);
209   CpuProfile* StopProfiling(const char* title);
210   CpuProfile* StopProfiling(String* title);
211   int GetProfilesCount();
212   CpuProfile* GetProfile(int index);
213   void DeleteAllProfiles();
214   void DeleteProfile(CpuProfile* profile);
215 
216   void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
217 
is_profiling()218   bool is_profiling() const { return is_profiling_; }
219 
generator()220   ProfileGenerator* generator() const { return generator_.get(); }
processor()221   ProfilerEventsProcessor* processor() const { return processor_.get(); }
isolate()222   Isolate* isolate() const { return isolate_; }
223 
profiler_listener_for_test()224   ProfilerListener* profiler_listener_for_test() {
225     return profiler_listener_.get();
226   }
227 
228  private:
229   void StartProcessorIfNotStarted();
230   void StopProcessorIfLastProfile(const char* title);
231   void StopProcessor();
232   void ResetProfiles();
233   void LogBuiltins();
234   void CreateEntriesForRuntimeCallStats();
235 
236   Isolate* const isolate_;
237   base::TimeDelta sampling_interval_;
238   std::unique_ptr<CpuProfilesCollection> profiles_;
239   std::unique_ptr<ProfileGenerator> generator_;
240   std::unique_ptr<ProfilerEventsProcessor> processor_;
241   std::unique_ptr<ProfilerListener> profiler_listener_;
242   bool saved_is_logging_;
243   bool is_profiling_;
244 
245   DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
246 };
247 
248 }  // namespace internal
249 }  // namespace v8
250 
251 #endif  // V8_PROFILER_CPU_PROFILER_H_
252