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.
5 #ifndef V8_PROFILER_CPU_PROFILER_H_
6 #define V8_PROFILER_CPU_PROFILER_H_
8 #include "src/allocation.h"
9 #include "src/base/atomicops.h"
10 #include "src/base/platform/time.h"
11 #include "src/compiler.h"
12 #include "src/profiler/circular-queue.h"
13 #include "src/profiler/sampler.h"
14 #include "src/profiler/unbound-queue.h"
19 // Forward declarations.
22 class CompilationInfo;
24 class CpuProfilesCollection;
25 class ProfileGenerator;
27 #define CODE_EVENTS_TYPE_LIST(V) \
28 V(CODE_CREATION, CodeCreateEventRecord) \
29 V(CODE_MOVE, CodeMoveEventRecord) \
30 V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
31 V(CODE_DEOPT, CodeDeoptEventRecord) \
32 V(REPORT_BUILTIN, ReportBuiltinEventRecord)
35 class CodeEventRecord {
37 #define DECLARE_TYPE(type, ignore) type,
40 CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
46 mutable unsigned order;
50 class CodeCreateEventRecord : public CodeEventRecord {
56 INLINE(void UpdateCodeMap(CodeMap* code_map));
60 class CodeMoveEventRecord : public CodeEventRecord {
65 INLINE(void UpdateCodeMap(CodeMap* code_map));
69 class CodeDisableOptEventRecord : public CodeEventRecord {
72 const char* bailout_reason;
74 INLINE(void UpdateCodeMap(CodeMap* code_map));
78 class CodeDeoptEventRecord : public CodeEventRecord {
81 const char* deopt_reason;
82 SourcePosition position;
85 INLINE(void UpdateCodeMap(CodeMap* code_map));
89 class ReportBuiltinEventRecord : public CodeEventRecord {
92 Builtins::Name builtin_id;
94 INLINE(void UpdateCodeMap(CodeMap* code_map));
98 class TickSampleEventRecord {
100 // The parameterless constructor is used when we dequeue data from
102 TickSampleEventRecord() { }
103 explicit TickSampleEventRecord(unsigned order) : order(order) { }
110 class CodeEventsContainer {
112 explicit CodeEventsContainer(
113 CodeEventRecord::Type type = CodeEventRecord::NONE) {
117 CodeEventRecord generic;
118 #define DECLARE_CLASS(ignore, type) type type##_;
119 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
125 // This class implements both the profile events processor thread and
126 // methods called by event producers: VM and stack sampler threads.
127 class ProfilerEventsProcessor : public base::Thread {
129 ProfilerEventsProcessor(ProfileGenerator* generator,
131 base::TimeDelta period);
132 virtual ~ProfilerEventsProcessor();
136 void StopSynchronously();
137 INLINE(bool running()) { return !!base::NoBarrier_Load(&running_); }
138 void Enqueue(const CodeEventsContainer& event);
140 // Puts current stack into tick sample events buffer.
141 void AddCurrentStack(Isolate* isolate);
142 void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta);
144 // Tick sample events are filled directly in the buffer of the circular
145 // queue (because the structure is of fixed width, but usually not all
146 // stack frame entries are filled.) This method returns a pointer to the
147 // next record of the buffer.
148 inline TickSample* StartTickSample();
149 inline void FinishTickSample();
151 // SamplingCircularQueue has stricter alignment requirements than a normal new
152 // can fulfil, so we need to provide our own new/delete here.
153 void* operator new(size_t size);
154 void operator delete(void* ptr);
157 // Called from events processing thread (Run() method.)
158 bool ProcessCodeEvent();
160 enum SampleProcessingResult {
162 FoundSampleForNextCodeEvent,
165 SampleProcessingResult ProcessOneSample();
167 ProfileGenerator* generator_;
169 base::Atomic32 running_;
170 // Sampling period in microseconds.
171 const base::TimeDelta period_;
172 UnboundQueue<CodeEventsContainer> events_buffer_;
173 static const size_t kTickSampleBufferSize = 1 * MB;
174 static const size_t kTickSampleQueueLength =
175 kTickSampleBufferSize / sizeof(TickSampleEventRecord);
176 SamplingCircularQueue<TickSampleEventRecord,
177 kTickSampleQueueLength> ticks_buffer_;
178 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
179 unsigned last_code_event_id_;
180 unsigned last_processed_code_event_id_;
184 #define PROFILE(IsolateGetter, Call) \
186 Isolate* cpu_profiler_isolate = (IsolateGetter); \
187 v8::internal::Logger* logger = cpu_profiler_isolate->logger(); \
188 CpuProfiler* cpu_profiler = cpu_profiler_isolate->cpu_profiler(); \
189 if (logger->is_logging_code_events() || cpu_profiler->is_profiling()) { \
195 class CpuProfiler : public CodeEventListener {
197 explicit CpuProfiler(Isolate* isolate);
199 CpuProfiler(Isolate* isolate,
200 CpuProfilesCollection* test_collection,
201 ProfileGenerator* test_generator,
202 ProfilerEventsProcessor* test_processor);
204 virtual ~CpuProfiler();
206 void set_sampling_interval(base::TimeDelta value);
207 void StartProfiling(const char* title, bool record_samples = false);
208 void StartProfiling(String* title, bool record_samples);
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);
216 // Invoked from stack sampler (thread or signal handler.)
217 inline TickSample* StartTickSample();
218 inline void FinishTickSample();
220 // Must be called via PROFILE macro, otherwise will crash when
221 // profiling is not enabled.
222 virtual void CallbackEvent(Name* name, Address entry_point);
223 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
224 Code* code, const char* comment);
225 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
226 Code* code, Name* name);
227 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
228 SharedFunctionInfo* shared,
229 CompilationInfo* info, Name* script_name);
230 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
231 SharedFunctionInfo* shared,
232 CompilationInfo* info, Name* script_name,
233 int line, int column);
234 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
235 Code* code, int args_count);
236 virtual void CodeMovingGCEvent() {}
237 virtual void CodeMoveEvent(Address from, Address to);
238 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
239 virtual void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
240 virtual void CodeDeleteEvent(Address from);
241 virtual void GetterCallbackEvent(Name* name, Address entry_point);
242 virtual void RegExpCodeCreateEvent(Code* code, String* source);
243 virtual void SetterCallbackEvent(Name* name, Address entry_point);
244 virtual void SharedFunctionInfoMoveEvent(Address from, Address to) {}
246 INLINE(bool is_profiling() const) { return is_profiling_; }
247 bool* is_profiling_address() {
248 return &is_profiling_;
251 ProfileGenerator* generator() const { return generator_; }
252 ProfilerEventsProcessor* processor() const { return processor_; }
253 Isolate* isolate() const { return isolate_; }
256 void StartProcessorIfNotStarted();
257 void StopProcessorIfLastProfile(const char* title);
258 void StopProcessor();
259 void ResetProfiles();
263 base::TimeDelta sampling_interval_;
264 CpuProfilesCollection* profiles_;
265 ProfileGenerator* generator_;
266 ProfilerEventsProcessor* processor_;
267 bool saved_is_logging_;
270 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
273 } } // namespace v8::internal
276 #endif // V8_PROFILER_CPU_PROFILER_H_