blob: 187cbbf18f2ec479425a6c9ed9b13692f7b01d00 [file] [log] [blame]
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001// Copyright 2012 the V8 project authors. All rights reserved.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00002// 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
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "atomicops.h"
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
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000047#define CODE_EVENTS_TYPE_LIST(V) \
48 V(CODE_CREATION, CodeCreateEventRecord) \
49 V(CODE_MOVE, CodeMoveEventRecord) \
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000050 V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000051
52
53class CodeEventRecord {
54 public:
55#define DECLARE_TYPE(type, ignore) type,
56 enum Type {
57 NONE = 0,
58 CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
59 NUMBER_OF_TYPES
60 };
61#undef DECLARE_TYPE
62
63 Type type;
64 unsigned order;
65};
66
67
68class CodeCreateEventRecord : public CodeEventRecord {
69 public:
70 Address start;
71 CodeEntry* entry;
72 unsigned size;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000073 Address shared;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000074
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
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000088class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000089 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000090 Address from;
91 Address to;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000092
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
ager@chromium.org04921a82011-06-27 13:21:41 +000097class TickSampleEventRecord {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000098 public:
ager@chromium.org04921a82011-06-27 13:21:41 +000099 // The parameterless constructor is used when we dequeue data from
100 // the ticks buffer.
101 TickSampleEventRecord() { }
102 explicit TickSampleEventRecord(unsigned order)
103 : filler(1),
104 order(order) {
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000105 ASSERT(filler != SamplingCircularQueue::kClear);
106 }
107
ager@chromium.org357bf652010-04-12 11:30:10 +0000108 // The first machine word of a TickSampleEventRecord must not ever
109 // become equal to SamplingCircularQueue::kClear. As both order and
110 // TickSample's first field are not reliable in this sense (order
111 // can overflow, TickSample can have all fields reset), we are
112 // forced to use an artificial filler field.
113 int filler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000114 unsigned order;
ager@chromium.org357bf652010-04-12 11:30:10 +0000115 TickSample sample;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000116
lrn@chromium.org25156de2010-04-06 13:10:27 +0000117 static TickSampleEventRecord* cast(void* value) {
118 return reinterpret_cast<TickSampleEventRecord*>(value);
119 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000120};
121
122
123// This class implements both the profile events processor thread and
124// methods called by event producers: VM and stack sampler threads.
125class ProfilerEventsProcessor : public Thread {
126 public:
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000127 ProfilerEventsProcessor(ProfileGenerator* generator,
128 Sampler* sampler,
129 int period_in_useconds);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000130 virtual ~ProfilerEventsProcessor() {}
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000131
132 // Thread control.
133 virtual void Run();
134 inline void Stop() { running_ = false; }
135 INLINE(bool running()) { return running_; }
136
137 // Events adding methods. Called by VM threads.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000138 void CallbackCreateEvent(Logger::LogEventsAndTags tag,
139 const char* prefix, String* name,
140 Address start);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000141 void CodeCreateEvent(Logger::LogEventsAndTags tag,
142 String* name,
143 String* resource_name, int line_number,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000144 Address start, unsigned size,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000145 Address shared);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000146 void CodeCreateEvent(Logger::LogEventsAndTags tag,
147 const char* name,
148 Address start, unsigned size);
149 void CodeCreateEvent(Logger::LogEventsAndTags tag,
150 int args_count,
151 Address start, unsigned size);
152 void CodeMoveEvent(Address from, Address to);
153 void CodeDeleteEvent(Address from);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000154 void SharedFunctionInfoMoveEvent(Address from, Address to);
ager@chromium.org357bf652010-04-12 11:30:10 +0000155 void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
156 const char* prefix, String* name,
157 Address start, unsigned size);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000158 // Puts current stack into tick sample events buffer.
159 void AddCurrentStack();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000160
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000161 // Tick sample events are filled directly in the buffer of the circular
162 // queue (because the structure is of fixed width, but usually not all
163 // stack frame entries are filled.) This method returns a pointer to the
164 // next record of the buffer.
165 INLINE(TickSample* TickSampleEvent());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000166
167 private:
168 union CodeEventsContainer {
169 CodeEventRecord generic;
170#define DECLARE_CLASS(ignore, type) type type##_;
171 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
172#undef DECLARE_TYPE
173 };
174
175 // Called from events processing thread (Run() method.)
176 bool ProcessCodeEvent(unsigned* dequeue_order);
177 bool ProcessTicks(unsigned dequeue_order);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000178 void ProcessEventsAndDoSample(unsigned* dequeue_order);
179 void ProcessEventsAndYield(unsigned* dequeue_order);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000180
ager@chromium.org357bf652010-04-12 11:30:10 +0000181 INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
182
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000183 ProfileGenerator* generator_;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000184 Sampler* sampler_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000185 bool running_;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000186 // Sampling period in microseconds.
187 const int period_in_useconds_;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000188 UnboundQueue<CodeEventsContainer> events_buffer_;
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000189 SamplingCircularQueue ticks_buffer_;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000190 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000191 unsigned enqueue_order_;
192};
193
lrn@chromium.org25156de2010-04-06 13:10:27 +0000194} } // namespace v8::internal
195
196
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000197#define PROFILE(isolate, Call) \
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000198 LOG_CODE_EVENT(isolate, Call); \
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000199 do { \
200 if (v8::internal::CpuProfiler::is_profiling(isolate)) { \
201 v8::internal::CpuProfiler::Call; \
202 } \
lrn@chromium.org25156de2010-04-06 13:10:27 +0000203 } while (false)
lrn@chromium.org25156de2010-04-06 13:10:27 +0000204
205
206namespace v8 {
207namespace internal {
208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209
210// TODO(isolates): isolatify this class.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000211class CpuProfiler {
212 public:
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000213 static void SetUp();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000214 static void TearDown();
215
lrn@chromium.org25156de2010-04-06 13:10:27 +0000216 static void StartProfiling(const char* title);
217 static void StartProfiling(String* title);
218 static CpuProfile* StopProfiling(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000219 static CpuProfile* StopProfiling(Object* security_token, String* title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000220 static int GetProfilesCount();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000221 static CpuProfile* GetProfile(Object* security_token, int index);
222 static CpuProfile* FindProfile(Object* security_token, unsigned uid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000223 static void DeleteAllProfiles();
224 static void DeleteProfile(CpuProfile* profile);
225 static bool HasDetachedProfiles();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000226
227 // Invoked from stack sampler (thread or signal handler.)
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000228 static TickSample* TickSampleEvent(Isolate* isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000229
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,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000238 Code* code,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000239 SharedFunctionInfo* shared,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000240 String* name);
241 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
242 Code* code,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000243 SharedFunctionInfo* shared,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000244 String* source, int line);
245 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
246 Code* code, int args_count);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000247 static void CodeMovingGCEvent() {}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000248 static void CodeMoveEvent(Address from, Address to);
249 static void CodeDeleteEvent(Address from);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000250 static void GetterCallbackEvent(String* name, Address entry_point);
251 static void RegExpCodeCreateEvent(Code* code, String* source);
252 static void SetterCallbackEvent(String* name, Address entry_point);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000253 static void SharedFunctionInfoMoveEvent(Address from, Address to);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000254
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000255 static INLINE(bool is_profiling(Isolate* isolate)) {
256 CpuProfiler* profiler = isolate->cpu_profiler();
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000257 return profiler != NULL && profiler->is_profiling_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000258 }
259
260 private:
261 CpuProfiler();
262 ~CpuProfiler();
263 void StartCollectingProfile(const char* title);
264 void StartCollectingProfile(String* title);
265 void StartProcessorIfNotStarted();
266 CpuProfile* StopCollectingProfile(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000267 CpuProfile* StopCollectingProfile(Object* security_token, String* title);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000268 void StopProcessorIfLastProfile(const char* title);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 void StopProcessor();
270 void ResetProfiles();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000271
272 CpuProfilesCollection* profiles_;
273 unsigned next_profile_uid_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000274 TokenEnumerator* token_enumerator_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000275 ProfileGenerator* generator_;
276 ProfilerEventsProcessor* processor_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000277 int saved_logging_nesting_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000278 bool need_to_stop_sampler_;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000279 bool is_profiling_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000280
lrn@chromium.org25156de2010-04-06 13:10:27 +0000281 private:
282 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
283};
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000284
285} } // namespace v8::internal
286
lrn@chromium.org25156de2010-04-06 13:10:27 +0000287
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000288#endif // V8_CPU_PROFILER_H_