blob: 10165f67c89cafbd7bb0ef2f2ef3095b22da43b0 [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
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "atomicops.h"
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000034#include "circular-queue.h"
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000035#include "unbound-queue.h"
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000036
37namespace v8 {
38namespace internal {
39
lrn@chromium.org25156de2010-04-06 13:10:27 +000040// Forward declarations.
41class CodeEntry;
42class CodeMap;
43class CpuProfile;
44class CpuProfilesCollection;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000045class HashMap;
lrn@chromium.org25156de2010-04-06 13:10:27 +000046class ProfileGenerator;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000047class TokenEnumerator;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000048
49#define CODE_EVENTS_TYPE_LIST(V) \
50 V(CODE_CREATION, CodeCreateEventRecord) \
51 V(CODE_MOVE, CodeMoveEventRecord) \
52 V(CODE_DELETE, CodeDeleteEventRecord) \
53 V(CODE_ALIAS, CodeAliasEventRecord)
54
55
56class 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 unsigned order;
68};
69
70
71class CodeCreateEventRecord : public CodeEventRecord {
72 public:
73 Address start;
74 CodeEntry* entry;
75 unsigned size;
76
lrn@chromium.org25156de2010-04-06 13:10:27 +000077 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000078};
79
80
81class CodeMoveEventRecord : public CodeEventRecord {
82 public:
83 Address from;
84 Address to;
85
lrn@chromium.org25156de2010-04-06 13:10:27 +000086 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000087};
88
89
90class CodeDeleteEventRecord : public CodeEventRecord {
91 public:
92 Address start;
93
lrn@chromium.org25156de2010-04-06 13:10:27 +000094 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000095};
96
97
98class CodeAliasEventRecord : public CodeEventRecord {
99 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000100 Address start;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000101 CodeEntry* entry;
102 Address code_start;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000103
lrn@chromium.org25156de2010-04-06 13:10:27 +0000104 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000105};
106
107
lrn@chromium.org25156de2010-04-06 13:10:27 +0000108class TickSampleEventRecord BASE_EMBEDDED {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000109 public:
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000110 TickSampleEventRecord()
111 : filler(1) {
112 ASSERT(filler != SamplingCircularQueue::kClear);
113 }
114
ager@chromium.org357bf652010-04-12 11:30:10 +0000115 // The first machine word of a TickSampleEventRecord must not ever
116 // become equal to SamplingCircularQueue::kClear. As both order and
117 // TickSample's first field are not reliable in this sense (order
118 // can overflow, TickSample can have all fields reset), we are
119 // forced to use an artificial filler field.
120 int filler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000121 unsigned order;
ager@chromium.org357bf652010-04-12 11:30:10 +0000122 TickSample sample;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000123
lrn@chromium.org25156de2010-04-06 13:10:27 +0000124 static TickSampleEventRecord* cast(void* value) {
125 return reinterpret_cast<TickSampleEventRecord*>(value);
126 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000127
ager@chromium.org357bf652010-04-12 11:30:10 +0000128 INLINE(static TickSampleEventRecord* init(void* value));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000129};
130
131
132// This class implements both the profile events processor thread and
133// methods called by event producers: VM and stack sampler threads.
134class ProfilerEventsProcessor : public Thread {
135 public:
136 explicit ProfilerEventsProcessor(ProfileGenerator* generator);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000137 virtual ~ProfilerEventsProcessor();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000138
139 // Thread control.
140 virtual void Run();
141 inline void Stop() { running_ = false; }
142 INLINE(bool running()) { return running_; }
143
144 // Events adding methods. Called by VM threads.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000145 void CallbackCreateEvent(Logger::LogEventsAndTags tag,
146 const char* prefix, String* name,
147 Address start);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000148 void CodeCreateEvent(Logger::LogEventsAndTags tag,
149 String* name,
150 String* resource_name, int line_number,
151 Address start, unsigned size);
152 void CodeCreateEvent(Logger::LogEventsAndTags tag,
153 const char* name,
154 Address start, unsigned size);
155 void CodeCreateEvent(Logger::LogEventsAndTags tag,
156 int args_count,
157 Address start, unsigned size);
158 void CodeMoveEvent(Address from, Address to);
159 void CodeDeleteEvent(Address from);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000160 void FunctionCreateEvent(Address alias, Address start, int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000161 void FunctionMoveEvent(Address from, Address to);
162 void FunctionDeleteEvent(Address from);
ager@chromium.org357bf652010-04-12 11:30:10 +0000163 void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
164 const char* prefix, String* name,
165 Address start, unsigned size);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000166 // Puts current stack into tick sample events buffer.
167 void AddCurrentStack();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000168 bool IsKnownFunction(Address start);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000169 void ProcessMovedFunctions();
170 void RememberMovedFunction(JSFunction* function);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000171
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000172 // Tick sample events are filled directly in the buffer of the circular
173 // queue (because the structure is of fixed width, but usually not all
174 // stack frame entries are filled.) This method returns a pointer to the
175 // next record of the buffer.
176 INLINE(TickSample* TickSampleEvent());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000177
178 private:
179 union CodeEventsContainer {
180 CodeEventRecord generic;
181#define DECLARE_CLASS(ignore, type) type type##_;
182 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
183#undef DECLARE_TYPE
184 };
185
186 // Called from events processing thread (Run() method.)
187 bool ProcessCodeEvent(unsigned* dequeue_order);
188 bool ProcessTicks(unsigned dequeue_order);
189
ager@chromium.org357bf652010-04-12 11:30:10 +0000190 INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000191 INLINE(static bool AddressesMatch(void* key1, void* key2)) {
192 return key1 == key2;
193 }
194 INLINE(static uint32_t AddressHash(Address addr)) {
195 return ComputeIntegerHash(
196 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
197 }
ager@chromium.org357bf652010-04-12 11:30:10 +0000198
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000199 ProfileGenerator* generator_;
200 bool running_;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000201 UnboundQueue<CodeEventsContainer> events_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000202 SamplingCircularQueue ticks_buffer_;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000203 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000204 unsigned enqueue_order_;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000205
206 // Used from the VM thread.
207 HashMap* known_functions_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000208 List<JSFunction*> moved_functions_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000209};
210
lrn@chromium.org25156de2010-04-06 13:10:27 +0000211} } // namespace v8::internal
212
213
214#define PROFILE(Call) \
215 LOG(Call); \
216 do { \
217 if (v8::internal::CpuProfiler::is_profiling()) { \
218 v8::internal::CpuProfiler::Call; \
219 } \
220 } while (false)
221#else
222#define PROFILE(Call) LOG(Call)
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000223#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000224
225
226namespace v8 {
227namespace internal {
228
229class CpuProfiler {
230 public:
231 static void Setup();
232 static void TearDown();
233
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000234#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000235 static void StartProfiling(const char* title);
236 static void StartProfiling(String* title);
237 static CpuProfile* StopProfiling(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000238 static CpuProfile* StopProfiling(Object* security_token, String* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000239 static int GetProfilesCount();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000240 static CpuProfile* GetProfile(Object* security_token, int index);
241 static CpuProfile* FindProfile(Object* security_token, unsigned uid);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000242
243 // Invoked from stack sampler (thread or signal handler.)
244 static TickSample* TickSampleEvent();
245
246 // Must be called via PROFILE macro, otherwise will crash when
247 // profiling is not enabled.
248 static void CallbackEvent(String* name, Address entry_point);
249 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
250 Code* code, const char* comment);
251 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
252 Code* code, String* name);
253 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
254 Code* code, String* name,
255 String* source, int line);
256 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
257 Code* code, int args_count);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000258 static void CodeMovingGCEvent() {}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000259 static void CodeMoveEvent(Address from, Address to);
260 static void CodeDeleteEvent(Address from);
261 static void FunctionCreateEvent(JSFunction* function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000262 // Reports function creation in case we had missed it (e.g.
263 // if it was created from compiled code).
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000264 static void FunctionCreateEventFromMove(JSFunction* function);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000265 static void FunctionMoveEvent(Address from, Address to);
266 static void FunctionDeleteEvent(Address from);
267 static void GetterCallbackEvent(String* name, Address entry_point);
268 static void RegExpCodeCreateEvent(Code* code, String* source);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000269 static void ProcessMovedFunctions();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000270 static void SetterCallbackEvent(String* name, Address entry_point);
271
272 static INLINE(bool is_profiling()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000273 return NoBarrier_Load(&is_profiling_);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000274 }
275
276 private:
277 CpuProfiler();
278 ~CpuProfiler();
279 void StartCollectingProfile(const char* title);
280 void StartCollectingProfile(String* title);
281 void StartProcessorIfNotStarted();
282 CpuProfile* StopCollectingProfile(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000283 CpuProfile* StopCollectingProfile(Object* security_token, String* title);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000284 void StopProcessorIfLastProfile(const char* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000285
286 CpuProfilesCollection* profiles_;
287 unsigned next_profile_uid_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000288 TokenEnumerator* token_enumerator_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000289 ProfileGenerator* generator_;
290 ProfilerEventsProcessor* processor_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000291 int saved_logging_nesting_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000292
293 static CpuProfiler* singleton_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 static Atomic32 is_profiling_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000295
296#else
297 static INLINE(bool is_profiling()) { return false; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000298#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000299
300 private:
301 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
302};
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000303
304} } // namespace v8::internal
305
lrn@chromium.org25156de2010-04-06 13:10:27 +0000306
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000307#endif // V8_CPU_PROFILER_H_