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_CPU_PROFILER_H_
6#define V8_CPU_PROFILER_H_
7
8#include "src/allocation.h"
9#include "src/base/atomicops.h"
10#include "src/base/platform/time.h"
11#include "src/circular-queue.h"
12#include "src/sampler.h"
13#include "src/unbound-queue.h"
14
15namespace v8 {
16namespace internal {
17
18// Forward declarations.
19class CodeEntry;
20class CodeMap;
21class CompilationInfo;
22class CpuProfile;
23class CpuProfilesCollection;
24class ProfileGenerator;
25
26#define CODE_EVENTS_TYPE_LIST(V)                                   \
27  V(CODE_CREATION,    CodeCreateEventRecord)                       \
28  V(CODE_MOVE,        CodeMoveEventRecord)                         \
29  V(CODE_DISABLE_OPT, CodeDisableOptEventRecord)                   \
30  V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)           \
31  V(REPORT_BUILTIN,   ReportBuiltinEventRecord)
32
33
34class CodeEventRecord {
35 public:
36#define DECLARE_TYPE(type, ignore) type,
37  enum Type {
38    NONE = 0,
39    CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
40    NUMBER_OF_TYPES
41  };
42#undef DECLARE_TYPE
43
44  Type type;
45  mutable unsigned order;
46};
47
48
49class CodeCreateEventRecord : public CodeEventRecord {
50 public:
51  Address start;
52  CodeEntry* entry;
53  unsigned size;
54  Address shared;
55
56  INLINE(void UpdateCodeMap(CodeMap* code_map));
57};
58
59
60class CodeMoveEventRecord : public CodeEventRecord {
61 public:
62  Address from;
63  Address to;
64
65  INLINE(void UpdateCodeMap(CodeMap* code_map));
66};
67
68
69class CodeDisableOptEventRecord : public CodeEventRecord {
70 public:
71  Address start;
72  const char* bailout_reason;
73
74  INLINE(void UpdateCodeMap(CodeMap* code_map));
75};
76
77
78class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
79 public:
80  Address from;
81  Address to;
82
83  INLINE(void UpdateCodeMap(CodeMap* code_map));
84};
85
86
87class ReportBuiltinEventRecord : public CodeEventRecord {
88 public:
89  Address start;
90  Builtins::Name builtin_id;
91
92  INLINE(void UpdateCodeMap(CodeMap* code_map));
93};
94
95
96class TickSampleEventRecord {
97 public:
98  // The parameterless constructor is used when we dequeue data from
99  // the ticks buffer.
100  TickSampleEventRecord() { }
101  explicit TickSampleEventRecord(unsigned order) : order(order) { }
102
103  unsigned order;
104  TickSample sample;
105};
106
107
108class CodeEventsContainer {
109 public:
110  explicit CodeEventsContainer(
111      CodeEventRecord::Type type = CodeEventRecord::NONE) {
112    generic.type = type;
113  }
114  union  {
115    CodeEventRecord generic;
116#define DECLARE_CLASS(ignore, type) type type##_;
117    CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
118#undef DECLARE_TYPE
119  };
120};
121
122
123// This class implements both the profile events processor thread and
124// methods called by event producers: VM and stack sampler threads.
125class ProfilerEventsProcessor : public base::Thread {
126 public:
127  ProfilerEventsProcessor(ProfileGenerator* generator,
128                          Sampler* sampler,
129                          base::TimeDelta period);
130  virtual ~ProfilerEventsProcessor() {}
131
132  // Thread control.
133  virtual void Run();
134  void StopSynchronously();
135  INLINE(bool running()) { return running_; }
136  void Enqueue(const CodeEventsContainer& event);
137
138  // Puts current stack into tick sample events buffer.
139  void AddCurrentStack(Isolate* isolate);
140
141  // Tick sample events are filled directly in the buffer of the circular
142  // queue (because the structure is of fixed width, but usually not all
143  // stack frame entries are filled.) This method returns a pointer to the
144  // next record of the buffer.
145  inline TickSample* StartTickSample();
146  inline void FinishTickSample();
147
148  // SamplingCircularQueue has stricter alignment requirements than a normal new
149  // can fulfil, so we need to provide our own new/delete here.
150  void* operator new(size_t size);
151  void operator delete(void* ptr);
152
153 private:
154  // Called from events processing thread (Run() method.)
155  bool ProcessCodeEvent();
156
157  enum SampleProcessingResult {
158    OneSampleProcessed,
159    FoundSampleForNextCodeEvent,
160    NoSamplesInQueue
161  };
162  SampleProcessingResult ProcessOneSample();
163
164  ProfileGenerator* generator_;
165  Sampler* sampler_;
166  bool running_;
167  // Sampling period in microseconds.
168  const base::TimeDelta period_;
169  UnboundQueue<CodeEventsContainer> events_buffer_;
170  static const size_t kTickSampleBufferSize = 1 * MB;
171  static const size_t kTickSampleQueueLength =
172      kTickSampleBufferSize / sizeof(TickSampleEventRecord);
173  SamplingCircularQueue<TickSampleEventRecord,
174                        kTickSampleQueueLength> ticks_buffer_;
175  UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
176  unsigned last_code_event_id_;
177  unsigned last_processed_code_event_id_;
178};
179
180
181#define PROFILE(IsolateGetter, Call)                                        \
182  do {                                                                      \
183    Isolate* cpu_profiler_isolate = (IsolateGetter);                        \
184    v8::internal::Logger* logger = cpu_profiler_isolate->logger();          \
185    CpuProfiler* cpu_profiler = cpu_profiler_isolate->cpu_profiler();       \
186    if (logger->is_logging_code_events() || cpu_profiler->is_profiling()) { \
187      logger->Call;                                                         \
188    }                                                                       \
189  } while (false)
190
191
192class CpuProfiler : public CodeEventListener {
193 public:
194  explicit CpuProfiler(Isolate* isolate);
195
196  CpuProfiler(Isolate* isolate,
197              CpuProfilesCollection* test_collection,
198              ProfileGenerator* test_generator,
199              ProfilerEventsProcessor* test_processor);
200
201  virtual ~CpuProfiler();
202
203  void set_sampling_interval(base::TimeDelta value);
204  void StartProfiling(const char* title, bool record_samples = false);
205  void StartProfiling(String* title, bool record_samples);
206  CpuProfile* StopProfiling(const char* title);
207  CpuProfile* StopProfiling(String* title);
208  int GetProfilesCount();
209  CpuProfile* GetProfile(int index);
210  void DeleteAllProfiles();
211  void DeleteProfile(CpuProfile* profile);
212
213  // Invoked from stack sampler (thread or signal handler.)
214  inline TickSample* StartTickSample();
215  inline void FinishTickSample();
216
217  // Must be called via PROFILE macro, otherwise will crash when
218  // profiling is not enabled.
219  virtual void CallbackEvent(Name* name, Address entry_point);
220  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
221                               Code* code, const char* comment);
222  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
223                               Code* code, Name* name);
224  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
225                               SharedFunctionInfo* shared,
226                               CompilationInfo* info, Name* script_name);
227  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
228                               SharedFunctionInfo* shared,
229                               CompilationInfo* info, Name* script_name,
230                               int line, int column);
231  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
232                               Code* code, int args_count);
233  virtual void CodeMovingGCEvent() {}
234  virtual void CodeMoveEvent(Address from, Address to);
235  virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
236  virtual void CodeDeleteEvent(Address from);
237  virtual void GetterCallbackEvent(Name* name, Address entry_point);
238  virtual void RegExpCodeCreateEvent(Code* code, String* source);
239  virtual void SetterCallbackEvent(Name* name, Address entry_point);
240  virtual void SharedFunctionInfoMoveEvent(Address from, Address to);
241
242  INLINE(bool is_profiling() const) { return is_profiling_; }
243  bool* is_profiling_address() {
244    return &is_profiling_;
245  }
246
247  ProfileGenerator* generator() const { return generator_; }
248  ProfilerEventsProcessor* processor() const { return processor_; }
249  Isolate* isolate() const { return isolate_; }
250
251 private:
252  void StartProcessorIfNotStarted();
253  void StopProcessorIfLastProfile(const char* title);
254  void StopProcessor();
255  void ResetProfiles();
256  void LogBuiltins();
257
258  Isolate* isolate_;
259  base::TimeDelta sampling_interval_;
260  CpuProfilesCollection* profiles_;
261  ProfileGenerator* generator_;
262  ProfilerEventsProcessor* processor_;
263  bool saved_is_logging_;
264  bool is_profiling_;
265
266  DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
267};
268
269} }  // namespace v8::internal
270
271
272#endif  // V8_CPU_PROFILER_H_
273