blob: a04ee3c3a8f022cba67b97ff61eb1e354e0f741c [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
17namespace v8 {
18namespace internal {
19
20// Forward declarations.
21class CodeEntry;
22class CodeMap;
23class CompilationInfo;
24class CpuProfile;
25class CpuProfilesCollection;
26class 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
36class 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
51class 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
61class CodeMoveEventRecord : public CodeEventRecord {
62 public:
63 Address from;
64 Address to;
65
66 INLINE(void UpdateCodeMap(CodeMap* code_map));
67};
68
69
70class CodeDisableOptEventRecord : public CodeEventRecord {
71 public:
72 Address start;
73 const char* bailout_reason;
74
75 INLINE(void UpdateCodeMap(CodeMap* code_map));
76};
77
78
79class 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
90class ReportBuiltinEventRecord : public CodeEventRecord {
91 public:
92 Address start;
93 Builtins::Name builtin_id;
94
95 INLINE(void UpdateCodeMap(CodeMap* code_map));
96};
97
98
99class TickSampleEventRecord {
100 public:
101 // The parameterless constructor is used when we dequeue data from
102 // the ticks buffer.
103 TickSampleEventRecord() { }
104 explicit TickSampleEventRecord(unsigned order) : order(order) { }
105
106 unsigned order;
107 TickSample sample;
108};
109
110
111class 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.
128class 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();
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.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142 void AddCurrentStack(Isolate* isolate, bool update_stats = false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 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_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100171 const base::TimeDelta period_; // Samples & code events processing period.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 LockedQueue<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 LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
179 AtomicNumber<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
195class 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
Ben Murdochda12d292016-06-02 14:46:10 +0100204 ~CpuProfiler() override;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205
206 void set_sampling_interval(base::TimeDelta value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 void CollectSample();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 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.
Ben Murdochda12d292016-06-02 14:46:10 +0100223 void CallbackEvent(Name* name, Address entry_point) override;
224 void CodeCreateEvent(Logger::LogEventsAndTags tag, AbstractCode* code,
225 const char* comment) override;
226 void CodeCreateEvent(Logger::LogEventsAndTags tag, AbstractCode* code,
227 Name* name) override;
228 void CodeCreateEvent(Logger::LogEventsAndTags tag, AbstractCode* code,
229 SharedFunctionInfo* shared, CompilationInfo* info,
230 Name* script_name) override;
231 void CodeCreateEvent(Logger::LogEventsAndTags tag, AbstractCode* code,
232 SharedFunctionInfo* shared, CompilationInfo* info,
233 Name* script_name, int line, int column) override;
234 void CodeCreateEvent(Logger::LogEventsAndTags tag, AbstractCode* code,
235 int args_count) override;
236 void CodeMovingGCEvent() override {}
237 void CodeMoveEvent(AbstractCode* from, Address to) override;
238 void CodeDisableOptEvent(AbstractCode* code,
239 SharedFunctionInfo* shared) override;
240 void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
241 void GetterCallbackEvent(Name* name, Address entry_point) override;
242 void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
243 void SetterCallbackEvent(Name* name, Address entry_point) override;
244 void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245
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();
Ben Murdochda12d292016-06-02 14:46:10 +0100261 void RecordInliningInfo(CodeEntry* entry, AbstractCode* abstract_code);
262 Name* InferScriptName(Name* name, SharedFunctionInfo* info);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263
264 Isolate* isolate_;
265 base::TimeDelta sampling_interval_;
266 CpuProfilesCollection* profiles_;
267 ProfileGenerator* generator_;
268 ProfilerEventsProcessor* processor_;
269 bool saved_is_logging_;
270 bool is_profiling_;
271
272 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
273};
274
275} // namespace internal
276} // namespace v8
277
278
279#endif // V8_PROFILER_CPU_PROFILER_H_