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
21namespace v8 {
22namespace internal {
23
24// Forward declarations.
25class CodeEntry;
26class CodeMap;
27class CpuProfile;
28class CpuProfilesCollection;
29class 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
39class 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
54class 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
64class CodeMoveEventRecord : public CodeEventRecord {
65 public:
66  Address from;
67  Address to;
68
69  INLINE(void UpdateCodeMap(CodeMap* code_map));
70};
71
72
73class CodeDisableOptEventRecord : public CodeEventRecord {
74 public:
75  Address start;
76  const char* bailout_reason;
77
78  INLINE(void UpdateCodeMap(CodeMap* code_map));
79};
80
81
82class 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
94class ReportBuiltinEventRecord : public CodeEventRecord {
95 public:
96  Address start;
97  Builtins::Name builtin_id;
98
99  INLINE(void UpdateCodeMap(CodeMap* code_map));
100};
101
102
103class TickSampleEventRecord {
104 public:
105  // The parameterless constructor is used when we dequeue data from
106  // the ticks buffer.
107  TickSampleEventRecord() { }
108  explicit TickSampleEventRecord(unsigned order) : order(order) { }
109
110  unsigned order;
111  TickSample sample;
112};
113
114
115class CodeEventsContainer {
116 public:
117  explicit CodeEventsContainer(
118      CodeEventRecord::Type type = CodeEventRecord::NONE) {
119    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.
132class 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
188class 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
224  Isolate* const isolate_;
225  base::TimeDelta sampling_interval_;
226  std::unique_ptr<CpuProfilesCollection> profiles_;
227  std::unique_ptr<ProfileGenerator> generator_;
228  std::unique_ptr<ProfilerEventsProcessor> processor_;
229  bool saved_is_logging_;
230  bool is_profiling_;
231
232  DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
233};
234
235}  // namespace internal
236}  // namespace v8
237
238
239#endif  // V8_PROFILER_CPU_PROFILER_H_
240