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 start;
57   CodeEntry* entry;
58   unsigned size;
59 
60   INLINE(void UpdateCodeMap(CodeMap* code_map));
61 };
62 
63 
64 class CodeMoveEventRecord : public CodeEventRecord {
65  public:
66   Address from;
67   Address to;
68 
69   INLINE(void UpdateCodeMap(CodeMap* code_map));
70 };
71 
72 
73 class CodeDisableOptEventRecord : public CodeEventRecord {
74  public:
75   Address start;
76   const char* bailout_reason;
77 
78   INLINE(void UpdateCodeMap(CodeMap* code_map));
79 };
80 
81 
82 class CodeDeoptEventRecord : public CodeEventRecord {
83  public:
84   Address start;
85   const char* deopt_reason;
86   int deopt_id;
87   void* pc;
88   int fp_to_sp_delta;
89 
90   INLINE(void UpdateCodeMap(CodeMap* code_map));
91 };
92 
93 
94 class ReportBuiltinEventRecord : public CodeEventRecord {
95  public:
96   Address start;
97   Builtins::Name builtin_id;
98 
99   INLINE(void UpdateCodeMap(CodeMap* code_map));
100 };
101 
102 
103 class TickSampleEventRecord {
104  public:
105   // The parameterless constructor is used when we dequeue data from
106   // the ticks buffer.
TickSampleEventRecord()107   TickSampleEventRecord() { }
TickSampleEventRecord(unsigned order)108   explicit TickSampleEventRecord(unsigned order) : order(order) { }
109 
110   unsigned order;
111   TickSample sample;
112 };
113 
114 
115 class CodeEventsContainer {
116  public:
117   explicit CodeEventsContainer(
118       CodeEventRecord::Type type = CodeEventRecord::NONE) {
119     generic.type = type;
120   }
121   union  {
122     CodeEventRecord generic;
123 #define DECLARE_CLASS(ignore, type) type type##_;
124     CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
125 #undef DECLARE_CLASS
126   };
127 };
128 
129 
130 // This class implements both the profile events processor thread and
131 // methods called by event producers: VM and stack sampler threads.
132 class ProfilerEventsProcessor : public base::Thread {
133  public:
134   ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
135                           base::TimeDelta period);
136   virtual ~ProfilerEventsProcessor();
137 
138   // Thread control.
139   virtual void Run();
140   void StopSynchronously();
INLINE(bool running ())141   INLINE(bool running()) { return !!base::NoBarrier_Load(&running_); }
142   void Enqueue(const CodeEventsContainer& event);
143 
144   // Puts current stack into tick sample events buffer.
145   void AddCurrentStack(Isolate* isolate, bool update_stats = false);
146   void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta);
147 
148   // Tick sample events are filled directly in the buffer of the circular
149   // queue (because the structure is of fixed width, but usually not all
150   // stack frame entries are filled.) This method returns a pointer to the
151   // next record of the buffer.
152   inline TickSample* StartTickSample();
153   inline void FinishTickSample();
154 
155   // SamplingCircularQueue has stricter alignment requirements than a normal new
156   // can fulfil, so we need to provide our own new/delete here.
157   void* operator new(size_t size);
158   void operator delete(void* ptr);
159 
sampler()160   sampler::Sampler* sampler() { return sampler_.get(); }
161 
162  private:
163   // Called from events processing thread (Run() method.)
164   bool ProcessCodeEvent();
165 
166   enum SampleProcessingResult {
167     OneSampleProcessed,
168     FoundSampleForNextCodeEvent,
169     NoSamplesInQueue
170   };
171   SampleProcessingResult ProcessOneSample();
172 
173   ProfileGenerator* generator_;
174   std::unique_ptr<sampler::Sampler> sampler_;
175   base::Atomic32 running_;
176   const base::TimeDelta period_;  // Samples & code events processing period.
177   LockedQueue<CodeEventsContainer> events_buffer_;
178   static const size_t kTickSampleBufferSize = 1 * MB;
179   static const size_t kTickSampleQueueLength =
180       kTickSampleBufferSize / sizeof(TickSampleEventRecord);
181   SamplingCircularQueue<TickSampleEventRecord,
182                         kTickSampleQueueLength> ticks_buffer_;
183   LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
184   base::AtomicNumber<unsigned> last_code_event_id_;
185   unsigned last_processed_code_event_id_;
186 };
187 
188 class CpuProfiler : public CodeEventObserver {
189  public:
190   explicit CpuProfiler(Isolate* isolate);
191 
192   CpuProfiler(Isolate* isolate, CpuProfilesCollection* profiles,
193               ProfileGenerator* test_generator,
194               ProfilerEventsProcessor* test_processor);
195 
196   ~CpuProfiler() override;
197 
198   void set_sampling_interval(base::TimeDelta value);
199   void CollectSample();
200   void StartProfiling(const char* title, bool record_samples = false);
201   void StartProfiling(String* title, bool record_samples);
202   CpuProfile* StopProfiling(const char* title);
203   CpuProfile* StopProfiling(String* title);
204   int GetProfilesCount();
205   CpuProfile* GetProfile(int index);
206   void DeleteAllProfiles();
207   void DeleteProfile(CpuProfile* profile);
208 
209   void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
210 
is_profiling()211   bool is_profiling() const { return is_profiling_; }
212 
generator()213   ProfileGenerator* generator() const { return generator_.get(); }
processor()214   ProfilerEventsProcessor* processor() const { return processor_.get(); }
isolate()215   Isolate* isolate() const { return isolate_; }
216 
217  private:
218   void StartProcessorIfNotStarted();
219   void StopProcessorIfLastProfile(const char* title);
220   void StopProcessor();
221   void ResetProfiles();
222   void LogBuiltins();
223   void CreateEntriesForRuntimeCallStats();
224 
225   Isolate* const isolate_;
226   base::TimeDelta sampling_interval_;
227   std::unique_ptr<CpuProfilesCollection> profiles_;
228   std::unique_ptr<ProfileGenerator> generator_;
229   std::unique_ptr<ProfilerEventsProcessor> processor_;
230   std::vector<std::unique_ptr<CodeEntry>> static_entries_;
231   bool saved_is_logging_;
232   bool is_profiling_;
233 
234   DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
235 };
236 
237 }  // namespace internal
238 }  // namespace v8
239 
240 
241 #endif  // V8_PROFILER_CPU_PROFILER_H_
242