The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / cpu-profiler.cc @ f230a1cf

History | View | Annotate | Download (16.2 KB)

1
// Copyright 2012 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
#include "compiler.h"
33
#include "frames-inl.h"
34
#include "hashmap.h"
35
#include "log-inl.h"
36
#include "vm-state-inl.h"
37

    
38
#include "../include/v8-profiler.h"
39

    
40
namespace v8 {
41
namespace internal {
42

    
43
static const int kProfilerStackSize = 64 * KB;
44

    
45

    
46
ProfilerEventsProcessor::ProfilerEventsProcessor(
47
    ProfileGenerator* generator,
48
    Sampler* sampler,
49
    TimeDelta period)
50
    : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
51
      generator_(generator),
52
      sampler_(sampler),
53
      running_(true),
54
      period_(period),
55
      last_code_event_id_(0), last_processed_code_event_id_(0) {
56
}
57

    
58

    
59
void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
60
  event.generic.order = ++last_code_event_id_;
61
  events_buffer_.Enqueue(event);
62
}
63

    
64

    
65
void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) {
66
  TickSampleEventRecord record(last_code_event_id_);
67
  RegisterState regs;
68
  StackFrameIterator it(isolate);
69
  if (!it.done()) {
70
    StackFrame* frame = it.frame();
71
    regs.sp = frame->sp();
72
    regs.fp = frame->fp();
73
    regs.pc = frame->pc();
74
  }
75
  record.sample.Init(isolate, regs);
76
  ticks_from_vm_buffer_.Enqueue(record);
77
}
78

    
79

    
80
void ProfilerEventsProcessor::StopSynchronously() {
81
  if (!running_) return;
82
  running_ = false;
83
  Join();
84
}
85

    
86

    
87
bool ProfilerEventsProcessor::ProcessCodeEvent() {
88
  CodeEventsContainer record;
89
  if (events_buffer_.Dequeue(&record)) {
90
    switch (record.generic.type) {
91
#define PROFILER_TYPE_CASE(type, clss)                          \
92
      case CodeEventRecord::type:                               \
93
        record.clss##_.UpdateCodeMap(generator_->code_map());   \
94
        break;
95

    
96
      CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
97

    
98
#undef PROFILER_TYPE_CASE
99
      default: return true;  // Skip record.
100
    }
101
    last_processed_code_event_id_ = record.generic.order;
102
    return true;
103
  }
104
  return false;
105
}
106

    
107
ProfilerEventsProcessor::SampleProcessingResult
108
    ProfilerEventsProcessor::ProcessOneSample() {
109
  if (!ticks_from_vm_buffer_.IsEmpty()
110
      && ticks_from_vm_buffer_.Peek()->order ==
111
         last_processed_code_event_id_) {
112
    TickSampleEventRecord record;
113
    ticks_from_vm_buffer_.Dequeue(&record);
114
    generator_->RecordTickSample(record.sample);
115
    return OneSampleProcessed;
116
  }
117

    
118
  const TickSampleEventRecord* record = ticks_buffer_.Peek();
119
  if (record == NULL) {
120
    if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue;
121
    return FoundSampleForNextCodeEvent;
122
  }
123
  if (record->order != last_processed_code_event_id_) {
124
    return FoundSampleForNextCodeEvent;
125
  }
126
  generator_->RecordTickSample(record->sample);
127
  ticks_buffer_.Remove();
128
  return OneSampleProcessed;
129
}
130

    
131

    
132
void ProfilerEventsProcessor::Run() {
133
  while (running_) {
134
    ElapsedTimer timer;
135
    timer.Start();
136
    // Keep processing existing events until we need to do next sample.
137
    do {
138
      if (FoundSampleForNextCodeEvent == ProcessOneSample()) {
139
        // All ticks of the current last_processed_code_event_id_ are
140
        // processed, proceed to the next code event.
141
        ProcessCodeEvent();
142
      }
143
    } while (!timer.HasExpired(period_));
144

    
145
    // Schedule next sample. sampler_ is NULL in tests.
146
    if (sampler_) sampler_->DoSample();
147
  }
148

    
149
  // Process remaining tick events.
150
  do {
151
    SampleProcessingResult result;
152
    do {
153
      result = ProcessOneSample();
154
    } while (result == OneSampleProcessed);
155
  } while (ProcessCodeEvent());
156
}
157

    
158

    
159
int CpuProfiler::GetProfilesCount() {
160
  // The count of profiles doesn't depend on a security token.
161
  return profiles_->profiles()->length();
162
}
163

    
164

    
165
CpuProfile* CpuProfiler::GetProfile(int index) {
166
  return profiles_->profiles()->at(index);
167
}
168

    
169

    
170
void CpuProfiler::DeleteAllProfiles() {
171
  if (is_profiling_) StopProcessor();
172
  ResetProfiles();
173
}
174

    
175

    
176
void CpuProfiler::DeleteProfile(CpuProfile* profile) {
177
  profiles_->RemoveProfile(profile);
178
  delete profile;
179
}
180

    
181

    
182
static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag) {
183
  return FLAG_prof_browser_mode
184
      && (tag != Logger::CALLBACK_TAG
185
          && tag != Logger::FUNCTION_TAG
186
          && tag != Logger::LAZY_COMPILE_TAG
187
          && tag != Logger::REG_EXP_TAG
188
          && tag != Logger::SCRIPT_TAG);
189
}
190

    
191

    
192
void CpuProfiler::CallbackEvent(Name* name, Address entry_point) {
193
  if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
194
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
195
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
196
  rec->start = entry_point;
197
  rec->entry = profiles_->NewCodeEntry(
198
      Logger::CALLBACK_TAG,
199
      profiles_->GetName(name));
200
  rec->size = 1;
201
  rec->shared = NULL;
202
  processor_->Enqueue(evt_rec);
203
}
204

    
205

    
206
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
207
                                  Code* code,
