cpu-profiler.h 8.63 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 "sampler.h"
35
#include "unbound-queue.h"
36 37 38 39

namespace v8 {
namespace internal {

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

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


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;
66
  mutable unsigned order;
67 68 69 70 71 72 73 74
};


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

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


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

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


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

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


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

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


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

115
  unsigned order;
116
  TickSample sample;
117

118 119 120
  static TickSampleEventRecord* cast(void* value) {
    return reinterpret_cast<TickSampleEventRecord*>(value);
  }
121 122 123
};


124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
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
  };
};


139 140 141 142
// 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:
143
  explicit ProfilerEventsProcessor(ProfileGenerator* generator);
144
  virtual ~ProfilerEventsProcessor() {}
145 146 147

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

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

155 156 157 158 159
  // 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.
  INLINE(TickSample* TickSampleEvent());
160 161 162

 private:
  // Called from events processing thread (Run() method.)
163 164
  bool ProcessCodeEvent();
  bool ProcessTicks();
165 166 167

  ProfileGenerator* generator_;
  bool running_;
168
  UnboundQueue<CodeEventsContainer> events_buffer_;
169
  SamplingCircularQueue ticks_buffer_;
170
  UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
171 172
  unsigned last_code_event_id_;
  unsigned last_processed_code_event_id_;
173 174
};

175

176 177 178 179 180 181 182 183
#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;                                                         \
    }                                                                       \
184 185 186
  } while (false)


187
class CpuProfiler : public CodeEventListener {
188
 public:
189
  explicit CpuProfiler(Isolate* isolate);
190 191 192 193 194 195

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

196
  virtual ~CpuProfiler();
197 198 199 200

  void StartProfiling(const char* title, bool record_samples = false);
  void StartProfiling(String* title, bool record_samples);
  CpuProfile* StopProfiling(const char* title);
201
  CpuProfile* StopProfiling(String* title);
202
  int GetProfilesCount();
203
  CpuProfile* GetProfile(int index);
204 205
  void DeleteAllProfiles();
  void DeleteProfile(CpuProfile* profile);
206 207

  // Invoked from stack sampler (thread or signal handler.)
208
  TickSample* TickSampleEvent();
209 210 211

  // Must be called via PROFILE macro, otherwise will crash when
  // profiling is not enabled.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
  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,
                               Name* source, int line);
  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);
236 237

  INLINE(bool is_profiling() const) { return is_profiling_; }
238 239 240
  bool* is_profiling_address() {
    return &is_profiling_;
  }
241

242 243 244
  ProfileGenerator* generator() const { return generator_; }
  ProfilerEventsProcessor* processor() const { return processor_; }

245 246
 private:
  void StartProcessorIfNotStarted();
247
  void StopProcessorIfLastProfile(const char* title);
248 249
  void StopProcessor();
  void ResetProfiles();
250
  void LogBuiltins();
251

252
  Isolate* isolate_;
253 254 255 256
  CpuProfilesCollection* profiles_;
  unsigned next_profile_uid_;
  ProfileGenerator* generator_;
  ProfilerEventsProcessor* processor_;
257
  int saved_logging_nesting_;
258
  bool need_to_stop_sampler_;
259
  bool is_profiling_;
260 261 262 263 264 265 266 267

 private:
  DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
};

} }  // namespace v8::internal


268
#endif  // V8_CPU_PROFILER_H_