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 15 namespace v8 { 16 namespace internal { 17 18 // Forward declarations. 19 class CodeEntry; 20 class CodeMap; 21 class CompilationInfo; 22 class CpuProfile; 23 class CpuProfilesCollection; 24 class 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 34 class 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 49 class 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 60 class CodeMoveEventRecord : public CodeEventRecord { 61 public: 62 Address from; 63 Address to; 64 65 INLINE(void UpdateCodeMap(CodeMap* code_map)); 66 }; 67 68 69 class CodeDisableOptEventRecord : public CodeEventRecord { 70 public: 71 Address start; 72 const char* bailout_reason; 73 74 INLINE(void UpdateCodeMap(CodeMap* code_map)); 75 }; 76 77 78 class SharedFunctionInfoMoveEventRecord : public CodeEventRecord { 79 public: 80 Address from; 81 Address to; 82 83 INLINE(void UpdateCodeMap(CodeMap* code_map)); 84 }; 85 86 87 class ReportBuiltinEventRecord : public CodeEventRecord { 88 public: 89 Address start; 90 Builtins::Name builtin_id; 91 92 INLINE(void UpdateCodeMap(CodeMap* code_map)); 93 }; 94 95 96 class TickSampleEventRecord { 97 public: 98 // The parameterless constructor is used when we dequeue data from 99 // the ticks buffer. TickSampleEventRecord()100 TickSampleEventRecord() { } TickSampleEventRecord(unsigned order)101 explicit TickSampleEventRecord(unsigned order) : order(order) { } 102 103 unsigned order; 104 TickSample sample; 105 }; 106 107 108 class 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. 125 class ProfilerEventsProcessor : public base::Thread { 126 public: 127 ProfilerEventsProcessor(ProfileGenerator* generator, 128 Sampler* sampler, 129 base::TimeDelta period); ~ProfilerEventsProcessor()130 virtual ~ProfilerEventsProcessor() {} 131 132 // Thread control. 133 virtual void Run(); 134 void StopSynchronously(); INLINE(bool running ())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 192 class 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); CodeMovingGCEvent()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 INLINE(bool is_profiling ()const)242 INLINE(bool is_profiling() const) { return is_profiling_; } is_profiling_address()243 bool* is_profiling_address() { 244 return &is_profiling_; 245 } 246 generator()247 ProfileGenerator* generator() const { return generator_; } processor()248 ProfilerEventsProcessor* processor() const { return processor_; } isolate()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