• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
TickSampleEventRecord()113   TickSampleEventRecord() { }
TickSampleEventRecord(unsigned order)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);
~ProfilerEventsProcessor()143   virtual ~ProfilerEventsProcessor() {}
144 
145   // Thread control.
146   virtual void Run();
147   void StopSynchronously();
INLINE(bool running ())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);
CodeMovingGCEvent()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 
INLINE(bool is_profiling ()const)252   INLINE(bool is_profiling() const) { return is_profiling_; }
is_profiling_address()253   bool* is_profiling_address() {
254     return &is_profiling_;
255   }
256 
generator()257   ProfileGenerator* generator() const { return generator_; }
processor()258   ProfilerEventsProcessor* processor() const { return processor_; }
isolate()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