Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / cpu-profiler.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "v8.h"
6
7 #include "cpu-profiler-inl.h"
8
9 #include "compiler.h"
10 #include "frames-inl.h"
11 #include "hashmap.h"
12 #include "log-inl.h"
13 #include "vm-state-inl.h"
14
15 #include "../include/v8-profiler.h"
16
17 namespace v8 {
18 namespace internal {
19
20 static const int kProfilerStackSize = 64 * KB;
21
22
23 ProfilerEventsProcessor::ProfilerEventsProcessor(
24     ProfileGenerator* generator,
25     Sampler* sampler,
26     TimeDelta period)
27     : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
28       generator_(generator),
29       sampler_(sampler),
30       running_(true),
31       period_(period),
32       last_code_event_id_(0), last_processed_code_event_id_(0) {
33 }
34
35
36 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
37   event.generic.order = ++last_code_event_id_;
38   events_buffer_.Enqueue(event);
39 }
40
41
42 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) {
43   TickSampleEventRecord record(last_code_event_id_);
44   RegisterState regs;
45   StackFrameIterator it(isolate);
46   if (!it.done()) {
47     StackFrame* frame = it.frame();
48     regs.sp = frame->sp();
49     regs.fp = frame->fp();
50     regs.pc = frame->pc();
51   }
52   record.sample.Init(isolate, regs);
53   ticks_from_vm_buffer_.Enqueue(record);
54 }
55
56
57 void ProfilerEventsProcessor::StopSynchronously() {
58   if (!running_) return;
59   running_ = false;
60   Join();
61 }
62
63
64 bool ProfilerEventsProcessor::ProcessCodeEvent() {
65   CodeEventsContainer record;
66   if (events_buffer_.Dequeue(&record)) {
67     switch (record.generic.type) {
68 #define PROFILER_TYPE_CASE(type, clss)                          \
69       case CodeEventRecord::type:                               \
70         record.clss##_.UpdateCodeMap(generator_->code_map());   \
71         break;
72
73       CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
74
75 #undef PROFILER_TYPE_CASE
76       default: return true;  // Skip record.
77     }
78     last_processed_code_event_id_ = record.generic.order;
79     return true;
80   }
81   return false;
82 }
83
84 ProfilerEventsProcessor::SampleProcessingResult
85     ProfilerEventsProcessor::ProcessOneSample() {
86   if (!ticks_from_vm_buffer_.IsEmpty()
87       && ticks_from_vm_buffer_.Peek()->order ==
88          last_processed_code_event_id_) {
89     TickSampleEventRecord record;
90     ticks_from_vm_buffer_.Dequeue(&record);
91     generator_->RecordTickSample(record.sample);
92     return OneSampleProcessed;
93   }
94
95   const TickSampleEventRecord* record = ticks_buffer_.Peek();
96   if (record == NULL) {
97     if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue;
98     return FoundSampleForNextCodeEvent;
99   }
100   if (record->order != last_processed_code_event_id_) {
101     return FoundSampleForNextCodeEvent;
102   }
103   generator_->RecordTickSample(record->sample);
104   ticks_buffer_.Remove();
105   return OneSampleProcessed;
106 }
107
108
109 void ProfilerEventsProcessor::Run() {
110   while (running_) {
111     ElapsedTimer timer;
112     timer.Start();
113     // Keep processing existing events until we need to do next sample.
114     do {
115       if (FoundSampleForNextCodeEvent == ProcessOneSample()) {
116         // All ticks of the current last_processed_code_event_id_ are
117         // processed, proceed to the next code event.
118         ProcessCodeEvent();
119       }
120     } while (!timer.HasExpired(period_));
121
122     // Schedule next sample. sampler_ is NULL in tests.
123     if (sampler_) sampler_->DoSample();
124   }
125
126   // Process remaining tick events.
127   do {
128     SampleProcessingResult result;
129     do {
130       result = ProcessOneSample();
131     } while (result == OneSampleProcessed);
132   } while (ProcessCodeEvent());
133 }
134
135
136 void* ProfilerEventsProcessor::operator new(size_t size) {
137   return AlignedAlloc(size, V8_ALIGNOF(ProfilerEventsProcessor));
138 }
139
140
141 void ProfilerEventsProcessor::operator delete(void* ptr) {
142   AlignedFree(ptr);
143 }
144
145
146 int CpuProfiler::GetProfilesCount() {
147   // The count of profiles doesn't depend on a security token.
148   return profiles_->profiles()->length();
149 }
150
151
152 CpuProfile* CpuProfiler::GetProfile(int index) {
153   return profiles_->profiles()->at(index);
154 }
155
156
157 void CpuProfiler::DeleteAllProfiles() {
158   if (is_profiling_) StopProcessor();
159   ResetProfiles();
160 }
161
162
163 void CpuProfiler::DeleteProfile(CpuProfile* profile) {
164   profiles_->RemoveProfile(profile);
165   delete profile;
166   if (profiles_->profiles()->is_empty() && !is_profiling_) {
167     // If this was the last profile, clean up all accessory data as well.
168     ResetProfiles();
169   }
170 }
171
172
173 static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag) {
174   return FLAG_prof_browser_mode
175       && (tag != Logger::CALLBACK_TAG
176           && tag != Logger::FUNCTION_TAG
177           && tag != Logger::LAZY_COMPILE_TAG
178           && tag != Logger::REG_EXP_TAG
179           && tag != Logger::SCRIPT_TAG);
180 }
181
182
183 void CpuProfiler::CallbackEvent(Name* name, Address entry_point) {
184   if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
185   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
186   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
187   rec->start = entry_point;
188   rec->entry = profiles_->NewCodeEntry(
189       Logger::CALLBACK_TAG,
190       profiles_->GetName(name));
191   rec->size = 1;
192   rec->shared = NULL;
193   processor_->Enqueue(evt_rec);
194 }
195
196
197 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
198                                   Code* code,
199                                   const char* name) {
200   if (FilterOutCodeCreateEvent(tag)) return;
201   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
202   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
203   rec->start = code->address();
204   rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
205   rec->size = code->ExecutableSize();
206   rec->shared = NULL;
207   processor_->Enqueue(evt_rec);
208 }
209
210
211 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
212                                   Code* code,
213                                   Name* name) {
214   if (FilterOutCodeCreateEvent(tag)) return;
215   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
216   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
217   rec->start = code->address();
218   rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
219   rec->size = code->ExecutableSize();
220   rec->shared = NULL;
221   processor_->Enqueue(evt_rec);
222 }
223
224
225 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
226                                   Code* code,
227                                   SharedFunctionInfo* shared,
228                                   CompilationInfo* info,
229                                   Name* name) {
230   if (FilterOutCodeCreateEvent(tag)) return;
231   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
232   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
233   rec->start = code->address();
234   rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
235   if (info) {
236     rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
237   }
238   if (shared->script()->IsScript()) {
239     ASSERT(Script::cast(shared->script()));
240     Script* script = Script::cast(shared->script());
241     rec->entry->set_script_id(script->id()->value());
242     rec->entry->set_bailout_reason(
243         GetBailoutReason(shared->DisableOptimizationReason()));
244   }
245   rec->size = code->ExecutableSize();
246   rec->shared = shared->address();
247   processor_->Enqueue(evt_rec);
248 }
249
250
251 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
252                                   Code* code,
253                                   SharedFunctionInfo* shared,
254                                   CompilationInfo* info,
255                                   Name* source, int line, int column) {
256   if (FilterOutCodeCreateEvent(tag)) return;
257   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
258   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
259   rec->start = code->address();
260   rec->entry = profiles_->NewCodeEntry(
261       tag,
262       profiles_->GetFunctionName(shared->DebugName()),
263       CodeEntry::kEmptyNamePrefix,
264       profiles_->GetName(source),
265       line,
266       column);
267   if (info) {
268     rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
269   }
270   ASSERT(Script::cast(shared->script()));
271   Script* script = Script::cast(shared->script());
272   rec->entry->set_script_id(script->id()->value());
273   rec->size = code->ExecutableSize();
274   rec->shared = shared->address();
275   rec->entry->set_bailout_reason(
276       GetBailoutReason(shared->DisableOptimizationReason()));
277   processor_->Enqueue(evt_rec);
278 }
279
280
281 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
282                                   Code* code,
283                                   int args_count) {
284   if (FilterOutCodeCreateEvent(tag)) return;
285   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
286   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
287   rec->start = code->address();
288   rec->entry = profiles_->NewCodeEntry(
289       tag,
290       profiles_->GetName(args_count),
291       "args_count: ");
292   rec->size = code->ExecutableSize();
293   rec->shared = NULL;
294   processor_->Enqueue(evt_rec);
295 }
296
297
298 void CpuProfiler::CodeMoveEvent(Address from, Address to) {
299   CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
300   CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
301   rec->from = from;
302   rec->to = to;
303   processor_->Enqueue(evt_rec);
304 }
305
306
307 void CpuProfiler::CodeDeleteEvent(Address from) {
308 }
309
310
311 void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
312   CodeEventsContainer evt_rec(CodeEventRecord::SHARED_FUNC_MOVE);
313   SharedFunctionInfoMoveEventRecord* rec =
314       &evt_rec.SharedFunctionInfoMoveEventRecord_;
315   rec->from = from;
316   rec->to = to;
317   processor_->Enqueue(evt_rec);
318 }
319
320
321 void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
322   if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
323   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
324   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
325   rec->start = entry_point;
326   rec->entry = profiles_->NewCodeEntry(
327       Logger::CALLBACK_TAG,
328       profiles_->GetName(name),
329       "get ");
330   rec->size = 1;
331   rec->shared = NULL;
332   processor_->Enqueue(evt_rec);
333 }
334
335
336 void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
337   if (FilterOutCodeCreateEvent(Logger::REG_EXP_TAG)) return;
338   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
339   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
340   rec->start = code->address();
341   rec->entry = profiles_->NewCodeEntry(
342       Logger::REG_EXP_TAG,
343       profiles_->GetName(source),
344       "RegExp: ");
345   rec->size = code->ExecutableSize();
346   processor_->Enqueue(evt_rec);
347 }
348
349
350 void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
351   if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
352   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
353   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
354   rec->start = entry_point;
355   rec->entry = profiles_->NewCodeEntry(
356       Logger::CALLBACK_TAG,
357       profiles_->GetName(name),
358       "set ");
359   rec->size = 1;
360   rec->shared = NULL;
361   processor_->Enqueue(evt_rec);
362 }
363
364
365 CpuProfiler::CpuProfiler(Isolate* isolate)
366     : isolate_(isolate),
367       sampling_interval_(TimeDelta::FromMicroseconds(
368           FLAG_cpu_profiler_sampling_interval)),
369       profiles_(new CpuProfilesCollection(isolate->heap())),
370       generator_(NULL),
371       processor_(NULL),
372       is_profiling_(false) {
373 }
374
375
376 CpuProfiler::CpuProfiler(Isolate* isolate,
377                          CpuProfilesCollection* test_profiles,
378                          ProfileGenerator* test_generator,
379                          ProfilerEventsProcessor* test_processor)
380     : isolate_(isolate),
381       sampling_interval_(TimeDelta::FromMicroseconds(
382           FLAG_cpu_profiler_sampling_interval)),
383       profiles_(test_profiles),
384       generator_(test_generator),
385       processor_(test_processor),
386       is_profiling_(false) {
387 }
388
389
390 CpuProfiler::~CpuProfiler() {
391   ASSERT(!is_profiling_);
392   delete profiles_;
393 }
394
395
396 void CpuProfiler::set_sampling_interval(TimeDelta value) {
397   ASSERT(!is_profiling_);
398   sampling_interval_ = value;
399 }
400
401
402 void CpuProfiler::ResetProfiles() {
403   delete profiles_;
404   profiles_ = new CpuProfilesCollection(isolate()->heap());
405 }
406
407
408 void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
409   if (profiles_->StartProfiling(title, record_samples)) {
410     StartProcessorIfNotStarted();
411   }
412 }
413
414
415 void CpuProfiler::StartProfiling(String* title, bool record_samples) {
416   StartProfiling(profiles_->GetName(title), record_samples);
417 }
418
419
420 void CpuProfiler::StartProcessorIfNotStarted() {
421   if (processor_ == NULL) {
422     Logger* logger = isolate_->logger();
423     // Disable logging when using the new implementation.
424     saved_is_logging_ = logger->is_logging_;
425     logger->is_logging_ = false;
426     generator_ = new ProfileGenerator(profiles_);
427     Sampler* sampler = logger->sampler();
428     processor_ = new ProfilerEventsProcessor(
429         generator_, sampler, sampling_interval_);
430     is_profiling_ = true;
431     // Enumerate stuff we already have in the heap.
432     ASSERT(isolate_->heap()->HasBeenSetUp());
433     if (!FLAG_prof_browser_mode) {
434       logger->LogCodeObjects();
435     }
436     logger->LogCompiledFunctions();
437     logger->LogAccessorCallbacks();
438     LogBuiltins();
439     // Enable stack sampling.
440     sampler->SetHasProcessingThread(true);
441     sampler->IncreaseProfilingDepth();
442     processor_->AddCurrentStack(isolate_);
443     processor_->StartSynchronously();
444   }
445 }
446
447
448 CpuProfile* CpuProfiler::StopProfiling(const char* title) {
449   if (!is_profiling_) return NULL;
450   StopProcessorIfLastProfile(title);
451   CpuProfile* result = profiles_->StopProfiling(title);
452   if (result != NULL) {
453     result->Print();
454   }
455   return result;
456 }
457
458
459 CpuProfile* CpuProfiler::StopProfiling(String* title) {
460   if (!is_profiling_) return NULL;
461   const char* profile_title = profiles_->GetName(title);
462   StopProcessorIfLastProfile(profile_title);
463   return profiles_->StopProfiling(profile_title);
464 }
465
466
467 void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
468   if (profiles_->IsLastProfile(title)) StopProcessor();
469 }
470
471
472 void CpuProfiler::StopProcessor() {
473   Logger* logger = isolate_->logger();
474   Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
475   is_profiling_ = false;
476   processor_->StopSynchronously();
477   delete processor_;
478   delete generator_;
479   processor_ = NULL;
480   generator_ = NULL;
481   sampler->SetHasProcessingThread(false);
482   sampler->DecreaseProfilingDepth();
483   logger->is_logging_ = saved_is_logging_;
484 }
485
486
487 void CpuProfiler::LogBuiltins() {
488   Builtins* builtins = isolate_->builtins();
489   ASSERT(builtins->is_initialized());
490   for (int i = 0; i < Builtins::builtin_count; i++) {
491     CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
492     ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
493     Builtins::Name id = static_cast<Builtins::Name>(i);
494     rec->start = builtins->builtin(id)->address();
495     rec->builtin_id = id;
496     processor_->Enqueue(evt_rec);
497   }
498 }
499
500
501 } }  // namespace v8::internal