blob: 03b81764851cea6881e33a4d42cdbd130ecaab51 [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;
44class ProfileGenerator;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000045class TokenEnumerator;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000046
47#define CODE_EVENTS_TYPE_LIST(V) \
48 V(CODE_CREATION, CodeCreateEventRecord) \
49 V(CODE_MOVE, CodeMoveEventRecord) \
50 V(CODE_DELETE, CodeDeleteEventRecord) \
51 V(CODE_ALIAS, CodeAliasEventRecord)
52
53
54class CodeEventRecord {
55 public:
56#define DECLARE_TYPE(type, ignore) type,
57 enum Type {
58 NONE = 0,
59 CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
60 NUMBER_OF_TYPES
61 };
62#undef DECLARE_TYPE
63
64 Type type;
65 unsigned order;
66};
67
68
69class CodeCreateEventRecord : public CodeEventRecord {
70 public:
71 Address start;
72 CodeEntry* entry;
73 unsigned size;
74
lrn@chromium.org25156de2010-04-06 13:10:27 +000075 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000076};
77
78
79class CodeMoveEventRecord : public CodeEventRecord {
80 public:
81 Address from;
82 Address to;
83
lrn@chromium.org25156de2010-04-06 13:10:27 +000084 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000085};
86
87
88class CodeDeleteEventRecord : public CodeEventRecord {
89 public:
90 Address start;
91
lrn@chromium.org25156de2010-04-06 13:10:27 +000092 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000093};
94
95
96class CodeAliasEventRecord : public CodeEventRecord {
97 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000098 Address start;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000099 CodeEntry* entry;
100 Address code_start;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000101
lrn@chromium.org25156de2010-04-06 13:10:27 +0000102 INLINE(void UpdateCodeMap(CodeMap* code_map));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000103};
104
105
lrn@chromium.org25156de2010-04-06 13:10:27 +0000106class TickSampleEventRecord BASE_EMBEDDED {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000107 public:
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000108 TickSampleEventRecord()
109 : filler(1) {
110 ASSERT(filler != SamplingCircularQueue::kClear);
111 }
112
ager@chromium.org357bf652010-04-12 11:30:10 +0000113 // The first machine word of a TickSampleEventRecord must not ever
114 // become equal to SamplingCircularQueue::kClear. As both order and
115 // TickSample's first field are not reliable in this sense (order
116 // can overflow, TickSample can have all fields reset), we are
117 // forced to use an artificial filler field.
118 int filler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000119 unsigned order;
ager@chromium.org357bf652010-04-12 11:30:10 +0000120 TickSample sample;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000121
lrn@chromium.org25156de2010-04-06 13:10:27 +0000122 static TickSampleEventRecord* cast(void* value) {
123 return reinterpret_cast<TickSampleEventRecord*>(value);
124 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000125
ager@chromium.org357bf652010-04-12 11:30:10 +0000126 INLINE(static TickSampleEventRecord* init(void* value));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000127};
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 Thread {
133 public:
134 explicit ProfilerEventsProcessor(ProfileGenerator* generator);
135 virtual ~ProfilerEventsProcessor() { }
136
137 // Thread control.
138 virtual void Run();
139 inline void Stop() { running_ = false; }
140 INLINE(bool running()) { return running_; }
141
142 // Events adding methods. Called by VM threads.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000143 void CallbackCreateEvent(Logger::LogEventsAndTags tag,
144 const char* prefix, String* name,
145 Address start);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000146 void CodeCreateEvent(Logger::LogEventsAndTags tag,
147 String* name,
148 String* resource_name, int line_number,
149 Address start, unsigned size);
150 void CodeCreateEvent(Logger::LogEventsAndTags tag,
151 const char* name,
152 Address start, unsigned size);
153 void CodeCreateEvent(Logger::LogEventsAndTags tag,
154 int args_count,
155 Address start, unsigned size);
156 void CodeMoveEvent(Address from, Address to);
157 void CodeDeleteEvent(Address from);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000158 void FunctionCreateEvent(Address alias, Address start, int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000159 void FunctionMoveEvent(Address from, Address to);
160 void FunctionDeleteEvent(Address from);
ager@chromium.org357bf652010-04-12 11:30:10 +0000161 void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
162 const char* prefix, String* name,
163 Address start, unsigned size);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000164 // Puts current stack into tick sample events buffer.
165 void AddCurrentStack();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000166
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000167 // Tick sample events are filled directly in the buffer of the circular
168 // queue (because the structure is of fixed width, but usually not all
169 // stack frame entries are filled.) This method returns a pointer to the
170 // next record of the buffer.
171 INLINE(TickSample* TickSampleEvent());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000172
173 private:
174 union CodeEventsContainer {
175 CodeEventRecord generic;
176#define DECLARE_CLASS(ignore, type) type type##_;
177 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
178#undef DECLARE_TYPE
179 };
180
181 // Called from events processing thread (Run() method.)
182 bool ProcessCodeEvent(unsigned* dequeue_order);
183 bool ProcessTicks(unsigned dequeue_order);
184
ager@chromium.org357bf652010-04-12 11:30:10 +0000185 INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
186
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000187 ProfileGenerator* generator_;
188 bool running_;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000189 UnboundQueue<CodeEventsContainer> events_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000190 SamplingCircularQueue ticks_buffer_;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000191 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000192 unsigned enqueue_order_;
193};
194
lrn@chromium.org25156de2010-04-06 13:10:27 +0000195} } // namespace v8::internal
196
197
198#define PROFILE(Call) \
199 LOG(Call); \
200 do { \
201 if (v8::internal::CpuProfiler::is_profiling()) { \
202 v8::internal::CpuProfiler::Call; \
203 } \
204 } while (false)
205#else
206#define PROFILE(Call) LOG(Call)
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000207#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000208
209
210namespace v8 {
211namespace internal {
212
213class CpuProfiler {
214 public:
215 static void Setup();
216 static void TearDown();
217
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000218#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000219 static void StartProfiling(const char* title);
220 static void StartProfiling(String* title);
221 static CpuProfile* StopProfiling(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000222 static CpuProfile* StopProfiling(Object* security_token, String* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000223 static int GetProfilesCount();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000224 static CpuProfile* GetProfile(Object* security_token, int index);
225 static CpuProfile* FindProfile(Object* security_token, unsigned uid);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000226
227 // Invoked from stack sampler (thread or signal handler.)
228 static TickSample* TickSampleEvent();
229
230 // Must be called via PROFILE macro, otherwise will crash when
231 // profiling is not enabled.
232 static void CallbackEvent(String* name, Address entry_point);
233 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
234 Code* code, const char* comment);
235 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
236 Code* code, String* name);
237 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
238 Code* code, String* name,
239 String* source, int line);
240 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
241 Code* code, int args_count);
242 static void CodeMoveEvent(Address from, Address to);
243 static void CodeDeleteEvent(Address from);
244 static void FunctionCreateEvent(JSFunction* function);
245 static void FunctionMoveEvent(Address from, Address to);
246 static void FunctionDeleteEvent(Address from);
247 static void GetterCallbackEvent(String* name, Address entry_point);
248 static void RegExpCodeCreateEvent(Code* code, String* source);
249 static void SetterCallbackEvent(String* name, Address entry_point);
250
251 static INLINE(bool is_profiling()) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000252 return singleton_ != NULL && singleton_->processor_ != NULL;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000253 }
254
255 private:
256 CpuProfiler();
257 ~CpuProfiler();
258 void StartCollectingProfile(const char* title);
259 void StartCollectingProfile(String* title);
260 void StartProcessorIfNotStarted();
261 CpuProfile* StopCollectingProfile(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000262 CpuProfile* StopCollectingProfile(Object* security_token, String* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000263 void StopProcessorIfLastProfile();
264
265 CpuProfilesCollection* profiles_;
266 unsigned next_profile_uid_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000267 TokenEnumerator* token_enumerator_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000268 ProfileGenerator* generator_;
269 ProfilerEventsProcessor* processor_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000270 int saved_logging_nesting_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000271
272 static CpuProfiler* singleton_;
273
274#else
275 static INLINE(bool is_profiling()) { return false; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000276#endif // ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org25156de2010-04-06 13:10:27 +0000277
278 private:
279 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
280};
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000281
282} } // namespace v8::internal
283
lrn@chromium.org25156de2010-04-06 13:10:27 +0000284
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000285#endif // V8_CPU_PROFILER_H_