blob: d3158d7aaa70ea4fc42bbd59481d417805173b4a [file] [log] [blame]
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001// Copyright 2010 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
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000031#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +000032
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000033#include "circular-queue.h"
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000034#include "unbound-queue.h"
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000035
36namespace v8 {
37namespace internal {
38
lrn@chromium.org25156de2010-04-06 13:10:27 +000039// Forward declarations.
40class CodeEntry;
41class CodeMap;
42class CpuProfile;
43class CpuProfilesCollection;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000044class HashMap;
lrn@chromium.org25156de2010-04-06 13:10:27 +000045class ProfileGenerator;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000046class TokenEnumerator;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000047
48#define CODE_EVENTS_TYPE_LIST(V) \
49 V(CODE_CREATION, CodeCreateEventRecord) \
50 V(CODE_MOVE, CodeMoveEventRecord) \
51 V(CODE_DELETE, CodeDeleteEventRecord) \
52 V(CODE_ALIAS, CodeAliasEventRecord)
53
54
55class CodeEventRecord {
56 public:
57#define DECLARE_TYPE(type, ignore) type,
58 enum Type {
59 NONE = 0,
60 CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
61 NUMBER_OF_TYPES
62 };
63#undef DECLARE_TYPE
64
65 Type type;
66 unsigned order;
67};
68
69
70class CodeCreateEventRecord : public CodeEventRecord {
71 public:
72 Address start;
73 CodeEntry* entry;
74 unsigned size;
75
lrn@chromium.org25156de2010-04-06 13:10:27 +000076 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000077};
78
79
80class CodeMoveEventRecord : public CodeEventRecord {
81 public:
82 Address from;
83 Address to;
84
lrn@chromium.org25156de2010-04-06 13:10:27 +000085 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000086};
87
88
89class CodeDeleteEventRecord : public CodeEventRecord {
90 public:
91 Address start;
92
lrn@chromium.org25156de2010-04-06 13:10:27 +000093 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000094};
95
96
97class CodeAliasEventRecord : public CodeEventRecord {
98 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000099 Address start;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000100 CodeEntry* entry;
101 Address code_start;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000102
lrn@chromium.org25156de2010-04-06 13:10:27 +0000103 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000104};
105
106
lrn@chromium.org25156de2010-04-06 13:10:27 +0000107class TickSampleEventRecord BASE_EMBEDDED {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000108 public:
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000109 TickSampleEventRecord()
110 : filler(1) {
111 ASSERT(filler != SamplingCircularQueue::kClear);
112 }
113
ager@chromium.org357bf652010-04-12 11:30:10 +0000114 // The first machine word of a TickSampleEventRecord must not ever
115 // become equal to SamplingCircularQueue::kClear. As both order and
116 // TickSample's first field are not reliable in this sense (order
117 // can overflow, TickSample can have all fields reset), we are
118 // forced to use an artificial filler field.
119 int filler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000120 unsigned order;
ager@chromium.org357bf652010-04-12 11:30:10 +0000121 TickSample sample;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000122
lrn@chromium.org25156de2010-04-06 13:10:27 +0000123 static TickSampleEventRecord* cast(void* value) {
124 return reinterpret_cast<TickSampleEventRecord*>(value);
125 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000126
ager@chromium.org357bf652010-04-12 11:30:10 +0000127 INLINE(static TickSampleEventRecord* init(void* value));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000128};
129
130
131// This class implements both the profile events processor thread and
132// methods called by event producers: VM and stack sampler threads.
133class ProfilerEventsProcessor : public Thread {
134 public:
135 explicit ProfilerEventsProcessor(ProfileGenerator* generator);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000136 virtual ~ProfilerEventsProcessor();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000137
138 // Thread control.
139 virtual void Run();
140 inline void Stop() { running_ = false; }
141 INLINE(bool running()) { return running_; }
142
143 // Events adding methods. Called by VM threads.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000144 void CallbackCreateEvent(Logger::LogEventsAndTags tag,
145 const char* prefix, String* name,
146 Address start);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000147 void CodeCreateEvent(Logger::LogEventsAndTags tag,
148 String* name,
149 String* resource_name, int line_number,
150 Address start, unsigned size);
151 void CodeCreateEvent(Logger::LogEventsAndTags tag,
152 const char* name,
153 Address start, unsigned size);
154 void CodeCreateEvent(Logger::LogEventsAndTags tag,
155 int args_count,
156 Address start, unsigned size);
157 void CodeMoveEvent(Address from, Address to);
158 void CodeDeleteEvent(Address from);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000159 void FunctionCreateEvent(Address alias, Address start, int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000160 void FunctionMoveEvent(Address from, Address to);
161 void FunctionDeleteEvent(Address from);
ager@chromium.org357bf652010-04-12 11:30:10 +0000162 void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
163 const char* prefix, String* name,
164 Address start, unsigned size);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000165 // Puts current stack into tick sample events buffer.
166 void AddCurrentStack();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000167 bool IsKnownFunction(Address start);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000168 void ProcessMovedFunctions();
169 void RememberMovedFunction(JSFunction* function);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000170
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000171 // Tick sample events are filled directly in the buffer of the circular
172 // queue (because the structure is of fixed width, but usually not all
173 // stack frame entries are filled.) This method returns a pointer to the
174 // next record of the buffer.
175 INLINE(TickSample* TickSampleEvent());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000176
177 private:
178 union CodeEventsContainer {
179 CodeEventRecord generic;
180#define DECLARE_CLASS(ignore, type) type type##_;
181 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
182#undef DECLARE_TYPE
183 };
184
185 // Called from events processing thread (Run() method.)
186 bool ProcessCodeEvent(unsigned* dequeue_order);
187 bool ProcessTicks(unsigned dequeue_order);
188
ager@chromium.org357bf652010-04-12 11:30:10 +0000189 INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000190 INLINE(static bool AddressesMatch(void* key1, void* key2)) {
191 return key1 == key2;
192 }
193 INLINE(static uint32_t AddressHash(Address addr)) {
194 return ComputeIntegerHash(
195 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
196 }
ager@chromium.org357bf652010-04-12 11:30:10 +0000197
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000198 ProfileGenerator* generator_;
199 bool running_;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000200 UnboundQueue<CodeEventsContainer> events_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000201 SamplingCircularQueue ticks_buffer_;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000202 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000203 unsigned enqueue_order_;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000204
205 // Used from the VM thread.
206 HashMap* known_functions_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000207 List<JSFunction*> moved_functions_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000208};
209
lrn@chromium.org25156de2010-04-06 13:10:27 +0000210} } // namespace v8::internal
211
212
213#define PROFILE(Call) \
214 LOG(Call); \
215 do { \
216 if (v8::internal::CpuProfiler::is_profiling()) { \
217 v8::internal::CpuProfiler::Call; \
218 } \
219 } while (false)
220#else
221#define PROFILE(Call) LOG(Call)
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000222#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000223
224
225namespace v8 {
226namespace internal {
227
228class CpuProfiler {
229 public:
230 static void Setup();
231 static void TearDown();
232
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000233#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000234 static void StartProfiling(const char* title);
235 static void StartProfiling(String* title);
236 static CpuProfile* StopProfiling(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000237 static CpuProfile* StopProfiling(Object* security_token, String* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000238 static int GetProfilesCount();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000239 static CpuProfile* GetProfile(Object* security_token, int index);
240 static CpuProfile* FindProfile(Object* security_token, unsigned uid);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000241
242 // Invoked from stack sampler (thread or signal handler.)
243 static TickSample* TickSampleEvent();
244
245 // Must be called via PROFILE macro, otherwise will crash when
246 // profiling is not enabled.
247 static void CallbackEvent(String* name, Address entry_point);
248 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
249 Code* code, const char* comment);
250 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
251 Code* code, String* name);
252 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
253 Code* code, String* name,
254 String* source, int line);
255 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
256 Code* code, int args_count);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000257 static void CodeMovingGCEvent() {}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000258 static void CodeMoveEvent(Address from, Address to);
259 static void CodeDeleteEvent(Address from);
260 static void FunctionCreateEvent(JSFunction* function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000261 // Reports function creation in case we had missed it (e.g.
262 // if it was created from compiled code).
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000263 static void FunctionCreateEventFromMove(JSFunction* function);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000264 static void FunctionMoveEvent(Address from, Address to);
265 static void FunctionDeleteEvent(Address from);
266 static void GetterCallbackEvent(String* name, Address entry_point);
267 static void RegExpCodeCreateEvent(Code* code, String* source);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000268 static void ProcessMovedFunctions();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000269 static void SetterCallbackEvent(String* name, Address entry_point);
270
271 static INLINE(bool is_profiling()) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000272 return singleton_ != NULL && singleton_->processor_ != NULL;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000273 }
274
275 private:
276 CpuProfiler();
277 ~CpuProfiler();
278 void StartCollectingProfile(const char* title);
279 void StartCollectingProfile(String* title);
280 void StartProcessorIfNotStarted();
281 CpuProfile* StopCollectingProfile(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000282 CpuProfile* StopCollectingProfile(Object* security_token, String* title);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000283 void StopProcessorIfLastProfile(const char* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000284
285 CpuProfilesCollection* profiles_;
286 unsigned next_profile_uid_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000287 TokenEnumerator* token_enumerator_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000288 ProfileGenerator* generator_;
289 ProfilerEventsProcessor* processor_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000290 int saved_logging_nesting_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000291
292 static CpuProfiler* singleton_;
293
294#else
295 static INLINE(bool is_profiling()) { return false; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000296#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000297
298 private:
299 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
300};
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000301
302} } // namespace v8::internal
303
lrn@chromium.org25156de2010-04-06 13:10:27 +0000304
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000305#endif // V8_CPU_PROFILER_H_