Commit 22783832 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[cpu-profiler] Refactor SamplingEventsProcessor into base and subclass

This is preparation to allow for a non-sampling events processor which
receives ticks from a source not driven by a timer. This will allow us
to have more deterministic testing of the CPU profiler.

It also allows different implementations for a wall time and CPU time
triggered sampler.

Change-Id: I2e9db9580ec70f05094e59c2c1e5efc28c8f7da8
Reviewed-on: https://chromium-review.googlesource.com/c/1280436Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56717}
parent fb29a554
...@@ -53,8 +53,7 @@ void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) { ...@@ -53,8 +53,7 @@ void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) {
entry->SetBuiltinId(builtin_id); entry->SetBuiltinId(builtin_id);
} }
TickSample* SamplingEventsProcessor::StartTickSample() {
TickSample* ProfilerEventsProcessor::StartTickSample() {
void* address = ticks_buffer_.StartEnqueue(); void* address = ticks_buffer_.StartEnqueue();
if (address == nullptr) return nullptr; if (address == nullptr) return nullptr;
TickSampleEventRecord* evt = TickSampleEventRecord* evt =
...@@ -62,8 +61,7 @@ TickSample* ProfilerEventsProcessor::StartTickSample() { ...@@ -62,8 +61,7 @@ TickSample* ProfilerEventsProcessor::StartTickSample() {
return &evt->sample; return &evt->sample;
} }
void SamplingEventsProcessor::FinishTickSample() {
void ProfilerEventsProcessor::FinishTickSample() {
ticks_buffer_.FinishEnqueue(); ticks_buffer_.FinishEnqueue();
} }
......
...@@ -25,7 +25,7 @@ static const int kProfilerStackSize = 64 * KB; ...@@ -25,7 +25,7 @@ static const int kProfilerStackSize = 64 * KB;
class CpuSampler : public sampler::Sampler { class CpuSampler : public sampler::Sampler {
public: public:
CpuSampler(Isolate* isolate, ProfilerEventsProcessor* processor) CpuSampler(Isolate* isolate, SamplingEventsProcessor* processor)
: sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)), : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
processor_(processor) {} processor_(processor) {}
...@@ -42,26 +42,31 @@ class CpuSampler : public sampler::Sampler { ...@@ -42,26 +42,31 @@ class CpuSampler : public sampler::Sampler {
} }
private: private:
ProfilerEventsProcessor* processor_; SamplingEventsProcessor* processor_;
}; };
ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate, ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
ProfileGenerator* generator,
base::TimeDelta period)
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
generator_(generator), generator_(generator),
sampler_(new CpuSampler(isolate, this)),
running_(1), running_(1),
period_(period),
last_code_event_id_(0), last_code_event_id_(0),
last_processed_code_event_id_(0) { last_processed_code_event_id_(0) {}
SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
ProfileGenerator* generator,
base::TimeDelta period)
: ProfilerEventsProcessor(generator),
sampler_(new CpuSampler(isolate, this)),
period_(period) {
sampler_->IncreaseProfilingDepth(); sampler_->IncreaseProfilingDepth();
} }
ProfilerEventsProcessor::~ProfilerEventsProcessor() { SamplingEventsProcessor::~SamplingEventsProcessor() {
sampler_->DecreaseProfilingDepth(); sampler_->DecreaseProfilingDepth();
} }
ProfilerEventsProcessor::~ProfilerEventsProcessor() = default;
void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
event.generic.order = ++last_code_event_id_; event.generic.order = ++last_code_event_id_;
events_buffer_.Enqueue(event); events_buffer_.Enqueue(event);
...@@ -96,6 +101,11 @@ void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate, ...@@ -96,6 +101,11 @@ void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate,
ticks_from_vm_buffer_.Enqueue(record); ticks_from_vm_buffer_.Enqueue(record);
} }
void ProfilerEventsProcessor::AddSample(TickSample sample) {
TickSampleEventRecord record(last_code_event_id_);
record.sample = sample;
ticks_from_vm_buffer_.Enqueue(record);
}
void ProfilerEventsProcessor::StopSynchronously() { void ProfilerEventsProcessor::StopSynchronously() {
if (!base::Relaxed_AtomicExchange(&running_, 0)) return; if (!base::Relaxed_AtomicExchange(&running_, 0)) return;
...@@ -124,7 +134,7 @@ bool ProfilerEventsProcessor::ProcessCodeEvent() { ...@@ -124,7 +134,7 @@ bool ProfilerEventsProcessor::ProcessCodeEvent() {
} }
ProfilerEventsProcessor::SampleProcessingResult ProfilerEventsProcessor::SampleProcessingResult
ProfilerEventsProcessor::ProcessOneSample() { SamplingEventsProcessor::ProcessOneSample() {
TickSampleEventRecord record1; TickSampleEventRecord record1;
if (ticks_from_vm_buffer_.Peek(&record1) && if (ticks_from_vm_buffer_.Peek(&record1) &&
(record1.order == last_processed_code_event_id_)) { (record1.order == last_processed_code_event_id_)) {
...@@ -147,8 +157,7 @@ ProfilerEventsProcessor::SampleProcessingResult ...@@ -147,8 +157,7 @@ ProfilerEventsProcessor::SampleProcessingResult
return OneSampleProcessed; return OneSampleProcessed;
} }
void SamplingEventsProcessor::Run() {
void ProfilerEventsProcessor::Run() {
while (!!base::Relaxed_Load(&running_)) { while (!!base::Relaxed_Load(&running_)) {
base::TimeTicks nextSampleTime = base::TimeTicks nextSampleTime =
base::TimeTicks::HighResolutionNow() + period_; base::TimeTicks::HighResolutionNow() + period_;
...@@ -180,8 +189,8 @@ void ProfilerEventsProcessor::Run() { ...@@ -180,8 +189,8 @@ void ProfilerEventsProcessor::Run() {
} }
} }
// Schedule next sample. sampler_ is nullptr in tests. // Schedule next sample.
if (sampler_) sampler_->DoSample(); sampler_->DoSample();
} }
// Process remaining tick events. // Process remaining tick events.
...@@ -193,16 +202,11 @@ void ProfilerEventsProcessor::Run() { ...@@ -193,16 +202,11 @@ void ProfilerEventsProcessor::Run() {
} while (ProcessCodeEvent()); } while (ProcessCodeEvent());
} }
void* SamplingEventsProcessor::operator new(size_t size) {
void* ProfilerEventsProcessor::operator new(size_t size) { return AlignedAlloc(size, V8_ALIGNOF(SamplingEventsProcessor));
return AlignedAlloc(size, V8_ALIGNOF(ProfilerEventsProcessor));
}
void ProfilerEventsProcessor::operator delete(void* ptr) {
AlignedFree(ptr);
} }
void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
int CpuProfiler::GetProfilesCount() { int CpuProfiler::GetProfilesCount() {
// The count of profiles doesn't depend on a security token. // The count of profiles doesn't depend on a security token.
...@@ -375,7 +379,7 @@ void CpuProfiler::StartProcessorIfNotStarted() { ...@@ -375,7 +379,7 @@ void CpuProfiler::StartProcessorIfNotStarted() {
codemap_needs_initialization = true; codemap_needs_initialization = true;
CreateEntriesForRuntimeCallStats(); CreateEntriesForRuntimeCallStats();
} }
processor_.reset(new ProfilerEventsProcessor(isolate_, generator_.get(), processor_.reset(new SamplingEventsProcessor(isolate_, generator_.get(),
sampling_interval_)); sampling_interval_));
if (!profiler_listener_) { if (!profiler_listener_) {
profiler_listener_.reset(new ProfilerListener(isolate_, this)); profiler_listener_.reset(new ProfilerListener(isolate_, this));
......
...@@ -133,35 +133,23 @@ class CodeEventsContainer { ...@@ -133,35 +133,23 @@ class CodeEventsContainer {
// methods called by event producers: VM and stack sampler threads. // methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public base::Thread { class ProfilerEventsProcessor : public base::Thread {
public: public:
ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator, virtual ~ProfilerEventsProcessor();
base::TimeDelta period);
~ProfilerEventsProcessor() override;
// Thread control. // Thread control.
void Run() override; virtual void Run() = 0;
void StopSynchronously(); void StopSynchronously();
V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); } V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); }
void Enqueue(const CodeEventsContainer& event); void Enqueue(const CodeEventsContainer& event);
// Puts current stack into tick sample events buffer. // Puts current stack into the tick sample events buffer.
void AddCurrentStack(Isolate* isolate, bool update_stats = false); void AddCurrentStack(Isolate* isolate, bool update_stats = false);
void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta); void AddDeoptStack(Isolate* isolate, Address from, int fp_to_sp_delta);
// Puts the given sample into the tick sample events buffer.
void AddSample(TickSample sample);
// Tick sample events are filled directly in the buffer of the circular protected:
// queue (because the structure is of fixed width, but usually not all explicit ProfilerEventsProcessor(ProfileGenerator* generator);
// stack frame entries are filled.) This method returns a pointer to the
// next record of the buffer.
inline TickSample* StartTickSample();
inline void FinishTickSample();
// SamplingCircularQueue has stricter alignment requirements than a normal new
// can fulfil, so we need to provide our own new/delete here.
void* operator new(size_t size);
void operator delete(void* ptr);
sampler::Sampler* sampler() { return sampler_.get(); }
private:
// Called from events processing thread (Run() method.) // Called from events processing thread (Run() method.)
bool ProcessCodeEvent(); bool ProcessCodeEvent();
...@@ -170,21 +158,48 @@ class ProfilerEventsProcessor : public base::Thread { ...@@ -170,21 +158,48 @@ class ProfilerEventsProcessor : public base::Thread {
FoundSampleForNextCodeEvent, FoundSampleForNextCodeEvent,
NoSamplesInQueue NoSamplesInQueue
}; };
SampleProcessingResult ProcessOneSample(); virtual SampleProcessingResult ProcessOneSample() = 0;
ProfileGenerator* generator_; ProfileGenerator* generator_;
std::unique_ptr<sampler::Sampler> sampler_;
base::Atomic32 running_; base::Atomic32 running_;
const base::TimeDelta period_; // Samples & code events processing period.
LockedQueue<CodeEventsContainer> events_buffer_; LockedQueue<CodeEventsContainer> events_buffer_;
LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
std::atomic<unsigned> last_code_event_id_;
unsigned last_processed_code_event_id_;
};
class SamplingEventsProcessor : public ProfilerEventsProcessor {
public:
SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
base::TimeDelta period);
~SamplingEventsProcessor() override;
// SamplingCircularQueue has stricter alignment requirements than a normal new
// can fulfil, so we need to provide our own new/delete here.
void* operator new(size_t size);
void operator delete(void* ptr);
void Run() override;
// Tick sample events are filled directly in the buffer of the circular
// queue (because the structure is of fixed width, but usually not all
// stack frame entries are filled.) This method returns a pointer to the
// next record of the buffer.
inline TickSample* StartTickSample();
inline void FinishTickSample();
sampler::Sampler* sampler() { return sampler_.get(); }
private:
SampleProcessingResult ProcessOneSample() override;
static const size_t kTickSampleBufferSize = 1 * MB; static const size_t kTickSampleBufferSize = 1 * MB;
static const size_t kTickSampleQueueLength = static const size_t kTickSampleQueueLength =
kTickSampleBufferSize / sizeof(TickSampleEventRecord); kTickSampleBufferSize / sizeof(TickSampleEventRecord);
SamplingCircularQueue<TickSampleEventRecord, SamplingCircularQueue<TickSampleEventRecord,
kTickSampleQueueLength> ticks_buffer_; kTickSampleQueueLength> ticks_buffer_;
LockedQueue<TickSampleEventRecord> ticks_from_vm_buffer_; std::unique_ptr<sampler::Sampler> sampler_;
std::atomic<unsigned> last_code_event_id_; const base::TimeDelta period_; // Samples & code events processing period.
unsigned last_processed_code_event_id_;
}; };
class CpuProfiler : public CodeEventObserver { class CpuProfiler : public CodeEventObserver {
......
...@@ -78,7 +78,7 @@ TEST(StartStop) { ...@@ -78,7 +78,7 @@ TEST(StartStop) {
CpuProfilesCollection profiles(isolate); CpuProfilesCollection profiles(isolate);
ProfileGenerator generator(&profiles); ProfileGenerator generator(&profiles);
std::unique_ptr<ProfilerEventsProcessor> processor( std::unique_ptr<ProfilerEventsProcessor> processor(
new ProfilerEventsProcessor(isolate, &generator, new SamplingEventsProcessor(isolate, &generator,
v8::base::TimeDelta::FromMicroseconds(100))); v8::base::TimeDelta::FromMicroseconds(100)));
processor->Start(); processor->Start();
processor->StopSynchronously(); processor->StopSynchronously();
...@@ -88,19 +88,20 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc, ...@@ -88,19 +88,20 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
i::Address frame1, i::Address frame1,
i::Address frame2 = kNullAddress, i::Address frame2 = kNullAddress,
i::Address frame3 = kNullAddress) { i::Address frame3 = kNullAddress) {
v8::TickSample* sample = proc->StartTickSample(); v8::internal::TickSample sample;
sample->pc = reinterpret_cast<void*>(frame1); sample.pc = reinterpret_cast<void*>(frame1);
sample->tos = reinterpret_cast<void*>(frame1); sample.tos = reinterpret_cast<void*>(frame1);
sample->frames_count = 0; sample.frames_count = 0;
if (frame2 != kNullAddress) { if (frame2 != kNullAddress) {
sample->stack[0] = reinterpret_cast<void*>(frame2); sample.stack[0] = reinterpret_cast<void*>(frame2);
sample->frames_count = 1; sample.frames_count = 1;
} }
if (frame3 != kNullAddress) { if (frame3 != kNullAddress) {
sample->stack[1] = reinterpret_cast<void*>(frame3); sample.stack[1] = reinterpret_cast<void*>(frame3);
sample->frames_count = 2; sample.frames_count = 2;
} }
proc->FinishTickSample(); sample.timestamp = base::TimeTicks::HighResolutionNow();
proc->AddSample(sample);
} }
namespace { namespace {
...@@ -159,7 +160,7 @@ TEST(CodeEvents) { ...@@ -159,7 +160,7 @@ TEST(CodeEvents) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles); ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = new ProfilerEventsProcessor( ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(100)); isolate, generator, v8::base::TimeDelta::FromMicroseconds(100));
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
...@@ -221,7 +222,7 @@ TEST(TickEvents) { ...@@ -221,7 +222,7 @@ TEST(TickEvents) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles); ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = ProfilerEventsProcessor* processor =
new ProfilerEventsProcessor(CcTest::i_isolate(), generator, new SamplingEventsProcessor(CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100)); v8::base::TimeDelta::FromMicroseconds(100));
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
...@@ -290,7 +291,7 @@ TEST(Issue1398) { ...@@ -290,7 +291,7 @@ TEST(Issue1398) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles); ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = ProfilerEventsProcessor* processor =
new ProfilerEventsProcessor(CcTest::i_isolate(), generator, new SamplingEventsProcessor(CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100)); v8::base::TimeDelta::FromMicroseconds(100));
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
...@@ -299,14 +300,15 @@ TEST(Issue1398) { ...@@ -299,14 +300,15 @@ TEST(Issue1398) {
profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb"); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
v8::TickSample* sample = processor->StartTickSample(); v8::internal::TickSample sample;
sample->pc = reinterpret_cast<void*>(code->InstructionStart()); sample.pc = reinterpret_cast<void*>(code->InstructionStart());
sample->tos = nullptr; sample.tos = nullptr;
sample->frames_count = v8::TickSample::kMaxFramesCount; sample.frames_count = v8::TickSample::kMaxFramesCount;
for (unsigned i = 0; i < sample->frames_count; ++i) { for (unsigned i = 0; i < sample.frames_count; ++i) {
sample->stack[i] = reinterpret_cast<void*>(code->InstructionStart()); sample.stack[i] = reinterpret_cast<void*>(code->InstructionStart());
} }
processor->FinishTickSample(); sample.timestamp = base::TimeTicks::HighResolutionNow();
processor->AddSample(sample);
processor->StopSynchronously(); processor->StopSynchronously();
CpuProfile* profile = profiles->StopProfiling(""); CpuProfile* profile = profiles->StopProfiling("");
...@@ -458,7 +460,9 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function, ...@@ -458,7 +460,9 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
v8::internal::CpuProfiler* iprofiler = v8::internal::CpuProfiler* iprofiler =
reinterpret_cast<v8::internal::CpuProfiler*>(profiler_); reinterpret_cast<v8::internal::CpuProfiler*>(profiler_);
v8::sampler::Sampler* sampler = iprofiler->processor()->sampler(); v8::sampler::Sampler* sampler =
reinterpret_cast<i::SamplingEventsProcessor*>(iprofiler->processor())
->sampler();
sampler->StartCountingSamples(); sampler->StartCountingSamples();
do { do {
function->Call(context_, context_->Global(), argc, argv).ToLocalChecked(); function->Call(context_, context_->Global(), argc, argv).ToLocalChecked();
...@@ -1143,7 +1147,7 @@ static void TickLines(bool optimize) { ...@@ -1143,7 +1147,7 @@ static void TickLines(bool optimize) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles); ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = ProfilerEventsProcessor* processor =
new ProfilerEventsProcessor(CcTest::i_isolate(), generator, new SamplingEventsProcessor(CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100)); v8::base::TimeDelta::FromMicroseconds(100));
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment