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 67035 : 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 5451233 : 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 1600 : class ProfilerEventsProcessor : public base::Thread, public CodeEventObserver {
136 : public:
137 : virtual ~ProfilerEventsProcessor();
138 :
139 : void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
140 :
141 : // Thread control.
142 : void Run() override = 0;
143 : void StopSynchronously();
144 : V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); }
145 : void Enqueue(const CodeEventsContainer& event);
146 :
147 : // Puts current stack into the tick sample events buffer.
148 : void AddCurrentStack(bool update_stats = false);
149 : void AddDeoptStack(Address from, int fp_to_sp_delta);
150 : // Add a sample into the tick sample events buffer. Used for testing.
151 : void AddSample(TickSample sample);
152 :
153 : protected:
154 : ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator);
155 :
156 : // Called from events processing thread (Run() method.)
157 : bool ProcessCodeEvent();
158 :
159 : enum SampleProcessingResult {
160 : OneSampleProcessed,
161 : FoundSampleForNextCodeEvent,
162 : NoSamplesInQueue
163 : };
164 : virtual SampleProcessingResult ProcessOneSample() = 0;
165 :
166 : ProfileGenerator* generator_;
167 : base::Atomic32 running_;
168 : base::ConditionVariable running_cond_;
169 : base::Mutex running_mutex_;
170 : LockedQueue<CodeEventsContainer> events_buffer_;
171 : LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
172 : std::atomic<unsigned> last_code_event_id_;
173 : unsigned last_processed_code_event_id_;
174 : Isolate* isolate_;
175 : };
176 :
177 : class SamplingEventsProcessor : public ProfilerEventsProcessor {
178 : public:
179 : SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
180 : base::TimeDelta period);
181 : ~SamplingEventsProcessor() override;
182 :
183 : // SamplingCircularQueue has stricter alignment requirements than a normal new
184 : // can fulfil, so we need to provide our own new/delete here.
185 : void* operator new(size_t size);
186 : void operator delete(void* ptr);
187 :
188 : void Run() override;
189 :
190 : // Tick sample events are filled directly in the buffer of the circular
191 : // queue (because the structure is of fixed width, but usually not all
192 : // stack frame entries are filled.) This method returns a pointer to the
193 : // next record of the buffer.
194 : // These methods are not thread-safe and should only ever be called by one
195 : // producer (from CpuSampler::SampleStack()). For testing, use AddSample.
196 : inline TickSample* StartTickSample();
197 : inline void FinishTickSample();
198 :
199 : sampler::Sampler* sampler() { return sampler_.get(); }
200 :
201 : private:
202 : SampleProcessingResult ProcessOneSample() override;
203 :
204 : static const size_t kTickSampleBufferSize = 512 * KB;
205 : static const size_t kTickSampleQueueLength =
206 : kTickSampleBufferSize / sizeof(TickSampleEventRecord);
207 : SamplingCircularQueue<TickSampleEventRecord,
208 : kTickSampleQueueLength> ticks_buffer_;
209 : std::unique_ptr<sampler::Sampler> sampler_;
210 : const base::TimeDelta period_; // Samples & code events processing period.
211 : };
212 :
213 : class CpuProfiler {
214 : public:
215 : explicit CpuProfiler(Isolate* isolate);
216 :
217 : CpuProfiler(Isolate* isolate, CpuProfilesCollection* profiles,
218 : ProfileGenerator* test_generator,
219 : ProfilerEventsProcessor* test_processor);
220 :
221 : ~CpuProfiler();
222 :
223 : static void CollectSample(Isolate* isolate);
224 :
225 : typedef v8::CpuProfilingMode ProfilingMode;
226 :
227 : void set_sampling_interval(base::TimeDelta value);
228 : void CollectSample();
229 : void StartProfiling(const char* title, bool record_samples = false,
230 : ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
231 : void StartProfiling(String title, bool record_samples, ProfilingMode mode);
232 : CpuProfile* StopProfiling(const char* title);
233 : CpuProfile* StopProfiling(String title);
234 : int GetProfilesCount();
235 : CpuProfile* GetProfile(int index);
236 : void DeleteAllProfiles();
237 : void DeleteProfile(CpuProfile* profile);
238 :
239 : bool is_profiling() const { return is_profiling_; }
240 :
241 : ProfileGenerator* generator() const { return generator_.get(); }
242 : ProfilerEventsProcessor* processor() const { return processor_.get(); }
243 : Isolate* isolate() const { return isolate_; }
244 :
245 : ProfilerListener* profiler_listener_for_test() {
246 : return profiler_listener_.get();
247 : }
248 :
249 : private:
250 : void StartProcessorIfNotStarted();
251 : void StopProcessorIfLastProfile(const char* title);
252 : void StopProcessor();
253 : void ResetProfiles();
254 : void LogBuiltins();
255 : void CreateEntriesForRuntimeCallStats();
256 :
257 : Isolate* const isolate_;
258 : base::TimeDelta sampling_interval_;
259 : std::unique_ptr<CpuProfilesCollection> profiles_;
260 : std::unique_ptr<ProfileGenerator> generator_;
261 : std::unique_ptr<ProfilerEventsProcessor> processor_;
262 : std::unique_ptr<ProfilerListener> profiler_listener_;
263 : bool saved_is_logging_;
264 : bool is_profiling_;
265 :
266 : DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
267 : };
268 :
269 : } // namespace internal
270 : } // namespace v8
271 :
272 : #endif // V8_PROFILER_CPU_PROFILER_H_
|