1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_CPU_PROFILER_H_ 29 #define V8_CPU_PROFILER_H_ 30 31 #include "allocation.h" 32 #include "atomicops.h" 33 #include "circular-queue.h" 34 #include "platform/time.h" 35 #include "sampler.h" 36 #include "unbound-queue.h" 37 38 namespace v8 { 39 namespace internal { 40 41 // Forward declarations. 42 class CodeEntry; 43 class CodeMap; 44 class CompilationInfo; 45 class CpuProfile; 46 class CpuProfilesCollection; 47 class ProfileGenerator; 48 49 #define CODE_EVENTS_TYPE_LIST(V) \ 50 V(CODE_CREATION, CodeCreateEventRecord) \ 51 V(CODE_MOVE, CodeMoveEventRecord) \ 52 V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord) \ 53 V(REPORT_BUILTIN, ReportBuiltinEventRecord) 54 55 56 class CodeEventRecord { 57 public: 58 #define DECLARE_TYPE(type, ignore) type, 59 enum Type { 60 NONE = 0, 61 CODE_EVENTS_TYPE_LIST(DECLARE_TYPE) 62 NUMBER_OF_TYPES 63 }; 64 #undef DECLARE_TYPE 65 66 Type type; 67 mutable unsigned order; 68 }; 69 70 71 class CodeCreateEventRecord : public CodeEventRecord { 72 public: 73 Address start; 74 CodeEntry* entry; 75 unsigned size; 76 Address shared; 77 78 INLINE(void UpdateCodeMap(CodeMap* code_map)); 79 }; 80 81 82 class CodeMoveEventRecord : public CodeEventRecord { 83 public: 84 Address from; 85 Address to; 86 87 INLINE(void UpdateCodeMap(CodeMap* code_map)); 88 }; 89 90 91 class SharedFunctionInfoMoveEventRecord : public CodeEventRecord { 92 public: 93 Address from; 94 Address to; 95 96 INLINE(void UpdateCodeMap(CodeMap* code_map)); 97 }; 98 99 100 class ReportBuiltinEventRecord : public CodeEventRecord { 101 public: 102 Address start; 103 Builtins::Name builtin_id; 104 105 INLINE(void UpdateCodeMap(CodeMap* code_map)); 106 }; 107 108 109 class TickSampleEventRecord { 110 public: 111 // The parameterless constructor is used when we dequeue data from 112 // the ticks buffer. 113 TickSampleEventRecord() { } 114 explicit TickSampleEventRecord(unsigned order) : order(order) { } 115 116 unsigned order; 117 TickSample sample; 118 }; 119 120 121 class CodeEventsContainer { 122 public: 123 explicit CodeEventsContainer( 124 CodeEventRecord::Type type = CodeEventRecord::NONE) { 125 generic.type = type; 126 } 127 union { 128 CodeEventRecord generic; 129 #define DECLARE_CLASS(ignore, type) type type##_; 130 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS) 131 #undef DECLARE_TYPE 132 }; 133 }; 134 135 136 // This class implements both the profile events processor thread and 137 // methods called by event producers: VM and stack sampler threads. 138 class ProfilerEventsProcessor : public Thread { 139 public: 140 ProfilerEventsProcessor(ProfileGenerator* generator, 141 Sampler* sampler, 142 TimeDelta period); 143 virtual ~ProfilerEventsProcessor() {} 144 145 // Thread control. 146 virtual void Run(); 147 void StopSynchronously(); 148 INLINE(bool running()) { return running_; } 149 void Enqueue(const CodeEventsContainer& event); 150 151 // Puts current stack into tick sample events buffer. 152 void AddCurrentStack(Isolate* isolate); 153 154 // Tick sample events are filled directly in the buffer of the circular 155 // queue (because the structure is of fixed width, but usually not all 156 // stack frame entries are filled.) This method returns a pointer to the 157 // next record of the buffer. 158 inline TickSample* StartTickSample(); 159 inline void FinishTickSample(); 160 161 private: 162 // Called from events processing thread (Run() method.) 163 bool ProcessCodeEvent(); 164 165 enum SampleProcessingResult { 166 OneSampleProcessed, 167 FoundSampleForNextCodeEvent, 168 NoSamplesInQueue 169 }; 170 SampleProcessingResult ProcessOneSample(); 171 172 ProfileGenerator* generator_; 173 Sampler* sampler_; 174 bool running_; 175 // Sampling period in microseconds. 176 const TimeDelta period_; 177 UnboundQueue<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 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_; 184 unsigned last_code_event_id_; 185 unsigned last_processed_code_event_id_; 186 }; 187 188 189 #define PROFILE(IsolateGetter, Call) \ 190 do { \ 191 Isolate* cpu_profiler_isolate = (IsolateGetter); \ 192 v8::internal::Logger* logger = cpu_profiler_isolate->logger(); \ 193 CpuProfiler* cpu_profiler = cpu_profiler_isolate->cpu_profiler(); \ 194 if (logger->is_logging_code_events() || cpu_profiler->is_profiling()) { \ 195 logger->Call; \ 196 } \ 197 } while (false) 198 199 200 class CpuProfiler : public CodeEventListener { 201 public: 202 explicit CpuProfiler(Isolate* isolate); 203 204 CpuProfiler(Isolate* isolate, 205 CpuProfilesCollection* test_collection, 206 ProfileGenerator* test_generator, 207 ProfilerEventsProcessor* test_processor); 208 209 virtual ~CpuProfiler(); 210 211 void set_sampling_interval(TimeDelta value); 212 void StartProfiling(const char* title, bool record_samples = false); 213 void StartProfiling(String* title, bool record_samples); 214 CpuProfile* StopProfiling(const char* title); 215 CpuProfile* StopProfiling(String* title); 216 int GetProfilesCount(); 217 CpuProfile* GetProfile(int index); 218 void DeleteAllProfiles(); 219 void DeleteProfile(CpuProfile* profile); 220 221 // Invoked from stack sampler (thread or signal handler.) 222 inline TickSample* StartTickSample(); 223 inline void FinishTickSample(); 224 225 // Must be called via PROFILE macro, otherwise will crash when 226 // profiling is not enabled. 227 virtual void CallbackEvent(Name* name, Address entry_point); 228 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 229 Code* code, const char* comment); 230 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 231 Code* code, Name* name); 232 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 233 Code* code, 234 SharedFunctionInfo* shared, 235 CompilationInfo* info, 236 Name* name); 237 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 238 Code* code, 239 SharedFunctionInfo* shared, 240 CompilationInfo* info, 241 Name* source, int line, int column); 242 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, 243 Code* code, int args_count); 244 virtual void CodeMovingGCEvent() {} 245 virtual void CodeMoveEvent(Address from, Address to); 246 virtual void CodeDeleteEvent(Address from); 247 virtual void GetterCallbackEvent(Name* name, Address entry_point); 248 virtual void RegExpCodeCreateEvent(Code* code, String* source); 249 virtual void SetterCallbackEvent(Name* name, Address entry_point); 250 virtual void SharedFunctionInfoMoveEvent(Address from, Address to); 251 252 INLINE(bool is_profiling() const) { return is_profiling_; } 253 bool* is_profiling_address() { 254 return &is_profiling_; 255 } 256 257 ProfileGenerator* generator() const { return generator_; } 258 ProfilerEventsProcessor* processor() const { return processor_; } 259 Isolate* isolate() const { return isolate_; } 260 261 private: 262 void StartProcessorIfNotStarted(); 263 void StopProcessorIfLastProfile(const char* title); 264 void StopProcessor(); 265 void ResetProfiles(); 266 void LogBuiltins(); 267 268 Isolate* isolate_; 269 TimeDelta sampling_interval_; 270 CpuProfilesCollection* profiles_; 271 unsigned next_profile_uid_; 272 ProfileGenerator* generator_; 273 ProfilerEventsProcessor* processor_; 274 bool saved_is_logging_; 275 bool is_profiling_; 276 277 DISALLOW_COPY_AND_ASSIGN(CpuProfiler); 278 }; 279 280 } } // namespace v8::internal 281 282 283 #endif // V8_CPU_PROFILER_H_ 284