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 "src/allocation.h"
9 #include "src/atomic-utils.h"
10 #include "src/base/atomicops.h"
11 #include "src/base/platform/time.h"
12 #include "src/compiler.h"
13 #include "src/locked-queue.h"
14 #include "src/profiler/circular-queue.h"
15 #include "src/profiler/sampler.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 // Forward declarations.
21 class CodeEntry;
22 class CodeMap;
23 class CompilationInfo;
24 class CpuProfile;
25 class CpuProfilesCollection;
26 class ProfileGenerator;
27 
28 #define CODE_EVENTS_TYPE_LIST(V)                         \
29   V(CODE_CREATION, CodeCreateEventRecord)                \
30   V(CODE_MOVE, CodeMoveEventRecord)                      \
31   V(CODE_DISABLE_OPT, CodeDisableOptEventRecord)         \
32   V(CODE_DEOPT, CodeDeoptEventRecord)                    \
33   V(REPORT_BUILTIN, ReportBuiltinEventRecord)
34 
35 
36 class CodeEventRecord {
37  public:
38 #define DECLARE_TYPE(type, ignore) type,
39   enum Type {
40     NONE = 0,
41     CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
42     NUMBER_OF_TYPES
43   };
44 #undef DECLARE_TYPE
45 
46   Type type;
47   mutable unsigned order;
48 };
49 
50 
51 class CodeCreateEventRecord : public CodeEventRecord {
52  public:
53   Address start;
54   CodeEntry* entry;
55   unsigned size;
56 
57   INLINE(void UpdateCodeMap(CodeMap* code_map));
58 };
59 
60 
61 class CodeMoveEventRecord : public CodeEventRecord {
62  public:
63   Address from;
64   Address to;
65 
66   INLINE(void UpdateCodeMap(CodeMap* code_map));
67 };
68 
69 
70 class CodeDisableOptEventRecord : public CodeEventRecord {
71  public:
72   Address start;
73   const char* bailout_reason;
74 
75   INLINE(void UpdateCodeMap(CodeMap* code_map));
76 };
77 
78 
79 class CodeDeoptEventRecord : public CodeEventRecord {
80  public:
81   Address start;
82   const char* deopt_reason;
83   SourcePosition position;
84   size_t pc_offset;
85 
86   INLINE(void UpdateCodeMap(CodeMap* code_map));
87 };
88 
89 
90 class ReportBuiltinEventRecord : public CodeEventRecord {
91  public:
92   Address start;
93   Builtins::Name builtin_id;
94 
95   INLINE(void UpdateCodeMap(CodeMap* code_map));
96 };
97 
98 
99 class TickSampleEventRecord {
100  public:
101   // The parameterless constructor is used when we dequeue data from
102   // the ticks buffer.
TickSampleEventRecord()103   TickSampleEventRecord() { }
TickSampleEventRecord(unsigned order)104   explicit TickSampleEventRecord(unsigned order) : order(order) { }
105 
106   unsigned order;
107   TickSample sample;
108 };
109 
110 
111 class CodeEventsContainer {
112  public:
113   explicit CodeEventsContainer(
114       CodeEventRecord::Type type = CodeEventRecord::NONE) {
115     generic.type = type;
116   }
117   union  {
118     CodeEventRecord generic;
119 #define DECLARE_CLASS(ignore, type) type type##_;
120     CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
121 #undef DECLARE_TYPE
122   };
123 };
124 
125 
126 // This class implements both the profile events processor thread and
127 // methods called by event producers: VM and stack sampler threads.
128 class ProfilerEventsProcessor : public base::Thread {
129  public:
130   ProfilerEventsProcessor(ProfileGenerator* generator,
131                           Sampler* sampler,
132                           base::TimeDelta period);
133   virtual ~ProfilerEventsProcessor();
134 
135   // Thread control.
136   virtual void Run();
137   void StopSynchronously();
INLINE(bool running ())138   INLINE(bool running()) { return !!base::NoBarrier_Load(&running_); }
139   void Enqueue(const CodeEventsContainer& event);
140 
141   // Puts current stack into tick sample events buffer.
142   void AddCurrentStack(Isolate* isolate);
143   void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta);
144 
145   // Tick sample events are filled directly in the buffer of the circular
146   // queue (because the structure is of fixed width, but usually not all
147   // stack frame entries are filled.) This method returns a pointer to the
148   // next record of the buffer.
149   inline TickSample* StartTickSample();
150   inline void FinishTickSample();
151 
152   // SamplingCircularQueue has stricter alignment requirements than a normal new
153   // can fulfil, so we need to provide our own new/delete here.
154   void* operator new(size_t size);
155   void operator delete(void* ptr);
156 
157  private:
158   // Called from events processing thread (Run() method.)
159   bool ProcessCodeEvent();
160 
161   enum SampleProcessingResult {
162     OneSampleProcessed,
163     FoundSampleForNextCodeEvent,
164     NoSamplesInQueue
165   };
166   SampleProcessingResult ProcessOneSample();
167 
168   ProfileGenerator* generator_;
169   Sampler* sampler_;
170   base::Atomic32 running_;
171   // Sampling period in microseconds.
172   const base::TimeDelta period_;
173   LockedQueue<CodeEventsContainer> events_buffer_;
174   static const size_t kTickSampleBufferSize = 1 * MB;
175   static const size_t kTickSampleQueueLength =
176       kTickSampleBufferSize / sizeof(TickSampleEventRecord);
177   SamplingCircularQueue<TickSampleEventRecord,
178                         kTickSampleQueueLength> ticks_buffer_;
179   LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
180   AtomicNumber<unsigned> last_code_event_id_;
181   unsigned last_processed_code_event_id_;
182 };
183 
184 
185 #define PROFILE(IsolateGetter, Call)                                        \
186   do {                                                                      \
187     Isolate* cpu_profiler_isolate = (IsolateGetter);                        \
188     v8::internal::Logger* logger = cpu_profiler_isolate->logger();          \
189     CpuProfiler* cpu_profiler = cpu_profiler_isolate->cpu_profiler();       \
190     if (logger->is_logging_code_events() || cpu_profiler->is_profiling()) { \
191       logger->Call;                                                         \
192     }                                                                       \
193   } while (false)
194 
195 
196 class CpuProfiler : public CodeEventListener {
197  public:
198   explicit CpuProfiler(Isolate* isolate);
199 
200   CpuProfiler(Isolate* isolate,
201               CpuProfilesCollection* test_collection,
202               ProfileGenerator* test_generator,
203               ProfilerEventsProcessor* test_processor);
204 
205   virtual ~CpuProfiler();
206 
207   void set_sampling_interval(base::TimeDelta value);
208   void StartProfiling(const char* title, bool record_samples = false);
209   void StartProfiling(String* title, bool record_samples);
210   CpuProfile* StopProfiling(const char* title);
211   CpuProfile* StopProfiling(String* title);
212   int GetProfilesCount();
213   CpuProfile* GetProfile(int index);
214   void DeleteAllProfiles();
215   void DeleteProfile(CpuProfile* profile);
216 
217   // Invoked from stack sampler (thread or signal handler.)
218   inline TickSample* StartTickSample();
219   inline void FinishTickSample();
220 
221   // Must be called via PROFILE macro, otherwise will crash when
222   // profiling is not enabled.
223   virtual void CallbackEvent(Name* name, Address entry_point);
224   virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
225                                Code* code, const char* comment);
226   virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
227                                Code* code, Name* name);
228   virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
229                                SharedFunctionInfo* shared,
230                                CompilationInfo* info, Name* script_name);
231   virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
232                                SharedFunctionInfo* shared,
233                                CompilationInfo* info, Name* script_name,
234                                int line, int column);
235   virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
236                                Code* code, int args_count);
CodeMovingGCEvent()237   virtual void CodeMovingGCEvent() {}
238   virtual void CodeMoveEvent(Address from, Address to);
239   virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
240   virtual void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
241   virtual void CodeDeleteEvent(Address from);
242   virtual void GetterCallbackEvent(Name* name, Address entry_point);
243   virtual void RegExpCodeCreateEvent(Code* code, String* source);
244   virtual void SetterCallbackEvent(Name* name, Address entry_point);
SharedFunctionInfoMoveEvent(Address from,Address to)245   virtual void SharedFunctionInfoMoveEvent(Address from, Address to) {}
246 
INLINE(bool is_profiling ()const)247   INLINE(bool is_profiling() const) { return is_profiling_; }
is_profiling_address()248   bool* is_profiling_address() {
249     return &is_profiling_;
250   }
251 
generator()252   ProfileGenerator* generator() const { return generator_; }
processor()253   ProfilerEventsProcessor* processor() const { return processor_; }
isolate()254   Isolate* isolate() const { return isolate_; }
255 
256  private:
257   void StartProcessorIfNotStarted();
258   void StopProcessorIfLastProfile(const char* title);
259   void StopProcessor();
260   void ResetProfiles();
261   void LogBuiltins();
262 
263   Isolate* isolate_;
264   base::TimeDelta sampling_interval_;
265   CpuProfilesCollection* profiles_;
266   ProfileGenerator* generator_;
267   ProfilerEventsProcessor* processor_;
268   bool saved_is_logging_;
269   bool is_profiling_;
270 
271   DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
272 };
273 
274 }  // namespace internal
275 }  // namespace v8
276 
277 
278 #endif  // V8_PROFILER_CPU_PROFILER_H_
279