cpu-profiler.h 9.41 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_CPU_PROFILER_H_
#define V8_CPU_PROFILER_H_

31
#include "allocation.h"
32
#include "atomicops.h"
33
#include "circular-queue.h"
34
#include "platform/time.h"
35
#include "sampler.h"
36
#include "unbound-queue.h"
37 38 39 40

namespace v8 {
namespace internal {

41 42 43
// Forward declarations.
class CodeEntry;
class CodeMap;
44
class CompilationInfo;
45 46 47 48
class CpuProfile;
class CpuProfilesCollection;
class ProfileGenerator;

49 50 51
#define CODE_EVENTS_TYPE_LIST(V)                                   \
  V(CODE_CREATION,    CodeCreateEventRecord)                       \
  V(CODE_MOVE,        CodeMoveEventRecord)                         \
52 53
  V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)           \
  V(REPORT_BUILTIN,   ReportBuiltinEventRecord)
54 55 56 57 58 59 60 61 62 63 64 65 66


class CodeEventRecord {
 public:
#define DECLARE_TYPE(type, ignore) type,
  enum Type {
    NONE = 0,
    CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
    NUMBER_OF_TYPES
  };
#undef DECLARE_TYPE

  Type type;
67
  mutable unsigned order;
68 69 70 71 72 73 74 75
};


class CodeCreateEventRecord : public CodeEventRecord {
 public:
  Address start;
  CodeEntry* entry;
  unsigned size;
76
  Address shared;
77

78
  INLINE(void UpdateCodeMap(CodeMap* code_map));
79 80 81 82 83 84 85 86
};


class CodeMoveEventRecord : public CodeEventRecord {
 public:
  Address from;
  Address to;

87
  INLINE(void UpdateCodeMap(CodeMap* code_map));
88 89 90
};


91
class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
92
 public:
93 94
  Address from;
  Address to;
95

96
  INLINE(void UpdateCodeMap(CodeMap* code_map));
97 98 99
};


100 101 102 103 104 105 106 107 108
class ReportBuiltinEventRecord : public CodeEventRecord {
 public:
  Address start;
  Builtins::Name builtin_id;

  INLINE(void UpdateCodeMap(CodeMap* code_map));
};


109
class TickSampleEventRecord {
110
 public:
111 112 113
  // The parameterless constructor is used when we dequeue data from
  // the ticks buffer.
  TickSampleEventRecord() { }
114 115
  explicit TickSampleEventRecord(unsigned order) : order(order) { }

116
  unsigned order;
117
  TickSample sample;
118 119 120
};


121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
class CodeEventsContainer {
 public:
  explicit CodeEventsContainer(
      CodeEventRecord::Type type = CodeEventRecord::NONE) {
    generic.type = type;
  }
  union  {
    CodeEventRecord generic;
#define DECLARE_CLASS(ignore, type) type type##_;
    CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
#undef DECLARE_TYPE
  };
};


136 137 138 139
// This class implements both the profile events processor thread and
// methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public Thread {
 public:
140 141
  ProfilerEventsProcessor(ProfileGenerator* generator,
                          Sampler* sampler,
142
                          TimeDelta period);
143
  virtual ~ProfilerEventsProcessor() {}
144 145 146

  // Thread control.
  virtual void Run();
147
  void StopSynchronously();
148
  INLINE(bool running()) { return running_; }
149
  void Enqueue(const CodeEventsContainer& event);
150

151
  // Puts current stack into tick sample events buffer.
152
  void AddCurrentStack(Isolate* isolate);
153

154 155 156 157
  // Tick sample events are filled directly in the buffer of the circular
  // queue (because the structure is of fixed width, but usually not all
  // stack frame entries are filled.) This method returns a pointer to the
  // next record of the buffer.
158 159
  inline TickSample* StartTickSample();
  inline void FinishTickSample();
160

161 162 163 164 165
  // SamplingCircularQueue has stricter alignment requirements than a normal new
  // can fulfil, so we need to provide our own new/delete here.
  void* operator new(size_t size);
  void operator delete(void* ptr);

166 167
 private:
  // Called from events processing thread (Run() method.)
168
  bool ProcessCodeEvent();
169

170 171 172 173 174 175
  enum SampleProcessingResult {
    OneSampleProcessed,
    FoundSampleForNextCodeEvent,
    NoSamplesInQueue
  };
  SampleProcessingResult ProcessOneSample();