208
                                  const char* name) {
209
  if (FilterOutCodeCreateEvent(tag)) return;
210
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
211
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
212
  rec->start = code->address();
213
  rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
214
  rec->size = code->ExecutableSize();
215
  rec->shared = NULL;
216
  processor_->Enqueue(evt_rec);
217
}
218

    
219

    
220
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
221
                                  Code* code,
222
                                  Name* name) {
223
  if (FilterOutCodeCreateEvent(tag)) return;
224
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
225
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
226
  rec->start = code->address();
227
  rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
228
  rec->size = code->ExecutableSize();
229
  rec->shared = NULL;
230
  processor_->Enqueue(evt_rec);
231
}
232

    
233

    
234
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
235
                                  Code* code,
236
                                  SharedFunctionInfo* shared,
237
                                  CompilationInfo* info,
238
                                  Name* name) {
239
  if (FilterOutCodeCreateEvent(tag)) return;
240
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
241
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
242
  rec->start = code->address();
243
  rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
244
  if (info) {
245
    rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
246
  }
247
  if (shared->script()->IsScript()) {
248
    ASSERT(Script::cast(shared->script()));
249
    Script* script = Script::cast(shared->script());
250
    rec->entry->set_script_id(script->id()->value());
251
    rec->entry->set_bailout_reason(
252
        GetBailoutReason(shared->DisableOptimizationReason()));
253
  }
254
  rec->size = code->ExecutableSize();
255
  rec->shared = shared->address();
256
  processor_->Enqueue(evt_rec);
257
}
258

    
259

    
260
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
261
                                  Code* code,
262
                                  SharedFunctionInfo* shared,
263
                                  CompilationInfo* info,
264
                                  Name* source, int line, int column) {
265
  if (FilterOutCodeCreateEvent(tag)) return;
266
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
267
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
268
  rec->start = code->address();
269
  rec->entry = profiles_->NewCodeEntry(
270
      tag,
271
      profiles_->GetFunctionName(shared->DebugName()),
272
      CodeEntry::kEmptyNamePrefix,
273
      profiles_->GetName(source),
274
      line,
275
      column);
276
  if (info) {
277
    rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
278
  }
279
  ASSERT(Script::cast(shared->script()));
280
  Script* script = Script::cast(shared->script());
281
  rec->entry->set_script_id(script->id()->value());
282
  rec->size = code->ExecutableSize();
283
  rec->shared = shared->address();
284
  rec->entry->set_bailout_reason(
285
      GetBailoutReason(shared->DisableOptimizationReason()));
286
  processor_->Enqueue(evt_rec);
287
}
288

    
289

    
290
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
291
                                  Code* code,
