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