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