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