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