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