292
                                  int args_count) {
293
  if (FilterOutCodeCreateEvent(tag)) return;
294
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
295
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
296
  rec->start = code->address();
297
  rec->entry = profiles_->NewCodeEntry(
298
      tag,
299
      profiles_->GetName(args_count),
300
      "args_count: ");
301
  rec->size = code->ExecutableSize();
302
  rec->shared = NULL;
303
  processor_->Enqueue(evt_rec);
304
}
305

    
306

    
307
void CpuProfiler::CodeMoveEvent(Address from, Address to) {
308
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
309
  CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
310
  rec->from = from;
311
  rec->to = to;
312
  processor_->Enqueue(evt_rec);
313
}
314

    
315

    
316
void CpuProfiler::CodeDeleteEvent(Address from) {
317
}
318

    
319

    
320
void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
321
  CodeEventsContainer evt_rec(CodeEventRecord::SHARED_FUNC_MOVE);
322
  SharedFunctionInfoMoveEventRecord* rec =
323
      &evt_rec.SharedFunctionInfoMoveEventRecord_;
324
  rec->from = from;
325
  rec->to = to;
326
  processor_->Enqueue(evt_rec);
327
}
328

    
329

    
330
void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
331
  if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
332
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
333
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
334
  rec->start = entry_point;
335
  rec->entry = profiles_->NewCodeEntry(
336
      Logger::CALLBACK_TAG,
337
      profiles_->GetName(name),
338
      "get ");
339
  rec->size = 1;
340
  rec->shared = NULL;
341
  processor_->Enqueue(evt_rec);
342
}
343

    
344

    
345
void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
346
  if (FilterOutCodeCreateEvent(Logger::REG_EXP_TAG)) return;
347
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
348
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
349
  rec->start = code->address();
350
  rec->entry = profiles_->NewCodeEntry(
351
      Logger::REG_EXP_TAG,
352
      profiles_->GetName(source),
353
      "RegExp: ");
354
  rec->size = code->ExecutableSize();
355
  processor_->Enqueue(evt_rec);
356
}
357

    
358

    
359
void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
360
  if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
361
  CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
362
  CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
363
  rec->start = entry_point;
364
  rec->entry = profiles_->NewCodeEntry(
365
      Logger::CALLBACK_TAG,
366
      profiles_->GetName(name),
367
      "set ");
368
  rec->size = 1;
369
  rec->shared = NULL;
370
  processor_->Enqueue(evt_rec);
371
}
372

    
373

    
374
CpuProfiler::CpuProfiler(Isolate* isolate)
375
    : isolate_(isolate),
376
      sampling_interval_(TimeDelta::FromMicroseconds(
377
          FLAG_cpu_profiler_sampling_interval)),
378
      profiles_(new CpuProfilesCollection(isolate->heap())),
379
      next_profile_uid_(1),
380
      generator_(NULL),
381
      processor_(NULL),
382
      is_profiling_(false) {
383
}
384

    
385

    
386
CpuProfiler::CpuProfiler(Isolate* isolate,
387
                         CpuProfilesCollection* test_profiles,
388
                         ProfileGenerator* test_generator,
389
                         ProfilerEventsProcessor* test_processor)
390
    : isolate_(isolate),
391
      sampling_interval_(TimeDelta::FromMicroseconds(
392
          FLAG_cpu_profiler_sampling_interval)),
393
      profiles_(test_profiles),
394
      next_profile_uid_(1),
395
      generator_(test_generator),
396
      processor_(test_processor),
