blob: c0ed9297a2dd966a5daf9a5b7046e2ac2601c04a [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"
Steve Block6ded16b2010-05-10 14:33:55 +010035#include "log-inl.h"
36
37#include "../include/v8-profiler.h"
38
39namespace v8 {
40namespace internal {
41
42static const int kEventsBufferSize = 256*KB;
43static const int kTickSamplesBufferChunkSize = 64*KB;
44static const int kTickSamplesBufferChunksCount = 16;
45
46
47ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
48 : generator_(generator),
Steve Block791712a2010-08-27 10:21:07 +010049 running_(true),
Steve Block6ded16b2010-05-10 14:33:55 +010050 ticks_buffer_(sizeof(TickSampleEventRecord),
51 kTickSamplesBufferChunkSize,
52 kTickSamplesBufferChunksCount),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010053 enqueue_order_(0) {
54}
Steve Block6ded16b2010-05-10 14:33:55 +010055
56
57void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
58 const char* prefix,
59 String* name,
60 Address start) {
61 if (FilterOutCodeCreateEvent(tag)) return;
62 CodeEventsContainer evt_rec;
63 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
64 rec->type = CodeEventRecord::CODE_CREATION;
65 rec->order = ++enqueue_order_;
66 rec->start = start;
67 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
68 rec->size = 1;
69 events_buffer_.Enqueue(evt_rec);
70}
71
72
73void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
74 String* name,
75 String* resource_name,
76 int line_number,
77 Address start,
78 unsigned size) {
79 if (FilterOutCodeCreateEvent(tag)) return;
80 CodeEventsContainer evt_rec;
81 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
82 rec->type = CodeEventRecord::CODE_CREATION;
83 rec->order = ++enqueue_order_;
84 rec->start = start;
85 rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
86 rec->size = size;
87 events_buffer_.Enqueue(evt_rec);
88}
89
90
91void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
92 const char* name,
93 Address start,
94 unsigned size) {
95 if (FilterOutCodeCreateEvent(tag)) return;
96 CodeEventsContainer evt_rec;
97 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
98 rec->type = CodeEventRecord::CODE_CREATION;
99 rec->order = ++enqueue_order_;
100 rec->start = start;
101 rec->entry = generator_->NewCodeEntry(tag, name);
102 rec->size = size;
103 events_buffer_.Enqueue(evt_rec);
104}
105
106
107void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
108 int args_count,
109 Address start,
110 unsigned size) {
111 if (FilterOutCodeCreateEvent(tag)) return;
112 CodeEventsContainer evt_rec;
113 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
114 rec->type = CodeEventRecord::CODE_CREATION;
115 rec->order = ++enqueue_order_;
116 rec->start = start;
117 rec->entry = generator_->NewCodeEntry(tag, args_count);
118 rec->size = size;
119 events_buffer_.Enqueue(evt_rec);
120}
121
122
123void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
124 CodeEventsContainer evt_rec;
125 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
126 rec->type = CodeEventRecord::CODE_MOVE;
127 rec->order = ++enqueue_order_;
128 rec->from = from;
129 rec->to = to;
130 events_buffer_.Enqueue(evt_rec);
131}
132
133
134void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
135 CodeEventsContainer evt_rec;
136 CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
137 rec->type = CodeEventRecord::CODE_DELETE;
138 rec->order = ++enqueue_order_;
139 rec->start = from;
140 events_buffer_.Enqueue(evt_rec);
141}
142
143
144void ProfilerEventsProcessor::FunctionCreateEvent(Address alias,
Leon Clarkef7060e22010-06-03 12:02:55 +0100145 Address start,
146 int security_token_id) {
Steve Block6ded16b2010-05-10 14:33:55 +0100147 CodeEventsContainer evt_rec;
148 CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_;
149 rec->type = CodeEventRecord::CODE_ALIAS;
150 rec->order = ++enqueue_order_;
Leon Clarkef7060e22010-06-03 12:02:55 +0100151 rec->start = alias;
152 rec->entry = generator_->NewCodeEntry(security_token_id);
153 rec->code_start = start;
Steve Block6ded16b2010-05-10 14:33:55 +0100154 events_buffer_.Enqueue(evt_rec);
155}
156
157
158void ProfilerEventsProcessor::FunctionMoveEvent(Address from, Address to) {
159 CodeMoveEvent(from, to);
160}
161
162
163void ProfilerEventsProcessor::FunctionDeleteEvent(Address from) {
164 CodeDeleteEvent(from);
165}
166
167
168void ProfilerEventsProcessor::RegExpCodeCreateEvent(
169 Logger::LogEventsAndTags tag,
170 const char* prefix,
171 String* name,
172 Address start,
173 unsigned size) {
174 if (FilterOutCodeCreateEvent(tag)) return;
175 CodeEventsContainer evt_rec;
176 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
177 rec->type = CodeEventRecord::CODE_CREATION;
178 rec->order = ++enqueue_order_;
179 rec->start = start;
180 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
181 rec->size = size;
182 events_buffer_.Enqueue(evt_rec);
183}
184
185
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100186void ProfilerEventsProcessor::AddCurrentStack() {
187 TickSampleEventRecord record;
188 TickSample* sample = &record.sample;
189 sample->state = VMState::current_state();
190 sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
191 sample->frames_count = 0;
192 for (StackTraceFrameIterator it;
193 !it.done() && sample->frames_count < TickSample::kMaxFramesCount;
194 it.Advance()) {
195 JavaScriptFrame* frame = it.frame();
196 sample->stack[sample->frames_count++] =
197 reinterpret_cast<Address>(frame->function());
198 }
199 record.order = enqueue_order_;
200 ticks_from_vm_buffer_.Enqueue(record);
201}
202
203
Steve Block6ded16b2010-05-10 14:33:55 +0100204bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
205 if (!events_buffer_.IsEmpty()) {
206 CodeEventsContainer record;
207 events_buffer_.Dequeue(&record);
208 switch (record.generic.type) {
209#define PROFILER_TYPE_CASE(type, clss) \
210 case CodeEventRecord::type: \
211 record.clss##_.UpdateCodeMap(generator_->code_map()); \
212 break;
213
214 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
215
216#undef PROFILER_TYPE_CASE
217 default: return true; // Skip record.
218 }
219 *dequeue_order = record.generic.order;
220 return true;
221 }
222 return false;
223}
224
225
226bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
227 while (true) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100228 if (!ticks_from_vm_buffer_.IsEmpty()
229 && ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
230 TickSampleEventRecord record;
231 ticks_from_vm_buffer_.Dequeue(&record);
232 generator_->RecordTickSample(record.sample);
233 }
234
Steve Block6ded16b2010-05-10 14:33:55 +0100235 const TickSampleEventRecord* rec =
236 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100237 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
Steve Block6ded16b2010-05-10 14:33:55 +0100238 if (rec->order == dequeue_order) {
239 generator_->RecordTickSample(rec->sample);
240 ticks_buffer_.FinishDequeue();
241 } else {
242 return true;
243 }
244 }
245}
246
247
248void ProfilerEventsProcessor::Run() {
249 unsigned dequeue_order = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100250
251 while (running_) {
252 // Process ticks until we have any.
253 if (ProcessTicks(dequeue_order)) {
254 // All ticks of the current dequeue_order are processed,
255 // proceed to the next code event.
256 ProcessCodeEvent(&dequeue_order);
257 }
258 YieldCPU();
259 }
260
261 // Process remaining tick events.
262 ticks_buffer_.FlushResidualRecords();
263 // Perform processing until we have tick events, skip remaining code events.
264 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
265}
266
267
268CpuProfiler* CpuProfiler::singleton_ = NULL;
269
270void CpuProfiler::StartProfiling(const char* title) {
271 ASSERT(singleton_ != NULL);
272 singleton_->StartCollectingProfile(title);
273}
274
275
276void CpuProfiler::StartProfiling(String* title) {
277 ASSERT(singleton_ != NULL);
278 singleton_->StartCollectingProfile(title);
279}
280
281
282CpuProfile* CpuProfiler::StopProfiling(const char* title) {
283 return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL;
284}
285
286
Leon Clarkef7060e22010-06-03 12:02:55 +0100287CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
288 return is_profiling() ?
289 singleton_->StopCollectingProfile(security_token, title) : NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100290}
291
292
293int CpuProfiler::GetProfilesCount() {
294 ASSERT(singleton_ != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100295 // The count of profiles doesn't depend on a security token.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100296 return singleton_->profiles_->Profiles(
297 TokenEnumerator::kNoSecurityToken)->length();
Steve Block6ded16b2010-05-10 14:33:55 +0100298}
299
300
Leon Clarkef7060e22010-06-03 12:02:55 +0100301CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
Steve Block6ded16b2010-05-10 14:33:55 +0100302 ASSERT(singleton_ != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100303 const int token = singleton_->token_enumerator_->GetTokenId(security_token);
304 return singleton_->profiles_->Profiles(token)->at(index);
Steve Block6ded16b2010-05-10 14:33:55 +0100305}
306
307
Leon Clarkef7060e22010-06-03 12:02:55 +0100308CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
Steve Block6ded16b2010-05-10 14:33:55 +0100309 ASSERT(singleton_ != NULL);
Leon Clarkef7060e22010-06-03 12:02:55 +0100310 const int token = singleton_->token_enumerator_->GetTokenId(security_token);
311 return singleton_->profiles_->GetProfile(token, uid);
Steve Block6ded16b2010-05-10 14:33:55 +0100312}
313
314
315TickSample* CpuProfiler::TickSampleEvent() {
316 if (CpuProfiler::is_profiling()) {
317 return singleton_->processor_->TickSampleEvent();
318 } else {
319 return NULL;
320 }
321}
322
323
324void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
325 singleton_->processor_->CallbackCreateEvent(
326 Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
327}
328
329
330void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
331 Code* code, const char* comment) {
332 singleton_->processor_->CodeCreateEvent(
333 tag, comment, code->address(), code->ExecutableSize());
334}
335
336
337void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
338 Code* code, String* name) {
339 singleton_->processor_->CodeCreateEvent(
340 tag,
341 name,
342 Heap::empty_string(),
343 v8::CpuProfileNode::kNoLineNumberInfo,
344 code->address(),
345 code->ExecutableSize());
346}
347
348
349void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
350 Code* code, String* name,
351 String* source, int line) {
352 singleton_->processor_->CodeCreateEvent(
353 tag,
354 name,
355 source,
356 line,
357 code->address(),
358 code->ExecutableSize());
359}
360
361
362void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
363 Code* code, int args_count) {
364 singleton_->processor_->CodeCreateEvent(
365 tag,
366 args_count,
367 code->address(),
368 code->ExecutableSize());
369}
370
371
372void CpuProfiler::CodeMoveEvent(Address from, Address to) {
373 singleton_->processor_->CodeMoveEvent(from, to);
374}
375
376
377void CpuProfiler::CodeDeleteEvent(Address from) {
378 singleton_->processor_->CodeDeleteEvent(from);
379}
380
381
382void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100383 int security_token_id = TokenEnumerator::kNoSecurityToken;
Leon Clarkef7060e22010-06-03 12:02:55 +0100384 if (function->unchecked_context()->IsContext()) {
385 security_token_id = singleton_->token_enumerator_->GetTokenId(
386 function->context()->global_context()->security_token());
387 }
Steve Block6ded16b2010-05-10 14:33:55 +0100388 singleton_->processor_->FunctionCreateEvent(
Leon Clarkef7060e22010-06-03 12:02:55 +0100389 function->address(),
390 function->code()->address(),
391 security_token_id);
Steve Block6ded16b2010-05-10 14:33:55 +0100392}
393
394
395void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
396 singleton_->processor_->FunctionMoveEvent(from, to);
397}
398
399
400void CpuProfiler::FunctionDeleteEvent(Address from) {
401 singleton_->processor_->FunctionDeleteEvent(from);
402}
403
404
405void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
406 singleton_->processor_->CallbackCreateEvent(
407 Logger::CALLBACK_TAG, "get ", name, entry_point);
408}
409
410
411void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
412 singleton_->processor_->RegExpCodeCreateEvent(
413 Logger::REG_EXP_TAG,
414 "RegExp: ",
415 source,
416 code->address(),
417 code->ExecutableSize());
418}
419
420
421void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
422 singleton_->processor_->CallbackCreateEvent(
423 Logger::CALLBACK_TAG, "set ", name, entry_point);
424}
425
426
427CpuProfiler::CpuProfiler()
428 : profiles_(new CpuProfilesCollection()),
429 next_profile_uid_(1),
Leon Clarkef7060e22010-06-03 12:02:55 +0100430 token_enumerator_(new TokenEnumerator()),
Steve Block6ded16b2010-05-10 14:33:55 +0100431 generator_(NULL),
432 processor_(NULL) {
433}
434
435
436CpuProfiler::~CpuProfiler() {
Leon Clarkef7060e22010-06-03 12:02:55 +0100437 delete token_enumerator_;
Steve Block6ded16b2010-05-10 14:33:55 +0100438 delete profiles_;
439}
440
441
442void CpuProfiler::StartCollectingProfile(const char* title) {
443 if (profiles_->StartProfiling(title, next_profile_uid_++)) {
444 StartProcessorIfNotStarted();
445 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100446 processor_->AddCurrentStack();
Steve Block6ded16b2010-05-10 14:33:55 +0100447}
448
449
450void CpuProfiler::StartCollectingProfile(String* title) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100451 StartCollectingProfile(profiles_->GetName(title));
Steve Block6ded16b2010-05-10 14:33:55 +0100452}
453
454
455void CpuProfiler::StartProcessorIfNotStarted() {
456 if (processor_ == NULL) {
457 // Disable logging when using the new implementation.
458 saved_logging_nesting_ = Logger::logging_nesting_;
459 Logger::logging_nesting_ = 0;
460 generator_ = new ProfileGenerator(profiles_);
461 processor_ = new ProfilerEventsProcessor(generator_);
462 processor_->Start();
Steve Block6ded16b2010-05-10 14:33:55 +0100463 // Enumerate stuff we already have in the heap.
464 if (Heap::HasBeenSetup()) {
465 Logger::LogCodeObjects();
466 Logger::LogCompiledFunctions();
467 Logger::LogFunctionObjects();
468 Logger::LogAccessorCallbacks();
469 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100470 // Enable stack sampling.
471 reinterpret_cast<Sampler*>(Logger::ticker_)->Start();
Steve Block6ded16b2010-05-10 14:33:55 +0100472 }
473}
474
475
476CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
477 const double actual_sampling_rate = generator_->actual_sampling_rate();
Iain Merrick75681382010-08-19 15:07:18 +0100478 StopProcessorIfLastProfile(title);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100479 CpuProfile* result =
480 profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
481 title,
482 actual_sampling_rate);
Steve Block6ded16b2010-05-10 14:33:55 +0100483 if (result != NULL) {
484 result->Print();
485 }
486 return result;
487}
488
489
Leon Clarkef7060e22010-06-03 12:02:55 +0100490CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
491 String* title) {
Steve Block6ded16b2010-05-10 14:33:55 +0100492 const double actual_sampling_rate = generator_->actual_sampling_rate();
Iain Merrick75681382010-08-19 15:07:18 +0100493 const char* profile_title = profiles_->GetName(title);
494 StopProcessorIfLastProfile(profile_title);
Leon Clarkef7060e22010-06-03 12:02:55 +0100495 int token = token_enumerator_->GetTokenId(security_token);
Iain Merrick75681382010-08-19 15:07:18 +0100496 return profiles_->StopProfiling(token, profile_title, actual_sampling_rate);
Steve Block6ded16b2010-05-10 14:33:55 +0100497}
498
499
Iain Merrick75681382010-08-19 15:07:18 +0100500void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
501 if (profiles_->IsLastProfile(title)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100502 reinterpret_cast<Sampler*>(Logger::ticker_)->Stop();
503 processor_->Stop();
504 processor_->Join();
505 delete processor_;
506 delete generator_;
507 processor_ = NULL;
508 generator_ = NULL;
509 Logger::logging_nesting_ = saved_logging_nesting_;
510 }
511}
512
513} } // namespace v8::internal
514
515#endif // ENABLE_LOGGING_AND_PROFILING
516
517namespace v8 {
518namespace internal {
519
520void CpuProfiler::Setup() {
521#ifdef ENABLE_LOGGING_AND_PROFILING
522 if (singleton_ == NULL) {
523 singleton_ = new CpuProfiler();
524 }
525#endif
526}
527
528
529void CpuProfiler::TearDown() {
530#ifdef ENABLE_LOGGING_AND_PROFILING
531 if (singleton_ != NULL) {
532 delete singleton_;
533 }
534 singleton_ = NULL;
535#endif
536}
537
538} } // namespace v8::internal