V8 Project
cpu-profiler.cc
Go to the documentation of this file.
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 
24  ProfileGenerator* generator,
25  Sampler* sampler,
26  base::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 
37  event.generic.order = ++last_code_event_id_;
38  events_buffer_.Enqueue(event);
39 }
40 
41 
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 
58  if (!running_) return;
59  running_ = false;
60  Join();
61 }
62 
63 
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 
74 
75 #undef PROFILER_TYPE_CASE
76  default: return true; // Skip record.
77  }
79  return true;
80  }
81  return false;
82 }
83 
86  if (!ticks_from_vm_buffer_.IsEmpty()
87  && ticks_from_vm_buffer_.Peek()->order ==
89  TickSampleEventRecord record;
90  ticks_from_vm_buffer_.Dequeue(&record);
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;
99  }
100  if (record->order != last_processed_code_event_id_) {
102  }
104  ticks_buffer_.Remove();
105  return OneSampleProcessed;
106 }
107 
108 
110  while (running_) {
111  base::ElapsedTimer timer;
112  timer.Start();
113  // Keep processing existing events until we need to do next sample.
114  do {
116  // All ticks of the current last_processed_code_event_id_ are
117  // processed, proceed to the next code event.
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) {
138 }
139 
140 
141 void ProfilerEventsProcessor::operator delete(void* ptr) {
142  AlignedFree(ptr);
143 }
144 
145 
147  // The count of profiles doesn't depend on a security token.
148  return profiles_->profiles()->length();
149 }
150 
151 
153  return profiles_->profiles()->at(index);
154 }
155 
156 
159  ResetProfiles();
160 }
161 
162 
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 
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 
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,
191  rec->size = 1;
192  rec->shared = NULL;
193  processor_->Enqueue(evt_rec);
194 }
195 
196 
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();
205  rec->size = code->ExecutableSize();
206  rec->shared = NULL;
207  processor_->Enqueue(evt_rec);
208 }
209 
210 
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();
219  rec->size = code->ExecutableSize();
220  rec->shared = NULL;
221  processor_->Enqueue(evt_rec);
222 }
223 
224 
226  SharedFunctionInfo* shared,
227  CompilationInfo* info, Name* script_name) {
228  if (FilterOutCodeCreateEvent(tag)) return;
229  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
230  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
231  rec->start = code->address();
232  rec->entry = profiles_->NewCodeEntry(
233  tag, profiles_->GetFunctionName(shared->DebugName()),
235  if (info) {
237  }
238  if (shared->script()->IsScript()) {
239  DCHECK(Script::cast(shared->script()));
240  Script* script = Script::cast(shared->script());
241  rec->entry->set_script_id(script->id()->value());
244  }
245  rec->size = code->ExecutableSize();
246  rec->shared = shared->address();
247  processor_->Enqueue(evt_rec);
248 }
249 
250 
252  SharedFunctionInfo* shared,
253  CompilationInfo* info, Name* script_name,
254  int line, int column) {
255  if (FilterOutCodeCreateEvent(tag)) return;
256  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
257  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
258  rec->start = code->address();
259  rec->entry = profiles_->NewCodeEntry(
260  tag, profiles_->GetFunctionName(shared->DebugName()),
261  CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name), line,
262  column);
263  if (info) {
265  }
266  DCHECK(Script::cast(shared->script()));
267  Script* script = Script::cast(shared->script());
268  rec->entry->set_script_id(script->id()->value());
269  rec->size = code->ExecutableSize();
270  rec->shared = shared->address();
273  processor_->Enqueue(evt_rec);
274 }
275 
276 
278  Code* code,
279  int args_count) {
280  if (FilterOutCodeCreateEvent(tag)) return;
281  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
282  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
283  rec->start = code->address();
284  rec->entry = profiles_->NewCodeEntry(
285  tag,
286  profiles_->GetName(args_count),
287  "args_count: ");
288  rec->size = code->ExecutableSize();
289  rec->shared = NULL;
290  processor_->Enqueue(evt_rec);
291 }
292 
293 
295  CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
296  CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
297  rec->from = from;
298  rec->to = to;
299  processor_->Enqueue(evt_rec);
300 }
301 
302 
304  CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
305  CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
306  rec->start = code->address();
308  processor_->Enqueue(evt_rec);
309 }
310 
311 
313 }
314 
315 
317  CodeEventsContainer evt_rec(CodeEventRecord::SHARED_FUNC_MOVE);
319  &evt_rec.SharedFunctionInfoMoveEventRecord_;
320  rec->from = from;
321  rec->to = to;
322  processor_->Enqueue(evt_rec);
323 }
324 
325 
327  if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
328  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
329  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
330  rec->start = entry_point;
331  rec->entry = profiles_->NewCodeEntry(
332  Logger::CALLBACK_TAG,
334  "get ");
335  rec->size = 1;
336  rec->shared = NULL;
337  processor_->Enqueue(evt_rec);
338 }
339 
340 
342  if (FilterOutCodeCreateEvent(Logger::REG_EXP_TAG)) return;
343  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
344  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
345  rec->start = code->address();
346  rec->entry = profiles_->NewCodeEntry(
347  Logger::REG_EXP_TAG,
348  profiles_->GetName(source),
349  "RegExp: ");
350  rec->size = code->ExecutableSize();
351  processor_->Enqueue(evt_rec);
352 }
353 
354 
356  if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
357  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
358  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
359  rec->start = entry_point;
360  rec->entry = profiles_->NewCodeEntry(
361  Logger::CALLBACK_TAG,
363  "set ");
364  rec->size = 1;
365  rec->shared = NULL;
366  processor_->Enqueue(evt_rec);
367 }
368 
369 
371  : isolate_(isolate),
372  sampling_interval_(base::TimeDelta::FromMicroseconds(
373  FLAG_cpu_profiler_sampling_interval)),
374  profiles_(new CpuProfilesCollection(isolate->heap())),
375  generator_(NULL),
376  processor_(NULL),
377  is_profiling_(false) {
378 }
379 
380 
382  CpuProfilesCollection* test_profiles,
383  ProfileGenerator* test_generator,
384  ProfilerEventsProcessor* test_processor)
385  : isolate_(isolate),
386  sampling_interval_(base::TimeDelta::FromMicroseconds(
387  FLAG_cpu_profiler_sampling_interval)),
388  profiles_(test_profiles),
389  generator_(test_generator),
390  processor_(test_processor),
391  is_profiling_(false) {
392 }
393 
394 
397  delete profiles_;
398 }
399 
400 
401 void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
403  sampling_interval_ = value;
404 }
405 
406 
408  delete profiles_;
409  profiles_ = new CpuProfilesCollection(isolate()->heap());
410 }
411 
412 
413 void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
414  if (profiles_->StartProfiling(title, record_samples)) {
416  }
417 }
418 
419 
420 void CpuProfiler::StartProfiling(String* title, bool record_samples) {
421  StartProfiling(profiles_->GetName(title), record_samples);
422 }
423 
424 
426  if (processor_ != NULL) {
428  return;
429  }
430  Logger* logger = isolate_->logger();
431  // Disable logging when using the new implementation.
432  saved_is_logging_ = logger->is_logging_;
433  logger->is_logging_ = false;
435  Sampler* sampler = logger->sampler();
437  generator_, sampler, sampling_interval_);
438  is_profiling_ = true;
439  // Enumerate stuff we already have in the heap.
441  if (!FLAG_prof_browser_mode) {
442  logger->LogCodeObjects();
443  }
444  logger->LogCompiledFunctions();
445  logger->LogAccessorCallbacks();
446  LogBuiltins();
447  // Enable stack sampling.
448  sampler->SetHasProcessingThread(true);
449  sampler->IncreaseProfilingDepth();
452 }
453 
454 
456  if (!is_profiling_) return NULL;
458  CpuProfile* result = profiles_->StopProfiling(title);
459  if (result != NULL) {
460  result->Print();
461  }
462  return result;
463 }
464 
465 
467  if (!is_profiling_) return NULL;
468  const char* profile_title = profiles_->GetName(title);
469  StopProcessorIfLastProfile(profile_title);
470  return profiles_->StopProfiling(profile_title);
471 }
472 
473 
475  if (profiles_->IsLastProfile(title)) StopProcessor();
476 }
477 
478 
480  Logger* logger = isolate_->logger();
481  Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
482  is_profiling_ = false;
484  delete processor_;
485  delete generator_;
486  processor_ = NULL;
487  generator_ = NULL;
488  sampler->SetHasProcessingThread(false);
489  sampler->DecreaseProfilingDepth();
490  logger->is_logging_ = saved_is_logging_;
491 }
492 
493 
495  Builtins* builtins = isolate_->builtins();
496  DCHECK(builtins->is_initialized());
497  for (int i = 0; i < Builtins::builtin_count; i++) {
498  CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
499  ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
500  Builtins::Name id = static_cast<Builtins::Name>(i);
501  rec->start = builtins->builtin(id)->address();
502  rec->builtin_id = id;
503  processor_->Enqueue(evt_rec);
504  }
505 }
506 
507 
508 } } // namespace v8::internal
A single JavaScript stack frame.
Definition: v8.h:1358
void StartSynchronously()
Definition: platform.h:440
bool is_initialized() const
Definition: builtins.h:278
Code * builtin(Name name)
Definition: builtins.h:254
void set_script_id(int script_id)
void set_bailout_reason(const char *bailout_reason)
static const char *const kEmptyNamePrefix
void set_no_frame_ranges(List< OffsetRange > *ranges)
int ExecutableSize()
Definition: objects.h:5263
List< OffsetRange > * ReleaseNoFrameRanges()
Definition: compiler.h:358
void StartProfiling(const char *title, bool record_samples=false)
CpuProfile * StopProfiling(const char *title)
CpuProfile * GetProfile(int index)
void StopProcessorIfLastProfile(const char *title)
CpuProfiler(Isolate *isolate)
virtual void CallbackEvent(Name *name, Address entry_point)
virtual void GetterCallbackEvent(Name *name, Address entry_point)
ProfilerEventsProcessor * processor_
Definition: cpu-profiler.h:262
void set_sampling_interval(base::TimeDelta value)
Isolate * isolate() const
Definition: cpu-profiler.h:249
virtual void CodeDisableOptEvent(Code *code, SharedFunctionInfo *shared)
CpuProfilesCollection * profiles_
Definition: cpu-profiler.h:260
virtual void CodeMoveEvent(Address from, Address to)
virtual void CodeDeleteEvent(Address from)
base::TimeDelta sampling_interval_
Definition: cpu-profiler.h:259
virtual void CodeCreateEvent(Logger::LogEventsAndTags tag, Code *code, const char *comment)
virtual void RegExpCodeCreateEvent(Code *code, String *source)
ProfileGenerator * generator_
Definition: cpu-profiler.h:261
virtual void SharedFunctionInfoMoveEvent(Address from, Address to)
void DeleteProfile(CpuProfile *profile)
virtual void SetterCallbackEvent(Name *name, Address entry_point)
CodeEntry * NewCodeEntry(Logger::LogEventsAndTags tag, const char *name, const char *name_prefix=CodeEntry::kEmptyNamePrefix, const char *resource_name=CodeEntry::kEmptyResourceName, int line_number=v8::CpuProfileNode::kNoLineNumberInfo, int column_number=v8::CpuProfileNode::kNoColumnNumberInfo)
bool StartProfiling(const char *title, bool record_samples)
const char * GetFunctionName(Name *name)
void RemoveProfile(CpuProfile *profile)
CpuProfile * StopProfiling(const char *title)
bool HasBeenSetUp()
Definition: heap.cc:221
Builtins * builtins()
Definition: isolate.h:947
Logger * logger()
Definition: isolate.h:866
Ticker * ticker_
Definition: log.h:386
void LogAccessorCallbacks()
Definition: log.cc:1765
bool is_logging_
Definition: log.h:405
void LogCompiledFunctions()
Definition: log.cc:1745
Sampler * sampler()
Definition: log.cc:1897
void LogCodeObjects()
Definition: log.cc:1685
void RecordTickSample(const TickSample &sample)
ProfilerEventsProcessor(ProfileGenerator *generator, Sampler *sampler, base::TimeDelta period)
Definition: cpu-profiler.cc:23
UnboundQueue< CodeEventsContainer > events_buffer_
Definition: cpu-profiler.h:169
SampleProcessingResult ProcessOneSample()
Definition: cpu-profiler.cc:85
void Enqueue(const CodeEventsContainer &event)
Definition: cpu-profiler.cc:36
UnboundQueue< TickSampleEventRecord > ticks_from_vm_buffer_
Definition: cpu-profiler.h:175
void AddCurrentStack(Isolate *isolate)
Definition: cpu-profiler.cc:42
SamplingCircularQueue< TickSampleEventRecord, kTickSampleQueueLength > ticks_buffer_
Definition: cpu-profiler.h:174
void SetHasProcessingThread(bool value)
Definition: sampler.h:90
void DecreaseProfilingDepth()
Definition: sampler.cc:677
void IncreaseProfilingDepth()
Definition: sampler.cc:669
BailoutReason DisableOptimizationReason()
Definition: objects-inl.h:5750
StackFrame * frame() const
Definition: frames.h:842
#define PROFILER_TYPE_CASE(type, clss)
#define CODE_EVENTS_TYPE_LIST(V)
Definition: cpu-profiler.h:26
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in only print modified registers Trace simulator debug messages Implied by trace sim abort randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot A filename with extra code to be included in the A file to write the raw snapshot bytes to(mksnapshot only)") DEFINE_STRING(raw_context_file
enable harmony numeric enable harmony object literal extensions Optimize object size
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions true
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
const int KB
Definition: globals.h:106
void * AlignedAlloc(size_t size, size_t alignment)
Definition: allocation.cc:86
const char * GetBailoutReason(BailoutReason reason)
byte * Address
Definition: globals.h:101
static const int kProfilerStackSize
Definition: cpu-profiler.cc:20
static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag)
void AlignedFree(void *ptr)
Definition: allocation.cc:104
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
void Init(Isolate *isolate, const RegisterState &state)
Definition: sampler.cc:579
#define V8_ALIGNOF(type)
Definition: v8config.h:416