OLD | NEW |
| (Empty) |
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/compiler.h" | |
13 #include "src/sampler.h" | |
14 #include "src/unbound-queue.h" | |
15 | |
16 namespace v8 { | |
17 namespace internal { | |
18 | |
19 // Forward declarations. | |
20 class CodeEntry; | |
21 class CodeMap; | |
22 class CompilationInfo; | |
23 class CpuProfile; | |
24 class CpuProfilesCollection; | |
25 class ProfileGenerator; | |
26 | |
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) | |
33 | |
34 | |
35 class CodeEventRecord { | |
36 public: | |
37 #define DECLARE_TYPE(type, ignore) type, | |
38 enum Type { | |
39 NONE = 0, | |
40 CODE_EVENTS_TYPE_LIST(DECLARE_TYPE) | |
41 NUMBER_OF_TYPES | |
42 }; | |
43 #undef DECLARE_TYPE | |
44 | |
45 Type type; | |
46 mutable unsigned order; | |
47 }; | |
48 | |
49 | |
50 class CodeCreateEventRecord : public CodeEventRecord { | |
51 public: | |
52 Address start; | |
53 CodeEntry* entry; | |
54 unsigned size; | |
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 CodeDeoptEventRecord : public CodeEventRecord { | |
79 public: | |
80 Address start; | |
81 const char* deopt_reason; | |
82 SourcePosition position; | |
83 size_t pc_offset; | |
84 | |
85 INLINE(void UpdateCodeMap(CodeMap* code_map)); | |
86 }; | |
87 | |
88 | |
89 class ReportBuiltinEventRecord : public CodeEventRecord { | |
90 public: | |
91 Address start; | |
92 Builtins::Name builtin_id; | |
93 | |
94 INLINE(void UpdateCodeMap(CodeMap* code_map)); | |
95 }; | |
96 | |
97 | |
98 class TickSampleEventRecord { | |
99 public: | |
100 // The parameterless constructor is used when we dequeue data from | |
101 // the ticks buffer. | |
102 TickSampleEventRecord() { } | |
103 explicit TickSampleEventRecord(unsigned order) : order(order) { } | |
104 | |
105 unsigned order; | |
106 TickSample sample; | |
107 }; | |
108 | |
109 | |
110 class CodeEventsContainer { | |
111 public: | |
112 explicit CodeEventsContainer( | |
113 CodeEventRecord::Type type = CodeEventRecord::NONE) { | |
114 generic.type = type; | |
115 } | |
116 union { | |
117 CodeEventRecord generic; | |
118 #define DECLARE_CLASS(ignore, type) type type##_; | |
119 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS) | |
120 #undef DECLARE_TYPE | |
121 }; | |
122 }; | |
123 | |
124 | |
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 { | |
128 public: | |
129 ProfilerEventsProcessor(ProfileGenerator* generator, | |
130 Sampler* sampler, | |
131 base::TimeDelta period); | |
132 virtual ~ProfilerEventsProcessor(); | |
133 | |
134 // Thread control. | |
135 virtual void Run(); | |
136 void StopSynchronously(); | |
137 INLINE(bool running()) { return !!base::NoBarrier_Load(&running_); } | |
138 void Enqueue(const CodeEventsContainer& event); | |
139 | |
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); | |
143 | |
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(); | |
150 | |
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); | |
155 | |
156 private: | |
157 // Called from events processing thread (Run() method.) | |
158 bool ProcessCodeEvent(); | |
159 | |
160 enum SampleProcessingResult { | |
161 OneSampleProcessed, | |
162 FoundSampleForNextCodeEvent, | |
163 NoSamplesInQueue | |
164 }; | |
165 SampleProcessingResult ProcessOneSample(); | |
166 | |
167 ProfileGenerator* generator_; | |
168 Sampler* sampler_; | |
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_; | |
181 }; | |
182 | |
183 | |
184 #define PROFILE(IsolateGetter, Call) \ | |
185 do { \ | |
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()) { \ | |
190 logger->Call; \ | |
191 } \ | |
192 } while (false) | |
193 | |
194 | |
195 class CpuProfiler : public CodeEventListener { | |
196 public: | |
197 explicit CpuProfiler(Isolate* isolate); | |
198 | |
199 CpuProfiler(Isolate* isolate, | |
200 CpuProfilesCollection* test_collection, | |
201 ProfileGenerator* test_generator, | |
202 ProfilerEventsProcessor* test_processor); | |
203 | |
204 virtual ~CpuProfiler(); | |
205 | |
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); | |
215 | |
216 // Invoked from stack sampler (thread or signal handler.) | |
217 inline TickSample* StartTickSample(); | |
218 inline void FinishTickSample(); | |
219 | |
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) {} | |
245 | |
246 INLINE(bool is_profiling() const) { return is_profiling_; } | |
247 bool* is_profiling_address() { | |
248 return &is_profiling_; | |
249 } | |
250 | |
251 ProfileGenerator* generator() const { return generator_; } | |
252 ProfilerEventsProcessor* processor() const { return processor_; } | |
253 Isolate* isolate() const { return isolate_; } | |
254 | |
255 private: | |
256 void StartProcessorIfNotStarted(); | |
257 void StopProcessorIfLastProfile(const char* title); | |
258 void StopProcessor(); | |
259 void ResetProfiles(); | |
260 void LogBuiltins(); | |
261 | |
262 Isolate* isolate_; | |
263 base::TimeDelta sampling_interval_; | |
264 CpuProfilesCollection* profiles_; | |
265 ProfileGenerator* generator_; | |
266 ProfilerEventsProcessor* processor_; | |
267 bool saved_is_logging_; | |
268 bool is_profiling_; | |
269 | |
270 DISALLOW_COPY_AND_ASSIGN(CpuProfiler); | |
271 }; | |
272 | |
273 } } // namespace v8::internal | |
274 | |
275 | |
276 #endif // V8_CPU_PROFILER_H_ | |
OLD | NEW |