Line data Source code
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 <memory>
9 :
10 : #include "src/allocation.h"
11 : #include "src/base/atomic-utils.h"
12 : #include "src/base/atomicops.h"
13 : #include "src/base/platform/condition-variable.h"
14 : #include "src/base/platform/mutex.h"
15 : #include "src/base/platform/time.h"
16 : #include "src/isolate.h"
17 : #include "src/libsampler/sampler.h"
18 : #include "src/locked-queue.h"
19 : #include "src/profiler/circular-queue.h"
20 : #include "src/profiler/profiler-listener.h"
21 : #include "src/profiler/tick-sample.h"
22 :
23 : namespace v8 {
24 : namespace internal {
25 :
26 : // Forward declarations.
27 : class CodeEntry;
28 : class CodeMap;
29 : class CpuProfile;
30 : class CpuProfilesCollection;
31 : class ProfileGenerator;
32 :
33 : #define CODE_EVENTS_TYPE_LIST(V) \
34 : V(CODE_CREATION, CodeCreateEventRecord) \
35 : V(CODE_MOVE, CodeMoveEventRecord) \
36 : V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
37 : V(CODE_DEOPT, CodeDeoptEventRecord) \
38 : V(REPORT_BUILTIN, ReportBuiltinEventRecord)
39 :
40 :
41 : class CodeEventRecord {
42 : public:
43 : #define DECLARE_TYPE(type, ignore) type,
44 : enum Type {
45 : NONE = 0,
46 : CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
47 : };
48 : #undef DECLARE_TYPE
49 :
50 : Type type;
51 : mutable unsigned order;
52 : };
53 :
54 :
55 : class CodeCreateEventRecord : public CodeEventRecord {
56 : public:
57 : Address instruction_start;
58 : CodeEntry* entry;
59 : unsigned instruction_size;
60 :
61 : V8_INLINE void UpdateCodeMap(CodeMap* code_map);
62 : };
63 :
64 :
65 : class CodeMoveEventRecord : public CodeEventRecord {
66 : public:
67 : Address from_instruction_start;
68 : Address to_instruction_start;
69 :
70 : V8_INLINE void UpdateCodeMap(CodeMap* code_map);
71 : };
72 :
73 :
74 : class CodeDisableOptEventRecord : public CodeEventRecord {
75 : public:
76 : Address instruction_start;
77 : const char* bailout_reason;
78 :
79 : V8_INLINE void UpdateCodeMap(CodeMap* code_map);
80 : };
81 :
82 :
83 : class CodeDeoptEventRecord : public CodeEventRecord {
84 : public:
85 : Address instruction_start;
86 : const char* deopt_reason;
87 : int deopt_id;
88 : Address pc;
89 : int fp_to_sp_delta;
90 : CpuProfileDeoptFrame* deopt_frames;
91 : int deopt_frame_count;
92 :
93 : V8_INLINE void UpdateCodeMap(CodeMap* code_map);
94 : };
95 :
96 :
97 : class ReportBuiltinEventRecord : public CodeEventRecord {
98 : public:
99 : Address instruction_start;
100 : Builtins::Name builtin_id;
101 :
102 : V8_INLINE void UpdateCodeMap(CodeMap* code_map);
103 : };
104 :
105 :
106 : class TickSampleEventRecord {
107 : public:
108 : // The parameterless constructor is used when we dequeue data from
109 : // the ticks buffer.
110 : TickSampleEventRecord() = default;
111 64081 : explicit TickSampleEventRecord(unsigned order) : order(order) { }
112 :
113 : unsigned order;
114 : TickSample sample;
115 : };
116 :
117 :
118 : class CodeEventsContainer {
119 : public:
120 : explicit CodeEventsContainer(
121 : CodeEventRecord::Type type = CodeEventRecord::NONE) {
122 5477143 : generic.type = type;
123 : }
124 : union {
125 : CodeEventRecord generic;
126 : #define DECLARE_CLASS(ignore, type) type type##_;
127 : CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
128 : #undef DECLARE_CLASS
129 : };
130 : };
131 :
132 :
133 : // This class implements both the profile events processor thread and
134 : // methods called by event producers: VM and stack sampler threads.
135 1614 : class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
136 : public CodeEventObserver {
137 : public:
138 : virtual ~ProfilerEventsProcessor();
139 :
140 : void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
141 :
142 : // Thread control.
143 : void Run() override = 0;
144 : void StopSynchronously();
145 : V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); }
146 : void Enqueue(const CodeEventsContainer& event);
147 :
148 : // Puts current stack into the tick sample events buffer.
149 : void AddCurrentStack(bool update_stats = false);
150 : void AddDeoptStack(Address from, int fp_to_sp_delta);
151 : // Add a sample into the tick sample events buffer. Used for testing.
152 : void AddSample(TickSample sample);
153 :
154 : protected:
155 : ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator);
156 :
157 : // Called from events processing thread (Run() method.)
158 : bool ProcessCodeEvent();
159 :
160 : enum SampleProcessingResult {
161 : OneSampleProcessed,
162 : FoundSampleForNextCodeEvent,
163 : NoSamplesInQueue
164 : };
165 : virtual SampleProcessingResult ProcessOneSample() = 0;
166 :
167 : ProfileGenerator* generator_;
168 : base::Atomic32 running_;
169 : base::ConditionVariable running_cond_;
170 : base::Mutex running_mutex_;
171 : LockedQueue<CodeEventsContainer> events_buffer_;
172 : LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
173 : std::atomic<unsigned> last_code_event_id_;
174 : unsigned last_processed_code_event_id_;
175 : Isolate* isolate_;
176 : };
177 :
178 : class V8_EXPORT_PRIVATE SamplingEventsProcessor
179 : : public ProfilerEventsProcessor {
180 : public:
181 : SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
182 : base::TimeDelta period, bool use_precise_sampling);
183 : ~SamplingEventsProcessor() override;
184 :
185 : // SamplingCircularQueue has stricter alignment requirements than a normal new
186 : // can fulfil, so we need to provide our own new/delete here.
187 : void* operator new(size_t size);
188 : void operator delete(void* ptr);
189 :
190 : void Run() override;
191 :
192 : // Tick sample events are filled directly in the buffer of the circular
193 : // queue (because the structure is of fixed width, but usually not all
194 : // stack frame entries are filled.) This method returns a pointer to the
195 : // next record of the buffer.
196 : // These methods are not thread-safe and should only ever be called by one
197 : // producer (from CpuSampler::SampleStack()). For testing, use AddSample.
198 : inline TickSample* StartTickSample();
199 : inline void FinishTickSample();
200 :
201 : sampler::Sampler* sampler() { return sampler_.get(); }
202 :
203 : private:
204 : SampleProcessingResult ProcessOneSample() override;
205 :
206 : static const size_t kTickSampleBufferSize = 512 * KB;
207 : static const size_t kTickSampleQueueLength =
208 : kTickSampleBufferSize / sizeof(TickSampleEventRecord);
209 : SamplingCircularQueue<TickSampleEventRecord,
210 : kTickSampleQueueLength> ticks_buffer_;
211 : std::unique_ptr<sampler::Sampler> sampler_;
212 : const base::TimeDelta period_; // Samples & code events processing period.
213 : const bool use_precise_sampling_; // Whether or not busy-waiting is used for
214 : // low sampling intervals on Windows.
215 : };
216 :
217 : class V8_EXPORT_PRIVATE CpuProfiler {
218 : public:
219 : explicit CpuProfiler(Isolate* isolate);
220 :
221 : CpuProfiler(Isolate* isolate, CpuProfilesCollection* profiles,
222 : ProfileGenerator* test_generator,
223 : ProfilerEventsProcessor* test_processor);
224 :
225 : ~CpuProfiler();
226 :
227 : static void CollectSample(Isolate* isolate);
228 :
229 : typedef v8::CpuProfilingMode ProfilingMode;
230 :
231 : void set_sampling_interval(base::TimeDelta value);
232 : void set_use_precise_sampling(bool);
233 : void CollectSample();
234 : void StartProfiling(const char* title, bool record_samples = false,
235 : ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
236 : void StartProfiling(String title, bool record_samples, ProfilingMode mode);
237 : CpuProfile* StopProfiling(const char* title);
238 : CpuProfile* StopProfiling(String title);
239 : int GetProfilesCount();
240 : CpuProfile* GetProfile(int index);
241 : void DeleteAllProfiles();
242 : void DeleteProfile(CpuProfile* profile);
243 :
244 : bool is_profiling() const { return is_profiling_; }
245 :
246 : ProfileGenerator* generator() const { return generator_.get(); }
247 : ProfilerEventsProcessor* processor() const { return processor_.get(); }
248 : Isolate* isolate() const { return isolate_; }
249 :
250 : ProfilerListener* profiler_listener_for_test() {
251 : return profiler_listener_.get();
252 : }
253 :
254 : private:
255 : void StartProcessorIfNotStarted();
256 : void StopProcessorIfLastProfile(const char* title);
257 : void StopProcessor();
258 : void ResetProfiles();
259 : void LogBuiltins();
260 : void CreateEntriesForRuntimeCallStats();
261 :
262 : Isolate* const isolate_;
263 : base::TimeDelta sampling_interval_;
264 : bool use_precise_sampling_ = true;
265 : std::unique_ptr<CpuProfilesCollection> profiles_;
266 : std::unique_ptr<ProfileGenerator> generator_;
267 : std::unique_ptr<ProfilerEventsProcessor> processor_;
268 : std::unique_ptr<ProfilerListener> profiler_listener_;
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 : #endif // V8_PROFILER_CPU_PROFILER_H_
|