176

177
  ProfileGenerator* generator_;
178
  Sampler* sampler_;
179
  bool running_;
180
  // Sampling period in microseconds.
181
  const TimeDelta period_;
182
  UnboundQueue<CodeEventsContainer> events_buffer_;
183 184 185 186 187
  static const size_t kTickSampleBufferSize = 1 * MB;
  static const size_t kTickSampleQueueLength =
      kTickSampleBufferSize / sizeof(TickSampleEventRecord);
  SamplingCircularQueue<TickSampleEventRecord,
                        kTickSampleQueueLength> ticks_buffer_;
188
  UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
189 190
  unsigned last_code_event_id_;
  unsigned last_processed_code_event_id_;
191 192
};

193

194 195 196 197 198 199 200 201
#define PROFILE(IsolateGetter, Call)                                        \
  do {                                                                      \
    Isolate* cpu_profiler_isolate = (IsolateGetter);                        \
    v8::internal::Logger* logger = cpu_profiler_isolate->logger();          \
    CpuProfiler* cpu_profiler = cpu_profiler_isolate->cpu_profiler();       \
    if (logger->is_logging_code_events() || cpu_profiler->is_profiling()) { \
      logger->Call;                                                         \
    }                                                                       \
202 203 204
  } while (false)


205
class CpuProfiler : public CodeEventListener {
206
 public:
207
  explicit CpuProfiler(Isolate* isolate);
208 209 210 211 212 213

  CpuProfiler(Isolate* isolate,
              CpuProfilesCollection* test_collection,
              ProfileGenerator* test_generator,
              ProfilerEventsProcessor* test_processor);

214
  virtual ~CpuProfiler();
215

216
  void set_sampling_interval(TimeDelta value);
217 218 219
  void StartProfiling(const char* title, bool record_samples = false);
  void StartProfiling(String* title, bool record_samples);
  CpuProfile* StopProfiling(const char* title);
220
  CpuProfile* StopProfiling(String* title);
221
  int GetProfilesCount();
222
  CpuProfile* GetProfile(int index);
223 224
  void DeleteAllProfiles();
  void DeleteProfile(CpuProfile* profile);
225 226

  // Invoked from stack sampler (thread or signal handler.)
227 228
  inline TickSample* StartTickSample();
  inline void FinishTickSample();
229 230 231

  // Must be called via PROFILE macro, otherwise will crash when
  // profiling is not enabled.
232 233 234 235 236 237 238 239 240 241 242 243 244 245
  virtual void CallbackEvent(Name* name, Address entry_point);
  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code, const char* comment);
  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code, Name* name);
  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code,
                               SharedFunctionInfo* shared,
                               CompilationInfo* info,
                               Name* name);
  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code,
                               SharedFunctionInfo* shared,
                               CompilationInfo* info,
246
                               Name* source, int line, int column);
247 248 249 250 251 252 253 254 255
  virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
                               Code* code, int args_count);
  virtual void CodeMovingGCEvent() {}
  virtual void CodeMoveEvent(Address from, Address to);
  virtual void CodeDeleteEvent(Address from);
  virtual void GetterCallbackEvent(Name* name, Address entry_point);
  virtual void RegExpCodeCreateEvent(Code* code, String* source);
  virtual void SetterCallbackEvent(Name* name, Address entry_point);
  virtual void SharedFunctionInfoMoveEvent(Address from, Address to);
256 257

  INLINE(bool is_profiling() const) { return is_profiling_; }
258 259 260
  bool* is_profiling_address() {
    return &is_profiling_;
  }
261

262 263
  ProfileGenerator* generator() const { return generator_; }
  ProfilerEventsProcessor* processor() const { return processor_; }
264
  Isolate* isolate() const { return isolate_; }
265

266 267
 private:
  void StartProcessorIfNotStarted();
268
  void StopProcessorIfLastProfile(const char* title);
269 270
  void StopProcessor();
  void ResetProfiles();
271
  void LogBuiltins();
272

273
  Isolate* isolate_;
274
  TimeDelta sampling_interval_;
275 276 277
  CpuProfilesCollection* profiles_;
  ProfileGenerator* generator_;
  ProfilerEventsProcessor* processor_;
278
  bool saved_is_logging_;
279
  bool is_profiling_;
280 281 282 283 284 285 286

  DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
};

} }  // namespace v8::internal


287
#endif  // V8_CPU_PROFILER_H_