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