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