blob: 4175e8f6805fa2fd08d4382e8fc97940b435bb13 [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
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;
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
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000048#define CODE_EVENTS_TYPE_LIST(V) \
49 V(CODE_CREATION, CodeCreateEventRecord) \
50 V(CODE_MOVE, CodeMoveEventRecord) \
51 V(CODE_DELETE, CodeDeleteEventRecord) \
52 V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000053
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;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000075 Address shared;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000076
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
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000098class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000099 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000100 Address from;
101 Address to;
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
ager@chromium.org04921a82011-06-27 13:21:41 +0000107class TickSampleEventRecord {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000108 public:
ager@chromium.org04921a82011-06-27 13:21:41 +0000109 // The parameterless constructor is used when we dequeue data from
110 // the ticks buffer.
111 TickSampleEventRecord() { }
112 explicit TickSampleEventRecord(unsigned order)
113 : filler(1),
114 order(order) {
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000115 ASSERT(filler != SamplingCircularQueue::kClear);
116 }
117
ager@chromium.org357bf652010-04-12 11:30:10 +0000118 // The first machine word of a TickSampleEventRecord must not ever
119 // become equal to SamplingCircularQueue::kClear. As both order and
120 // TickSample's first field are not reliable in this sense (order
121 // can overflow, TickSample can have all fields reset), we are
122 // forced to use an artificial filler field.
123 int filler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000124 unsigned order;
ager@chromium.org357bf652010-04-12 11:30:10 +0000125 TickSample sample;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000126
lrn@chromium.org25156de2010-04-06 13:10:27 +0000127 static TickSampleEventRecord* cast(void* value) {
128 return reinterpret_cast<TickSampleEventRecord*>(value);
129 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000130};
131
132
133// This class implements both the profile events processor thread and
134// methods called by event producers: VM and stack sampler threads.
135class ProfilerEventsProcessor : public Thread {
136 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000137 explicit ProfilerEventsProcessor(ProfileGenerator* generator);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000138 virtual ~ProfilerEventsProcessor() {}
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000139
140 // Thread control.
141 virtual void Run();
142 inline void Stop() { running_ = false; }
143 INLINE(bool running()) { return running_; }
144
145 // Events adding methods. Called by VM threads.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000146 void CallbackCreateEvent(Logger::LogEventsAndTags tag,
147 const char* prefix, String* name,
148 Address start);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000149 void CodeCreateEvent(Logger::LogEventsAndTags tag,
150 String* name,
151 String* resource_name, int line_number,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000152 Address start, unsigned size,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000153 Address shared);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000154 void CodeCreateEvent(Logger::LogEventsAndTags tag,
155 const char* name,
156 Address start, unsigned size);
157 void CodeCreateEvent(Logger::LogEventsAndTags tag,
158 int args_count,
159 Address start, unsigned size);
160 void CodeMoveEvent(Address from, Address to);
161 void CodeDeleteEvent(Address from);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000162 void SharedFunctionInfoMoveEvent(Address from, Address to);
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.orgcec079d2010-03-22 14:44:04 +0000168
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000169 // Tick sample events are filled directly in the buffer of the circular
170 // queue (because the structure is of fixed width, but usually not all
171 // stack frame entries are filled.) This method returns a pointer to the
172 // next record of the buffer.
173 INLINE(TickSample* TickSampleEvent());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000174
175 private:
176 union CodeEventsContainer {
177 CodeEventRecord generic;
178#define DECLARE_CLASS(ignore, type) type type##_;
179 CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
180#undef DECLARE_TYPE
181 };
182
183 // Called from events processing thread (Run() method.)
184 bool ProcessCodeEvent(unsigned* dequeue_order);
185 bool ProcessTicks(unsigned dequeue_order);
186
ager@chromium.org357bf652010-04-12 11:30:10 +0000187 INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
188
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000189 ProfileGenerator* generator_;
190 bool running_;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000191 UnboundQueue<CodeEventsContainer> events_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000192 SamplingCircularQueue ticks_buffer_;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000193 UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000194 unsigned enqueue_order_;
195};
196
lrn@chromium.org25156de2010-04-06 13:10:27 +0000197} } // namespace v8::internal
198
199
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000200#define PROFILE(isolate, Call) \
201 LOG(isolate, Call); \
202 do { \
203 if (v8::internal::CpuProfiler::is_profiling(isolate)) { \
204 v8::internal::CpuProfiler::Call; \
205 } \
lrn@chromium.org25156de2010-04-06 13:10:27 +0000206 } while (false)
lrn@chromium.org25156de2010-04-06 13:10:27 +0000207
208
209namespace v8 {
210namespace internal {
211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212
213// TODO(isolates): isolatify this class.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000214class CpuProfiler {
215 public:
216 static void Setup();
217 static void TearDown();
218
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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000226 static void DeleteAllProfiles();
227 static void DeleteProfile(CpuProfile* profile);
228 static bool HasDetachedProfiles();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000229
230 // Invoked from stack sampler (thread or signal handler.)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 static TickSample* TickSampleEvent(Isolate* isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000232
233 // Must be called via PROFILE macro, otherwise will crash when
234 // profiling is not enabled.
235 static void CallbackEvent(String* name, Address entry_point);
236 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
237 Code* code, const char* comment);
238 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
239 Code* code, String* name);
240 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000241 Code* code,
242 SharedFunctionInfo *shared,
243 String* name);
244 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
245 Code* code,
246 SharedFunctionInfo *shared,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000247 String* source, int line);
248 static void CodeCreateEvent(Logger::LogEventsAndTags tag,
249 Code* code, int args_count);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000250 static void CodeMovingGCEvent() {}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000251 static void CodeMoveEvent(Address from, Address to);
252 static void CodeDeleteEvent(Address from);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000253 static void GetterCallbackEvent(String* name, Address entry_point);
254 static void RegExpCodeCreateEvent(Code* code, String* source);
255 static void SetterCallbackEvent(String* name, Address entry_point);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000256 static void SharedFunctionInfoMoveEvent(Address from, Address to);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 // TODO(isolates): this doesn't have to use atomics anymore.
259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 static INLINE(bool is_profiling(Isolate* isolate)) {
261 CpuProfiler* profiler = isolate->cpu_profiler();
262 return profiler != NULL && NoBarrier_Load(&profiler->is_profiling_);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000263 }
264
265 private:
266 CpuProfiler();
267 ~CpuProfiler();
268 void StartCollectingProfile(const char* title);
269 void StartCollectingProfile(String* title);
270 void StartProcessorIfNotStarted();
271 CpuProfile* StopCollectingProfile(const char* title);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000272 CpuProfile* StopCollectingProfile(Object* security_token, String* title);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000273 void StopProcessorIfLastProfile(const char* title);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 void StopProcessor();
275 void ResetProfiles();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000276
277 CpuProfilesCollection* profiles_;
278 unsigned next_profile_uid_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000279 TokenEnumerator* token_enumerator_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000280 ProfileGenerator* generator_;
281 ProfilerEventsProcessor* processor_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000282 int saved_logging_nesting_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 bool need_to_stop_sampler_;
284 Atomic32 is_profiling_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000285
lrn@chromium.org25156de2010-04-06 13:10:27 +0000286 private:
287 DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
288};
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000289
290} } // namespace v8::internal
291
lrn@chromium.org25156de2010-04-06 13:10:27 +0000292
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000293#endif // V8_CPU_PROFILER_H_