1
// Copyright 2012 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
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.
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.
30
#include "cpu-profiler-inl.h"
32
#include "frames-inl.h"
35
#include "vm-state-inl.h"
37
#include "../include/v8-profiler.h"
42
static const int kEventsBufferSize = 256 * KB;
43
static const int kTickSamplesBufferChunkSize = 64 * KB;
44
static const int kTickSamplesBufferChunksCount = 16;
45
static const int kProfilerStackSize = 64 * KB;
48
ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
49
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
50
generator_(generator),
52
ticks_buffer_(sizeof(TickSampleEventRecord),
53
kTickSamplesBufferChunkSize,
54
kTickSamplesBufferChunksCount),
59
void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
63
if (FilterOutCodeCreateEvent(tag)) return;
64
CodeEventsContainer evt_rec;
65
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
66
rec->type = CodeEventRecord::CODE_CREATION;
67
rec->order = ++enqueue_order_;
69
rec->entry = generator_->NewCodeEntry(tag, prefix, name);
72
events_buffer_.Enqueue(evt_rec);
76
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
78
String* resource_name,
83
if (FilterOutCodeCreateEvent(tag)) return;
84
CodeEventsContainer evt_rec;
85
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
86
rec->type = CodeEventRecord::CODE_CREATION;
87
rec->order = ++enqueue_order_;
89
rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
92
events_buffer_.Enqueue(evt_rec);
96
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
100
if (FilterOutCodeCreateEvent(tag)) return;
101
CodeEventsContainer evt_rec;
102
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
103
rec->type = CodeEventRecord::CODE_CREATION;
104
rec->order = ++enqueue_order_;
106
rec->entry = generator_->NewCodeEntry(tag, name);
109
events_buffer_.Enqueue(evt_rec);
113
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
117
if (FilterOutCodeCreateEvent(tag)) return;
118
CodeEventsContainer evt_rec;
119
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
120
rec->type = CodeEventRecord::CODE_CREATION;
121
rec->order = ++enqueue_order_;
123
rec->entry = generator_->NewCodeEntry(tag, args_count);
126
events_buffer_.Enqueue(evt_rec);
130
void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
131
CodeEventsContainer evt_rec;
132
CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
133
rec->type = CodeEventRecord::CODE_MOVE;
134
rec->order = ++enqueue_order_;
137
events_buffer_.Enqueue(evt_rec);
141
void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
143
CodeEventsContainer evt_rec;
144
SharedFunctionInfoMoveEventRecord* rec =
145
&evt_rec.SharedFunctionInfoMoveEventRecord_;
146
rec->type = CodeEventRecord::SHARED_FUNC_MOVE;
147
rec->order = ++enqueue_order_;
150
events_buffer_.Enqueue(evt_rec);
154
void ProfilerEventsProcessor::RegExpCodeCreateEvent(
155
Logger::LogEventsAndTags tag,
160
if (FilterOutCodeCreateEvent(tag)) return;
161
CodeEventsContainer evt_rec;
162
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
163
rec->type = CodeEventRecord::CODE_CREATION;
164
rec->order = ++enqueue_order_;
166
rec->entry = generator_->NewCodeEntry(tag, prefix, name);
168
events_buffer_.Enqueue(evt_rec);
172
void ProfilerEventsProcessor::AddCurrentStack() {
173
TickSampleEventRecord record(enqueue_order_);
174
TickSample* sample = &record.sample;
175
Isolate* isolate = Isolate::Current();
176
sample->state = isolate->current_vm_state();
177
sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
178
for (StackTraceFrameIterator it(isolate);
179
!it.done() && sample->frames_count < TickSample::kMaxFramesCount;
181
sample->stack[sample->frames_count++] = it.frame()->pc();
183
ticks_from_vm_buffer_.Enqueue(record);
187
bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
188
if (!events_buffer_.IsEmpty()) {
189
CodeEventsContainer record;
190
events_buffer_.Dequeue(&record);
191
switch (record.generic.type) {
192
#define PROFILER_TYPE_CASE(type, clss) \
193
case CodeEventRecord::type: \
194
record.clss##_.UpdateCodeMap(generator_->code_map()); \
197
CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
199
#undef PROFILER_TYPE_CASE
200
default: return true; // Skip record.
202
*dequeue_order = record.generic.order;
209
bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
211
if (!ticks_from_vm_buffer_.IsEmpty()
212
&& ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
213
TickSampleEventRecord record;
214
ticks_from_vm_buffer_.Dequeue(&record);
215
generator_->RecordTickSample(record.sample);
218
const TickSampleEventRecord* rec =
219
TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
220
if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
221
// Make a local copy of tick sample record to ensure that it won't
222
// be modified as we are processing it. This is possible as the
223
// sampler writes w/o any sync to the queue, so if the processor
224
// will get far behind, a record may be modified right under its
226
TickSampleEventRecord record = *rec;
227
if (record.order == dequeue_order) {
228
// A paranoid check to make sure that we don't get a memory overrun
229
// in case of frames_count having a wild value.
230
if (record.sample.frames_count < 0
231
|| record.sample.frames_count > TickSample::kMaxFramesCount)
232
record.sample.frames_count = 0;
233
generator_->RecordTickSample(record.sample);
234
ticks_buffer_.FinishDequeue();
242
void ProfilerEventsProcessor::Run() {
243
unsigned dequeue_order = 0;
246
// Process ticks until we have any.
247
if (ProcessTicks(dequeue_order)) {
248
// All ticks of the current dequeue_order are processed,
249
// proceed to the next code event.
250
ProcessCodeEvent(&dequeue_order);
255
// Process remaining tick events.
256
ticks_buffer_.FlushResidualRecords();
257
// Perform processing until we have tick events, skip remaining code events.
258
while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
262
void CpuProfiler::StartProfiling(const char* title) {
263
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
264
Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
268
void CpuProfiler::StartProfiling(String* title) {
269
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
270
Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
274
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
275
Isolate* isolate = Isolate::Current();
276
return is_profiling(isolate) ?
277
isolate->cpu_profiler()->StopCollectingProfile(title) : NULL;
281
CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
282
Isolate* isolate = Isolate::Current();
283
return is_profiling(isolate) ?
284
isolate->cpu_profiler()->StopCollectingProfile(
285
security_token, title) : NULL;
289
int CpuProfiler::GetProfilesCount() {
290
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
291
// The count of profiles doesn't depend on a security token.
292
return Isolate::Current()->cpu_profiler()->profiles_->Profiles(
293
TokenEnumerator::kNoSecurityToken)->length();
297
CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
298
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
299
CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
300
const int token = profiler->token_enumerator_->GetTokenId(security_token);
301
return profiler->profiles_->Profiles(token)->at(index);
305
CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
306
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
307
CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
308
const int token = profiler->token_enumerator_->GetTokenId(security_token);
309
return profiler->profiles_->GetProfile(token, uid);
313
TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
314
if (CpuProfiler::is_profiling(isolate)) {
315
return isolate->cpu_profiler()->processor_->TickSampleEvent();
322
void CpuProfiler::DeleteAllProfiles() {
323
Isolate* isolate = Isolate::Current();
324
ASSERT(isolate->cpu_profiler() != NULL);
325
if (is_profiling(isolate)) {
326
isolate->cpu_profiler()->StopProcessor();
328
isolate->cpu_profiler()->ResetProfiles();
332
void CpuProfiler::DeleteProfile(CpuProfile* profile) {
333
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
334
Isolate::Current()->cpu_profiler()->profiles_->RemoveProfile(profile);
339
bool CpuProfiler::HasDetachedProfiles() {
340
ASSERT(Isolate::Current()->cpu_profiler() != NULL);
341
return Isolate::Current()->cpu_profiler()->profiles_->HasDetachedProfiles();
345
void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
346
Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
347
Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
351
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
352
Code* code, const char* comment) {
353
Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
354
tag, comment, code->address(), code->ExecutableSize());
358
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
359
Code* code, String* name) {
360
Isolate* isolate = Isolate::Current();
361
isolate->cpu_profiler()->processor_->CodeCreateEvent(
364
isolate->heap()->empty_string(),
365
v8::CpuProfileNode::kNoLineNumberInfo,
367
code->ExecutableSize(),
372
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
374
SharedFunctionInfo* shared,
376
Isolate* isolate = Isolate::Current();
377
isolate->cpu_profiler()->processor_->CodeCreateEvent(
380
isolate->heap()->empty_string(),
381
v8::CpuProfileNode::kNoLineNumberInfo,
383
code->ExecutableSize(),
388
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
390
SharedFunctionInfo* shared,
391
String* source, int line) {
392
Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
398
code->ExecutableSize(),
403
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
404
Code* code, int args_count) {
405
Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
409
code->ExecutableSize());
413
void CpuProfiler::CodeMoveEvent(Address from, Address to) {
414
Isolate::Current()->cpu_profiler()->processor_->CodeMoveEvent(from, to);
418
void CpuProfiler::CodeDeleteEvent(Address from) {
422
void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
423
CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
424
profiler->processor_->SharedFunctionInfoMoveEvent(from, to);
428
void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
429
Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
430
Logger::CALLBACK_TAG, "get ", name, entry_point);
434
void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
435
Isolate::Current()->cpu_profiler()->processor_->RegExpCodeCreateEvent(
440
code->ExecutableSize());
444
void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
445
Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
446
Logger::CALLBACK_TAG, "set ", name, entry_point);
450
CpuProfiler::CpuProfiler()
451
: profiles_(new CpuProfilesCollection()),
452
next_profile_uid_(1),
453
token_enumerator_(new TokenEnumerator()),
456
need_to_stop_sampler_(false),
457
is_profiling_(false) {
461
CpuProfiler::~CpuProfiler() {
462
delete token_enumerator_;
467
void CpuProfiler::ResetProfiles() {
469
profiles_ = new CpuProfilesCollection();
472
void CpuProfiler::StartCollectingProfile(const char* title) {
473
if (profiles_->StartProfiling(title, next_profile_uid_++)) {
474
StartProcessorIfNotStarted();
476
processor_->AddCurrentStack();
480
void CpuProfiler::StartCollectingProfile(String* title) {
481
StartCollectingProfile(profiles_->GetName(title));
485
void CpuProfiler::StartProcessorIfNotStarted() {
486
if (processor_ == NULL) {
487
Isolate* isolate = Isolate::Current();
489
// Disable logging when using the new implementation.
490
saved_logging_nesting_ = isolate->logger()->logging_nesting_;
491
isolate->logger()->logging_nesting_ = 0;
492
generator_ = new ProfileGenerator(profiles_);
493
processor_ = new ProfilerEventsProcessor(generator_);
494
NoBarrier_Store(&is_profiling_, true);
496
// Enumerate stuff we already have in the heap.
497
if (isolate->heap()->HasBeenSetUp()) {
498
if (!FLAG_prof_browser_mode) {
499
bool saved_log_code_flag = FLAG_log_code;
500
FLAG_log_code = true;
501
isolate->logger()->LogCodeObjects();
502
FLAG_log_code = saved_log_code_flag;
504
isolate->logger()->LogCompiledFunctions();
505
isolate->logger()->LogAccessorCallbacks();
507
// Enable stack sampling.
508
Sampler* sampler = reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
509
if (!sampler->IsActive()) {
511
need_to_stop_sampler_ = true;
513
sampler->IncreaseProfilingDepth();
518
CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
519
const double actual_sampling_rate = generator_->actual_sampling_rate();
520
StopProcessorIfLastProfile(title);
522
profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
524
actual_sampling_rate);
525
if (result != NULL) {
532
CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
534
const double actual_sampling_rate = generator_->actual_sampling_rate();
535
const char* profile_title = profiles_->GetName(title);
536
StopProcessorIfLastProfile(profile_title);
537
int token = token_enumerator_->GetTokenId(security_token);
538
return profiles_->StopProfiling(token, profile_title, actual_sampling_rate);
542
void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
543
if (profiles_->IsLastProfile(title)) StopProcessor();
547
void CpuProfiler::StopProcessor() {
548
Logger* logger = Isolate::Current()->logger();
549
Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
550
sampler->DecreaseProfilingDepth();
551
if (need_to_stop_sampler_) {
553
need_to_stop_sampler_ = false;
555
NoBarrier_Store(&is_profiling_, false);
562
logger->logging_nesting_ = saved_logging_nesting_;
566
void CpuProfiler::SetUp() {
567
Isolate* isolate = Isolate::Current();
568
if (isolate->cpu_profiler() == NULL) {
569
isolate->set_cpu_profiler(new CpuProfiler());
574
void CpuProfiler::TearDown() {
575
Isolate* isolate = Isolate::Current();
576
if (isolate->cpu_profiler() != NULL) {
577
delete isolate->cpu_profiler();
579
isolate->set_cpu_profiler(NULL);
582
} } // namespace v8::internal