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/circular-queue.h" 11 #include "src/platform/time.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. 100 TickSampleEventRecord() { } 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 Thread { 126 public: 127 ProfilerEventsProcessor(ProfileGenerator* generator, 128 Sampler* sampler, 129 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 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(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, 225 Code* code, 226 SharedFunctionInfo* shared, 227 CompilationInfo* info, 228 Name* name); 229 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 230 Code* code, 231 SharedFunctionInfo* shared, 232 CompilationInfo* info, 233 Name* source, int line, int column); 234 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 235 Code* code, int args_count); 236 virtual void CodeMovingGCEvent() {} 237 virtual void CodeMoveEvent(Address from, Address to); 238 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared); 239 virtual void CodeDeleteEvent(Address from); 240 virtual void GetterCallbackEvent(Name* name, Address entry_point); 241 virtual void RegExpCodeCreateEvent(Code* code, String* source); 242 virtual void SetterCallbackEvent(Name* name, Address entry_point); 243 virtual void SharedFunctionInfoMoveEvent(Address from, Address to); 244 245 INLINE(bool is_profiling() const) { return is_profiling_; } 246 bool* is_profiling_address() { 247 return &is_profiling_; 248 } 249 250 ProfileGenerator* generator() const { return generator_; } 251 ProfilerEventsProcessor* processor() const { return processor_; } 252 Isolate* isolate() const { return isolate_; } 253 254 private: 255 void StartProcessorIfNotStarted(); 256 void StopProcessorIfLastProfile(const char* title); 257 void StopProcessor(); 258 void ResetProfiles(); 259 void LogBuiltins(); 260 261 Isolate* isolate_; 262 TimeDelta sampling_interval_; 263 CpuProfilesCollection* profiles_; 264 ProfileGenerator* generator_; 265 ProfilerEventsProcessor* processor_; 266 bool saved_is_logging_; 267 bool is_profiling_; 268 269 DISALLOW_COPY_AND_ASSIGN(CpuProfiler); 270 }; 271 272 } } // namespace v8::internal 273 274 275 #endif // V8_CPU_PROFILER_H_ 276