397
      is_profiling_(false) {
398
}
399

    
400

    
401
CpuProfiler::~CpuProfiler() {
402
  ASSERT(!is_profiling_);
403
  delete profiles_;
404
}
405

    
406

    
407
void CpuProfiler::set_sampling_interval(TimeDelta value) {
408
  ASSERT(!is_profiling_);
409
  sampling_interval_ = value;
410
}
411

    
412

    
413
void CpuProfiler::ResetProfiles() {
414
  delete profiles_;
415
  profiles_ = new CpuProfilesCollection(isolate()->heap());
416
}
417

    
418

    
419
void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
420
  if (profiles_->StartProfiling(title, next_profile_uid_++, record_samples)) {
421
    StartProcessorIfNotStarted();
422
  }
423
  processor_->AddCurrentStack(isolate_);
424
}
425

    
426

    
427
void CpuProfiler::StartProfiling(String* title, bool record_samples) {
428
  StartProfiling(profiles_->GetName(title), record_samples);
429
}
430

    
431

    
432
void CpuProfiler::StartProcessorIfNotStarted() {
433
  if (processor_ == NULL) {
434
    Logger* logger = isolate_->logger();
435
    // Disable logging when using the new implementation.
436
    saved_is_logging_ = logger->is_logging_;
437
    logger->is_logging_ = false;
438
    generator_ = new ProfileGenerator(profiles_);
439
    Sampler* sampler = logger->sampler();
440
#if V8_CC_MSVC && (_MSC_VER >= 1800)
441
    // VS2013 reports "warning C4316: 'v8::internal::ProfilerEventsProcessor'
442
    // : object allocated on the heap may not be aligned 64".  We need to
443
    // figure out if this is a legitimate warning or a compiler bug.
444
    #pragma warning(push)
445
    #pragma warning(disable:4316)
446
#endif
447
    processor_ = new ProfilerEventsProcessor(
448
        generator_, sampler, sampling_interval_);
449
#if V8_CC_MSVC && (_MSC_VER >= 1800)
450
    #pragma warning(pop)
451
#endif
452
    is_profiling_ = true;
453
    // Enumerate stuff we already have in the heap.
454
    ASSERT(isolate_->heap()->HasBeenSetUp());
455
    if (!FLAG_prof_browser_mode) {
456
      logger->LogCodeObjects();
457
    }
458
    logger->LogCompiledFunctions();
459
    logger->LogAccessorCallbacks();
460
    LogBuiltins();
461
    // Enable stack sampling.
462
    sampler->SetHasProcessingThread(true);
463
    sampler->IncreaseProfilingDepth();
464
    processor_->StartSynchronously();
465
  }
466
}
467

    
468

    
469
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
470
  if (!is_profiling_) return NULL;
471
  StopProcessorIfLastProfile(title);
472
  CpuProfile* result = profiles_->StopProfiling(title);
473
  if (result != NULL) {
474
    result->Print();
475
  }
476
  return result;
477
}
478

    
479

    
480
CpuProfile* CpuProfiler::StopProfiling(String* title) {
481
  if (!is_profiling_) return NULL;
482
  const char* profile_title = profiles_->GetName(title);
483
  StopProcessorIfLastProfile(profile_title);
484
  return profiles_->StopProfiling(profile_title);
485
}
486

    
487

    
488
void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
489
  if (profiles_->IsLastProfile(title)) StopProcessor();
490
}
491

    
492

    
493
void CpuProfiler::StopProcessor() {
494
  Logger* logger = isolate_->logger();
495
  Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
496
  is_profiling_ = false;
497
  processor_->StopSynchronously();
498
  delete processor_;
499
  delete generator_;
500
  processor_ = NULL;
501
  generator_ = NULL;
502
  sampler->SetHasProcessingThread(false);
503
  sampler->DecreaseProfilingDepth();
504
  logger->is_logging_ = saved_is_logging_;
505
}
506

    
507

    
508
void CpuProfiler::LogBuiltins() {
509
  Builtins* builtins = isolate_->builtins();
510
  ASSERT(builtins->is_initialized());
511
  for (int i = 0; i < Builtins::builtin_count; i++) {
512
    CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
513
    ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
514
    Builtins::Name id = static_cast<Builtins::Name>(i);
515
    rec->start = builtins->builtin(id)->address();
516
    rec->builtin_id = id;
517
    processor_->Enqueue(evt_rec);
518
  }
519
}
520

    
521

    
522
} }  // namespace v8::internal