blob: ed3f6925e083cee4c39d262b4ef4fa3a3352d780 [file] [log] [blame]
Steve Block6ded16b2010-05-10 14:33:55 +01001// 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#include "v8.h"
29
30#include "cpu-profiler-inl.h"
31
32#ifdef ENABLE_LOGGING_AND_PROFILING
33
34#include "log-inl.h"
35
36#include "../include/v8-profiler.h"
37
38namespace v8 {
39namespace internal {
40
41static const int kEventsBufferSize = 256*KB;
42static const int kTickSamplesBufferChunkSize = 64*KB;
43static const int kTickSamplesBufferChunksCount = 16;
44
45
46ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
47 : generator_(generator),
48 running_(false),
49 events_buffer_(kEventsBufferSize),
50 ticks_buffer_(sizeof(TickSampleEventRecord),
51 kTickSamplesBufferChunkSize,
52 kTickSamplesBufferChunksCount),
53 enqueue_order_(0) { }
54
55
56void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
57 const char* prefix,
58 String* name,
59 Address start) {
60 if (FilterOutCodeCreateEvent(tag)) return;
61 CodeEventsContainer evt_rec;
62 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
63 rec->type = CodeEventRecord::CODE_CREATION;
64 rec->order = ++enqueue_order_;
65 rec->start = start;
66 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
67 rec->size = 1;
68 events_buffer_.Enqueue(evt_rec);
69}
70
71
72void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
73 String* name,
74 String* resource_name,
75 int line_number,
76 Address start,
77 unsigned size) {
78 if (FilterOutCodeCreateEvent(tag)) return;
79 CodeEventsContainer evt_rec;
80 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
81 rec->type = CodeEventRecord::CODE_CREATION;
82 rec->order = ++enqueue_order_;
83 rec->start = start;
84 rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
85 rec->size = size;
86 events_buffer_.Enqueue(evt_rec);
87}
88
89
90void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
91 const char* name,
92 Address start,
93 unsigned size) {
94 if (FilterOutCodeCreateEvent(tag)) return;
95 CodeEventsContainer evt_rec;
96 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
97 rec->type = CodeEventRecord::CODE_CREATION;
98 rec->order = ++enqueue_order_;
99 rec->start = start;
100 rec->entry = generator_->NewCodeEntry(tag, name);
101 rec->size = size;
102 events_buffer_.Enqueue(evt_rec);
103}
104
105
106void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
107 int args_count,
108 Address start,
109 unsigned size) {
110 if (FilterOutCodeCreateEvent(tag)) return;
111 CodeEventsContainer evt_rec;
112 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
113 rec->type = CodeEventRecord::CODE_CREATION;
114 rec->order = ++enqueue_order_;
115 rec->start = start;
116 rec->entry = generator_->NewCodeEntry(tag, args_count);
117 rec->size = size;
118 events_buffer_.Enqueue(evt_rec);
119}
120
121
122void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
123 CodeEventsContainer evt_rec;
124 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
125 rec->type = CodeEventRecord::CODE_MOVE;
126 rec->order = ++enqueue_order_;
127 rec->from = from;
128 rec->to = to;
129 events_buffer_.Enqueue(evt_rec);
130}
131
132
133void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
134 CodeEventsContainer evt_rec;
135 CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
136 rec->type = CodeEventRecord::CODE_DELETE;
137 rec->order = ++enqueue_order_;
138 rec->start = from;
139 events_buffer_.Enqueue(evt_rec);
140}
141
142
143void ProfilerEventsProcessor::FunctionCreateEvent(Address alias,
144 Address start) {
145 CodeEventsContainer evt_rec;
146 CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_;
147 rec->type = CodeEventRecord::CODE_ALIAS;
148 rec->order = ++enqueue_order_;
149 rec->alias = alias;
150 rec->start = start;
151 events_buffer_.Enqueue(evt_rec);
152}
153
154
155void ProfilerEventsProcessor::FunctionMoveEvent(Address from, Address to) {
156 CodeMoveEvent(from, to);
157}
158
159
160void ProfilerEventsProcessor::FunctionDeleteEvent(Address from) {
161 CodeDeleteEvent(from);
162}
163
164
165void ProfilerEventsProcessor::RegExpCodeCreateEvent(
166 Logger::LogEventsAndTags tag,
167 const char* prefix,
168 String* name,
169 Address start,
170 unsigned size) {
171 if (FilterOutCodeCreateEvent(tag)) return;
172 CodeEventsContainer evt_rec;
173 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
174 rec->type = CodeEventRecord::CODE_CREATION;
175 rec->order = ++enqueue_order_;
176 rec->start = start;
177 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
178 rec->size = size;
179 events_buffer_.Enqueue(evt_rec);
180}
181
182
183bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
184 if (!events_buffer_.IsEmpty()) {
185 CodeEventsContainer record;
186 events_buffer_.Dequeue(&record);
187 switch (record.generic.type) {
188#define PROFILER_TYPE_CASE(type, clss) \
189 case CodeEventRecord::type: \
190 record.clss##_.UpdateCodeMap(generator_->code_map()); \
191 break;
192
193 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
194
195#undef PROFILER_TYPE_CASE
196 default: return true; // Skip record.
197 }
198 *dequeue_order = record.generic.order;
199 return true;
200 }
201 return false;
202}
203
204
205bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
206 while (true) {
207 const TickSampleEventRecord* rec =
208 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
209 if (rec == NULL) return false;
210 if (rec->order == dequeue_order) {
211 generator_->RecordTickSample(rec->sample);
212 ticks_buffer_.FinishDequeue();
213 } else {
214 return true;
215 }
216 }
217}
218
219
220void ProfilerEventsProcessor::Run() {
221 unsigned dequeue_order = 0;
222 running_ = true;
223
224 while (running_) {
225 // Process ticks until we have any.
226 if (ProcessTicks(dequeue_order)) {
227 // All ticks of the current dequeue_order are processed,
228 // proceed to the next code event.
229 ProcessCodeEvent(&dequeue_order);
230 }
231 YieldCPU();
232 }
233
234 // Process remaining tick events.
235 ticks_buffer_.FlushResidualRecords();
236 // Perform processing until we have tick events, skip remaining code events.
237 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
238}
239
240
241CpuProfiler* CpuProfiler::singleton_ = NULL;
242
243void CpuProfiler::StartProfiling(const char* title) {
244 ASSERT(singleton_ != NULL);
245 singleton_->StartCollectingProfile(title);
246}
247
248
249void CpuProfiler::StartProfiling(String* title) {
250 ASSERT(singleton_ != NULL);
251 singleton_->StartCollectingProfile(title);
252}
253
254
255CpuProfile* CpuProfiler::StopProfiling(const char* title) {
256 return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL;
257}
258
259
260CpuProfile* CpuProfiler::StopProfiling(String* title) {
261 return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL;
262}
263
264
265int CpuProfiler::GetProfilesCount() {
266 ASSERT(singleton_ != NULL);
267 return singleton_->profiles_->profiles()->length();
268}
269
270
271CpuProfile* CpuProfiler::GetProfile(int index) {
272 ASSERT(singleton_ != NULL);
273 return singleton_->profiles_->profiles()->at(index);
274}
275
276
277CpuProfile* CpuProfiler::FindProfile(unsigned uid) {
278 ASSERT(singleton_ != NULL);
279 return singleton_->profiles_->GetProfile(uid);
280}
281
282
283TickSample* CpuProfiler::TickSampleEvent() {
284 if (CpuProfiler::is_profiling()) {
285 return singleton_->processor_->TickSampleEvent();
286 } else {
287 return NULL;
288 }
289}
290
291
292void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
293 singleton_->processor_->CallbackCreateEvent(
294 Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
295}
296
297
298void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
299 Code* code, const char* comment) {
300 singleton_->processor_->CodeCreateEvent(
301 tag, comment, code->address(), code->ExecutableSize());
302}
303
304
305void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
306 Code* code, String* name) {
307 singleton_->processor_->CodeCreateEvent(
308 tag,
309 name,
310 Heap::empty_string(),
311 v8::CpuProfileNode::kNoLineNumberInfo,
312 code->address(),
313 code->ExecutableSize());
314}
315
316
317void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
318 Code* code, String* name,
319 String* source, int line) {
320 singleton_->processor_->CodeCreateEvent(
321 tag,
322 name,
323 source,
324 line,
325 code->address(),
326 code->ExecutableSize());
327}
328
329
330void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
331 Code* code, int args_count) {
332 singleton_->processor_->CodeCreateEvent(
333 tag,
334 args_count,
335 code->address(),
336 code->ExecutableSize());
337}
338
339
340void CpuProfiler::CodeMoveEvent(Address from, Address to) {
341 singleton_->processor_->CodeMoveEvent(from, to);
342}
343
344
345void CpuProfiler::CodeDeleteEvent(Address from) {
346 singleton_->processor_->CodeDeleteEvent(from);
347}
348
349
350void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
351 singleton_->processor_->FunctionCreateEvent(
352 function->address(), function->code()->address());
353}
354
355
356void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
357 singleton_->processor_->FunctionMoveEvent(from, to);
358}
359
360
361void CpuProfiler::FunctionDeleteEvent(Address from) {
362 singleton_->processor_->FunctionDeleteEvent(from);
363}
364
365
366void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
367 singleton_->processor_->CallbackCreateEvent(
368 Logger::CALLBACK_TAG, "get ", name, entry_point);
369}
370
371
372void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
373 singleton_->processor_->RegExpCodeCreateEvent(
374 Logger::REG_EXP_TAG,
375 "RegExp: ",
376 source,
377 code->address(),
378 code->ExecutableSize());
379}
380
381
382void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
383 singleton_->processor_->CallbackCreateEvent(
384 Logger::CALLBACK_TAG, "set ", name, entry_point);
385}
386
387
388CpuProfiler::CpuProfiler()
389 : profiles_(new CpuProfilesCollection()),
390 next_profile_uid_(1),
391 generator_(NULL),
392 processor_(NULL) {
393}
394
395
396CpuProfiler::~CpuProfiler() {
397 delete profiles_;
398}
399
400
401void CpuProfiler::StartCollectingProfile(const char* title) {
402 if (profiles_->StartProfiling(title, next_profile_uid_++)) {
403 StartProcessorIfNotStarted();
404 }
405}
406
407
408void CpuProfiler::StartCollectingProfile(String* title) {
409 if (profiles_->StartProfiling(title, next_profile_uid_++)) {
410 StartProcessorIfNotStarted();
411 }
412}
413
414
415void CpuProfiler::StartProcessorIfNotStarted() {
416 if (processor_ == NULL) {
417 // Disable logging when using the new implementation.
418 saved_logging_nesting_ = Logger::logging_nesting_;
419 Logger::logging_nesting_ = 0;
420 generator_ = new ProfileGenerator(profiles_);
421 processor_ = new ProfilerEventsProcessor(generator_);
422 processor_->Start();
423 // Enable stack sampling.
424 // It is important to have it started prior to logging, see issue 683:
425 // http://code.google.com/p/v8/issues/detail?id=683
426 reinterpret_cast<Sampler*>(Logger::ticker_)->Start();
427 // Enumerate stuff we already have in the heap.
428 if (Heap::HasBeenSetup()) {
429 Logger::LogCodeObjects();
430 Logger::LogCompiledFunctions();
431 Logger::LogFunctionObjects();
432 Logger::LogAccessorCallbacks();
433 }
434 }
435}
436
437
438CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
439 const double actual_sampling_rate = generator_->actual_sampling_rate();
440 StopProcessorIfLastProfile();
441 CpuProfile* result = profiles_->StopProfiling(title, actual_sampling_rate);
442 if (result != NULL) {
443 result->Print();
444 }
445 return result;
446}
447
448
449CpuProfile* CpuProfiler::StopCollectingProfile(String* title) {
450 const double actual_sampling_rate = generator_->actual_sampling_rate();
451 StopProcessorIfLastProfile();
452 return profiles_->StopProfiling(title, actual_sampling_rate);
453}
454
455
456void CpuProfiler::StopProcessorIfLastProfile() {
457 if (profiles_->is_last_profile()) {
458 reinterpret_cast<Sampler*>(Logger::ticker_)->Stop();
459 processor_->Stop();
460 processor_->Join();
461 delete processor_;
462 delete generator_;
463 processor_ = NULL;
464 generator_ = NULL;
465 Logger::logging_nesting_ = saved_logging_nesting_;
466 }
467}
468
469} } // namespace v8::internal
470
471#endif // ENABLE_LOGGING_AND_PROFILING
472
473namespace v8 {
474namespace internal {
475
476void CpuProfiler::Setup() {
477#ifdef ENABLE_LOGGING_AND_PROFILING
478 if (singleton_ == NULL) {
479 singleton_ = new CpuProfiler();
480 }
481#endif
482}
483
484
485void CpuProfiler::TearDown() {
486#ifdef ENABLE_LOGGING_AND_PROFILING
487 if (singleton_ != NULL) {
488 delete singleton_;
489 }
490 singleton_ = NULL;
491#endif
492}
493
494} } // namespace v8::internal