blob: f13c0eefabe7caf45c1058ccf52564b6549bf0b4 [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
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010034#include "frames-inl.h"
Kristian Monsen0d5e1162010-09-30 15:31:59 +010035#include "hashmap.h"
Steve Block6ded16b2010-05-10 14:33:55 +010036#include "log-inl.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037#include "vm-state-inl.h"
Steve Block6ded16b2010-05-10 14:33:55 +010038
39#include "../include/v8-profiler.h"
40
41namespace v8 {
42namespace internal {
43
44static const int kEventsBufferSize = 256*KB;
45static const int kTickSamplesBufferChunkSize = 64*KB;
46static const int kTickSamplesBufferChunksCount = 16;
47
48
49ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
50 : generator_(generator),
Steve Block791712a2010-08-27 10:21:07 +010051 running_(true),
Steve Block6ded16b2010-05-10 14:33:55 +010052 ticks_buffer_(sizeof(TickSampleEventRecord),
53 kTickSamplesBufferChunkSize,
54 kTickSamplesBufferChunksCount),
Kristian Monsen0d5e1162010-09-30 15:31:59 +010055 enqueue_order_(0),
56 known_functions_(new HashMap(AddressesMatch)) {
57}
58
59
60ProfilerEventsProcessor::~ProfilerEventsProcessor() {
61 delete known_functions_;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010062}
Steve Block6ded16b2010-05-10 14:33:55 +010063
64
65void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
66 const char* prefix,
67 String* name,
68 Address start) {
69 if (FilterOutCodeCreateEvent(tag)) return;
70 CodeEventsContainer evt_rec;
71 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
72 rec->type = CodeEventRecord::CODE_CREATION;
73 rec->order = ++enqueue_order_;
74 rec->start = start;
75 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
76 rec->size = 1;
77 events_buffer_.Enqueue(evt_rec);
78}
79
80
81void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
82 String* name,
83 String* resource_name,
84 int line_number,
85 Address start,
86 unsigned size) {
87 if (FilterOutCodeCreateEvent(tag)) return;
88 CodeEventsContainer evt_rec;
89 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
90 rec->type = CodeEventRecord::CODE_CREATION;
91 rec->order = ++enqueue_order_;
92 rec->start = start;
93 rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
94 rec->size = size;
95 events_buffer_.Enqueue(evt_rec);
96}
97
98
99void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
100 const char* name,
101 Address start,
102 unsigned size) {
103 if (FilterOutCodeCreateEvent(tag)) return;
104 CodeEventsContainer evt_rec;
105 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
106 rec->type = CodeEventRecord::CODE_CREATION;
107 rec->order = ++enqueue_order_;
108 rec->start = start;
109 rec->entry = generator_->NewCodeEntry(tag, name);
110 rec->size = size;
111 events_buffer_.Enqueue(evt_rec);
112}
113
114
115void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
116 int args_count,
117 Address start,
118 unsigned size) {
119 if (FilterOutCodeCreateEvent(tag)) return;
120 CodeEventsContainer evt_rec;
121 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
122 rec->type = CodeEventRecord::CODE_CREATION;
123 rec->order = ++enqueue_order_;
124 rec->start = start;
125 rec->entry = generator_->NewCodeEntry(tag, args_count);
126 rec->size = size;
127 events_buffer_.Enqueue(evt_rec);
128}
129
130
131void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
132 CodeEventsContainer evt_rec;
133 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
134 rec->type = CodeEventRecord::CODE_MOVE;
135 rec->order = ++enqueue_order_;
136 rec->from = from;
137 rec->to = to;
138 events_buffer_.Enqueue(evt_rec);
139}
140
141
142void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
143 CodeEventsContainer evt_rec;
144 CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
145 rec->type = CodeEventRecord::CODE_DELETE;
146 rec->order = ++enqueue_order_;
147 rec->start = from;
148 events_buffer_.Enqueue(evt_rec);
149}
150
151
152void ProfilerEventsProcessor::FunctionCreateEvent(Address alias,
Leon Clarkef7060e22010-06-03 12:02:55 +0100153 Address start,
154 int security_token_id) {
Steve Block6ded16b2010-05-10 14:33:55 +0100155 CodeEventsContainer evt_rec;
156 CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_;
157 rec->type = CodeEventRecord::CODE_ALIAS;
158 rec->order = ++enqueue_order_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100159 rec->start = alias;
160 rec->entry = generator_->NewCodeEntry(security_token_id);
161 rec->code_start = start;
Steve Block6ded16b2010-05-10 14:33:55 +0100162 events_buffer_.Enqueue(evt_rec);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100163
164 known_functions_->Lookup(alias, AddressHash(alias), true);
Steve Block6ded16b2010-05-10 14:33:55 +0100165}
166
167
168void ProfilerEventsProcessor::FunctionMoveEvent(Address from, Address to) {
169 CodeMoveEvent(from, to);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100170
171 if (IsKnownFunction(from)) {
172 known_functions_->Remove(from, AddressHash(from));
173 known_functions_->Lookup(to, AddressHash(to), true);
174 }
Steve Block6ded16b2010-05-10 14:33:55 +0100175}
176
177
178void ProfilerEventsProcessor::FunctionDeleteEvent(Address from) {
179 CodeDeleteEvent(from);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100180
181 known_functions_->Remove(from, AddressHash(from));
182}
183
184
185bool ProfilerEventsProcessor::IsKnownFunction(Address start) {
186 HashMap::Entry* entry =
187 known_functions_->Lookup(start, AddressHash(start), false);
188 return entry != NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100189}
190
191
Ben Murdochf87a2032010-10-22 12:50:53 +0100192void ProfilerEventsProcessor::ProcessMovedFunctions() {
193 for (int i = 0; i < moved_functions_.length(); ++i) {
194 JSFunction* function = moved_functions_[i];
195 CpuProfiler::FunctionCreateEvent(function);
196 }
197 moved_functions_.Clear();
198}
199
200
201void ProfilerEventsProcessor::RememberMovedFunction(JSFunction* function) {
202 moved_functions_.Add(function);
203}
204
205
Steve Block6ded16b2010-05-10 14:33:55 +0100206void ProfilerEventsProcessor::RegExpCodeCreateEvent(
207 Logger::LogEventsAndTags tag,
208 const char* prefix,
209 String* name,
210 Address start,
211 unsigned size) {
212 if (FilterOutCodeCreateEvent(tag)) return;
213 CodeEventsContainer evt_rec;
214 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
215 rec->type = CodeEventRecord::CODE_CREATION;
216 rec->order = ++enqueue_order_;
217 rec->start = start;
218 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
219 rec->size = size;
220 events_buffer_.Enqueue(evt_rec);
221}
222
223
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100224void ProfilerEventsProcessor::AddCurrentStack() {
225 TickSampleEventRecord record;
226 TickSample* sample = &record.sample;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100227 sample->state = Top::current_vm_state();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100228 sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
229 sample->frames_count = 0;
230 for (StackTraceFrameIterator it;
231 !it.done() && sample->frames_count < TickSample::kMaxFramesCount;
232 it.Advance()) {
233 JavaScriptFrame* frame = it.frame();
234 sample->stack[sample->frames_count++] =
235 reinterpret_cast<Address>(frame->function());
236 }
237 record.order = enqueue_order_;
238 ticks_from_vm_buffer_.Enqueue(record);
239}
240
241
Steve Block6ded16b2010-05-10 14:33:55 +0100242bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
243 if (!events_buffer_.IsEmpty()) {
244 CodeEventsContainer record;
245 events_buffer_.Dequeue(&record);
246 switch (record.generic.type) {
247#define PROFILER_TYPE_CASE(type, clss) \
248 case CodeEventRecord::type: \
249 record.clss##_.UpdateCodeMap(generator_->code_map()); \
250 break;
251
252 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
253
254#undef PROFILER_TYPE_CASE
255 default: return true; // Skip record.
256 }
257 *dequeue_order = record.generic.order;
258 return true;
259 }
260 return false;
261}
262
263
264bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
265 while (true) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100266 if (!ticks_from_vm_buffer_.IsEmpty()
267 && ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
268 TickSampleEventRecord record;
269 ticks_from_vm_buffer_.Dequeue(&record);
270 generator_->RecordTickSample(record.sample);
271 }
272
Steve Block6ded16b2010-05-10 14:33:55 +0100273 const TickSampleEventRecord* rec =
274 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100275 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
Iain Merrick9ac36c92010-09-13 15:29:50 +0100276 // Make a local copy of tick sample record to ensure that it won't
277 // be modified as we are processing it. This is possible as the
278 // sampler writes w/o any sync to the queue, so if the processor
279 // will get far behind, a record may be modified right under its
280 // feet.
281 TickSampleEventRecord record = *rec;
282 if (record.order == dequeue_order) {
283 // A paranoid check to make sure that we don't get a memory overrun
284 // in case of frames_count having a wild value.
285 if (record.sample.frames_count < 0
286 || record.sample.frames_count >= TickSample::kMaxFramesCount)
287 record.sample.frames_count = 0;
288 generator_->RecordTickSample(record.sample);
Steve Block6ded16b2010-05-10 14:33:55 +0100289 ticks_buffer_.FinishDequeue();
290 } else {
291 return true;
292 }
293 }
294}
295
296
297void ProfilerEventsProcessor::Run() {
298 unsigned dequeue_order = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100299
300 while (running_) {
301 // Process ticks until we have any.
302 if (ProcessTicks(dequeue_order)) {
303 // All ticks of the current dequeue_order are processed,
304 // proceed to the next code event.
305 ProcessCodeEvent(&dequeue_order);
306 }
307 YieldCPU();
308 }
309
310 // Process remaining tick events.
311 ticks_buffer_.FlushResidualRecords();
312 // Perform processing until we have tick events, skip remaining code events.
313 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
314}
315
316
317CpuProfiler* CpuProfiler::singleton_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100318Atomic32 CpuProfiler::is_profiling_ = false;
Steve Block6ded16b2010-05-10 14:33:55 +0100319
320void CpuProfiler::StartProfiling(const char* title) {
321 ASSERT(singleton_ != NULL);
322 singleton_->StartCollectingProfile(title);
323}
324
325
326void CpuProfiler::StartProfiling(String* title) {
327 ASSERT(singleton_ != NULL);
328 singleton_->StartCollectingProfile(title);
329}
330
331
332CpuProfile* CpuProfiler::StopProfiling(const char* title) {
333 return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL;
334}
335
336
Leon Clarkef7060e22010-06-03 12:02:55 +0100337CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
338 return is_profiling() ?
339 singleton_->StopCollectingProfile(security_token, title) : NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100340}
341
342
343int CpuProfiler::GetProfilesCount() {
344 ASSERT(singleton_ != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100345 // The count of profiles doesn't depend on a security token.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100346 return singleton_->profiles_->Profiles(
347 TokenEnumerator::kNoSecurityToken)->length();
Steve Block6ded16b2010-05-10 14:33:55 +0100348}
349
350
Leon Clarkef7060e22010-06-03 12:02:55 +0100351CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
Steve Block6ded16b2010-05-10 14:33:55 +0100352 ASSERT(singleton_ != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100353 const int token = singleton_->token_enumerator_->GetTokenId(security_token);
354 return singleton_->profiles_->Profiles(token)->at(index);
Steve Block6ded16b2010-05-10 14:33:55 +0100355}
356
357
Leon Clarkef7060e22010-06-03 12:02:55 +0100358CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
Steve Block6ded16b2010-05-10 14:33:55 +0100359 ASSERT(singleton_ != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100360 const int token = singleton_->token_enumerator_->GetTokenId(security_token);
361 return singleton_->profiles_->GetProfile(token, uid);
Steve Block6ded16b2010-05-10 14:33:55 +0100362}
363
364
365TickSample* CpuProfiler::TickSampleEvent() {
366 if (CpuProfiler::is_profiling()) {
367 return singleton_->processor_->TickSampleEvent();
368 } else {
369 return NULL;
370 }
371}
372
373
374void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
375 singleton_->processor_->CallbackCreateEvent(
376 Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
377}
378
379
380void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
381 Code* code, const char* comment) {
382 singleton_->processor_->CodeCreateEvent(
383 tag, comment, code->address(), code->ExecutableSize());
384}
385
386
387void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
388 Code* code, String* name) {
389 singleton_->processor_->CodeCreateEvent(
390 tag,
391 name,
392 Heap::empty_string(),
393 v8::CpuProfileNode::kNoLineNumberInfo,
394 code->address(),
395 code->ExecutableSize());
396}
397
398
399void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
400 Code* code, String* name,
401 String* source, int line) {
402 singleton_->processor_->CodeCreateEvent(
403 tag,
404 name,
405 source,
406 line,
407 code->address(),
408 code->ExecutableSize());
409}
410
411
412void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
413 Code* code, int args_count) {
414 singleton_->processor_->CodeCreateEvent(
415 tag,
416 args_count,
417 code->address(),
418 code->ExecutableSize());
419}
420
421
422void CpuProfiler::CodeMoveEvent(Address from, Address to) {
423 singleton_->processor_->CodeMoveEvent(from, to);
424}
425
426
427void CpuProfiler::CodeDeleteEvent(Address from) {
428 singleton_->processor_->CodeDeleteEvent(from);
429}
430
431
432void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100433 int security_token_id = TokenEnumerator::kNoSecurityToken;
Leon Clarkef7060e22010-06-03 12:02:55 +0100434 if (function->unchecked_context()->IsContext()) {
435 security_token_id = singleton_->token_enumerator_->GetTokenId(
436 function->context()->global_context()->security_token());
437 }
Steve Block6ded16b2010-05-10 14:33:55 +0100438 singleton_->processor_->FunctionCreateEvent(
Leon Clarkef7060e22010-06-03 12:02:55 +0100439 function->address(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100440 function->shared()->code()->address(),
Leon Clarkef7060e22010-06-03 12:02:55 +0100441 security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100442}
443
444
Ben Murdochf87a2032010-10-22 12:50:53 +0100445void CpuProfiler::ProcessMovedFunctions() {
446 singleton_->processor_->ProcessMovedFunctions();
447}
448
449
450void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100451 // This function is called from GC iterators (during Scavenge,
452 // MC, and MS), so marking bits can be set on objects. That's
453 // why unchecked accessors are used here.
454
455 // The same function can be reported several times.
456 if (function->unchecked_code() == Builtins::builtin(Builtins::LazyCompile)
457 || singleton_->processor_->IsKnownFunction(function->address())) return;
458
Ben Murdochf87a2032010-10-22 12:50:53 +0100459 singleton_->processor_->RememberMovedFunction(function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100460}
461
462
Steve Block6ded16b2010-05-10 14:33:55 +0100463void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
464 singleton_->processor_->FunctionMoveEvent(from, to);
465}
466
467
468void CpuProfiler::FunctionDeleteEvent(Address from) {
469 singleton_->processor_->FunctionDeleteEvent(from);
470}
471
472
473void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
474 singleton_->processor_->CallbackCreateEvent(
475 Logger::CALLBACK_TAG, "get ", name, entry_point);
476}
477
478
479void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
480 singleton_->processor_->RegExpCodeCreateEvent(
481 Logger::REG_EXP_TAG,
482 "RegExp: ",
483 source,
484 code->address(),
485 code->ExecutableSize());
486}
487
488
489void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
490 singleton_->processor_->CallbackCreateEvent(
491 Logger::CALLBACK_TAG, "set ", name, entry_point);
492}
493
494
495CpuProfiler::CpuProfiler()
496 : profiles_(new CpuProfilesCollection()),
497 next_profile_uid_(1),
Leon Clarkef7060e22010-06-03 12:02:55 +0100498 token_enumerator_(new TokenEnumerator()),
Steve Block6ded16b2010-05-10 14:33:55 +0100499 generator_(NULL),
500 processor_(NULL) {
501}
502
503
504CpuProfiler::~CpuProfiler() {
Leon Clarkef7060e22010-06-03 12:02:55 +0100505 delete token_enumerator_;
Steve Block6ded16b2010-05-10 14:33:55 +0100506 delete profiles_;
507}
508
509
510void CpuProfiler::StartCollectingProfile(const char* title) {
511 if (profiles_->StartProfiling(title, next_profile_uid_++)) {
512 StartProcessorIfNotStarted();
513 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100514 processor_->AddCurrentStack();
Steve Block6ded16b2010-05-10 14:33:55 +0100515}
516
517
518void CpuProfiler::StartCollectingProfile(String* title) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100519 StartCollectingProfile(profiles_->GetName(title));
Steve Block6ded16b2010-05-10 14:33:55 +0100520}
521
522
523void CpuProfiler::StartProcessorIfNotStarted() {
524 if (processor_ == NULL) {
525 // Disable logging when using the new implementation.
526 saved_logging_nesting_ = Logger::logging_nesting_;
527 Logger::logging_nesting_ = 0;
528 generator_ = new ProfileGenerator(profiles_);
529 processor_ = new ProfilerEventsProcessor(generator_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100530 NoBarrier_Store(&is_profiling_, true);
Steve Block6ded16b2010-05-10 14:33:55 +0100531 processor_->Start();
Steve Block6ded16b2010-05-10 14:33:55 +0100532 // Enumerate stuff we already have in the heap.
533 if (Heap::HasBeenSetup()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100534 if (!FLAG_prof_browser_mode) {
535 bool saved_log_code_flag = FLAG_log_code;
536 FLAG_log_code = true;
537 Logger::LogCodeObjects();
538 FLAG_log_code = saved_log_code_flag;
539 }
Steve Block6ded16b2010-05-10 14:33:55 +0100540 Logger::LogCompiledFunctions();
541 Logger::LogFunctionObjects();
542 Logger::LogAccessorCallbacks();
543 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100544 // Enable stack sampling.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100545 Sampler* sampler = reinterpret_cast<Sampler*>(Logger::ticker_);
546 if (!sampler->IsActive()) sampler->Start();
547 sampler->IncreaseProfilingDepth();
Steve Block6ded16b2010-05-10 14:33:55 +0100548 }
549}
550
551
552CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
553 const double actual_sampling_rate = generator_->actual_sampling_rate();
Iain Merrick75681382010-08-19 15:07:18 +0100554 StopProcessorIfLastProfile(title);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100555 CpuProfile* result =
556 profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
557 title,
558 actual_sampling_rate);
Steve Block6ded16b2010-05-10 14:33:55 +0100559 if (result != NULL) {
560 result->Print();
561 }
562 return result;
563}
564
565
Leon Clarkef7060e22010-06-03 12:02:55 +0100566CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
567 String* title) {
Steve Block6ded16b2010-05-10 14:33:55 +0100568 const double actual_sampling_rate = generator_->actual_sampling_rate();
Iain Merrick75681382010-08-19 15:07:18 +0100569 const char* profile_title = profiles_->GetName(title);
570 StopProcessorIfLastProfile(profile_title);
Leon Clarkef7060e22010-06-03 12:02:55 +0100571 int token = token_enumerator_->GetTokenId(security_token);
Iain Merrick75681382010-08-19 15:07:18 +0100572 return profiles_->StopProfiling(token, profile_title, actual_sampling_rate);
Steve Block6ded16b2010-05-10 14:33:55 +0100573}
574
575
Iain Merrick75681382010-08-19 15:07:18 +0100576void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
577 if (profiles_->IsLastProfile(title)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100578 Sampler* sampler = reinterpret_cast<Sampler*>(Logger::ticker_);
579 sampler->DecreaseProfilingDepth();
580 sampler->Stop();
Steve Block6ded16b2010-05-10 14:33:55 +0100581 processor_->Stop();
582 processor_->Join();
583 delete processor_;
584 delete generator_;
585 processor_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100586 NoBarrier_Store(&is_profiling_, false);
Steve Block6ded16b2010-05-10 14:33:55 +0100587 generator_ = NULL;
588 Logger::logging_nesting_ = saved_logging_nesting_;
589 }
590}
591
592} } // namespace v8::internal
593
594#endif // ENABLE_LOGGING_AND_PROFILING
595
596namespace v8 {
597namespace internal {
598
599void CpuProfiler::Setup() {
600#ifdef ENABLE_LOGGING_AND_PROFILING
601 if (singleton_ == NULL) {
602 singleton_ = new CpuProfiler();
603 }
604#endif
605}
606
607
608void CpuProfiler::TearDown() {
609#ifdef ENABLE_LOGGING_AND_PROFILING
610 if (singleton_ != NULL) {
611 delete singleton_;
612 }
613 singleton_ = NULL;
614#endif
615}
616
617} } // namespace v8::internal