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