Commit 8b3cd48d authored by Andrew Comminos's avatar Andrew Comminos Committed by Commit Bot

[cpu-profiler] Add method for controlling sampler busy-waiting

Adds CpuProfiler::SetUsePreciseSampling, which provides a hint whether
to sacrifice CPU cycles to reduce the level of sampling interval
variance. On Windows, this controls whether or not busy waiting is
performed for sample rates < 100ms. Defaults to enabled (old behaviour).

Bug: v8:3967
Change-Id: Iee84c3ae8132541c78b1f78bf294ec7c718bb19b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1510577
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarAlexei Filippov <alph@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60866}
parent c8206043
...@@ -329,6 +329,15 @@ class V8_EXPORT CpuProfiler { ...@@ -329,6 +329,15 @@ class V8_EXPORT CpuProfiler {
*/ */
void SetSamplingInterval(int us); void SetSamplingInterval(int us);
/**
* Sets whether or not the profiler should prioritize consistency of sample
* periodicity on Windows. Disabling this can greatly reduce CPU usage, but
* may result in greater variance in sample timings from the platform's
* scheduler. Defaults to enabled. This method must be called when there are
* no profiles being recorded.
*/
void SetUsePreciseSampling(bool);
/** /**
* Starts collecting CPU profile. Title may be an empty string. It * Starts collecting CPU profile. Title may be an empty string. It
* is allowed to have several profiles being collected at * is allowed to have several profiles being collected at
......
...@@ -10140,6 +10140,11 @@ void CpuProfiler::SetSamplingInterval(int us) { ...@@ -10140,6 +10140,11 @@ void CpuProfiler::SetSamplingInterval(int us) {
base::TimeDelta::FromMicroseconds(us)); base::TimeDelta::FromMicroseconds(us));
} }
void CpuProfiler::SetUsePreciseSampling(bool use_precise_sampling) {
reinterpret_cast<i::CpuProfiler*>(this)->set_use_precise_sampling(
use_precise_sampling);
}
void CpuProfiler::CollectSample() { void CpuProfiler::CollectSample() {
reinterpret_cast<i::CpuProfiler*>(this)->CollectSample(); reinterpret_cast<i::CpuProfiler*>(this)->CollectSample();
} }
......
...@@ -55,10 +55,12 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate, ...@@ -55,10 +55,12 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate, SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
ProfileGenerator* generator, ProfileGenerator* generator,
base::TimeDelta period) base::TimeDelta period,
bool use_precise_sampling)
: ProfilerEventsProcessor(isolate, generator), : ProfilerEventsProcessor(isolate, generator),
sampler_(new CpuSampler(isolate, this)), sampler_(new CpuSampler(isolate, this)),
period_(period) { period_(period),
use_precise_sampling_(use_precise_sampling) {
sampler_->Start(); sampler_->Start();
} }
...@@ -201,13 +203,16 @@ void SamplingEventsProcessor::Run() { ...@@ -201,13 +203,16 @@ void SamplingEventsProcessor::Run() {
if (nextSampleTime > now) { if (nextSampleTime > now) {
#if V8_OS_WIN #if V8_OS_WIN
if (nextSampleTime - now < base::TimeDelta::FromMilliseconds(100)) { if (use_precise_sampling_ &&
nextSampleTime - now < base::TimeDelta::FromMilliseconds(100)) {
// Do not use Sleep on Windows as it is very imprecise, with up to 16ms // Do not use Sleep on Windows as it is very imprecise, with up to 16ms
// jitter, which is unacceptable for short profile intervals. // jitter, which is unacceptable for short profile intervals.
while (base::TimeTicks::HighResolutionNow() < nextSampleTime) { while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
} }
} else // NOLINT } else // NOLINT
#endif #else
USE(use_precise_sampling_);
#endif // V8_OS_WIN
{ {
// Allow another thread to interrupt the delay between samples in the // Allow another thread to interrupt the delay between samples in the
// event of profiler shutdown. // event of profiler shutdown.
...@@ -333,6 +338,11 @@ void CpuProfiler::set_sampling_interval(base::TimeDelta value) { ...@@ -333,6 +338,11 @@ void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
sampling_interval_ = value; sampling_interval_ = value;
} }
void CpuProfiler::set_use_precise_sampling(bool value) {
DCHECK(!is_profiling_);
use_precise_sampling_ = value;
}
void CpuProfiler::ResetProfiles() { void CpuProfiler::ResetProfiles() {
profiles_.reset(new CpuProfilesCollection(isolate_)); profiles_.reset(new CpuProfilesCollection(isolate_));
profiles_->set_cpu_profiler(this); profiles_->set_cpu_profiler(this);
...@@ -394,8 +404,8 @@ void CpuProfiler::StartProcessorIfNotStarted() { ...@@ -394,8 +404,8 @@ void CpuProfiler::StartProcessorIfNotStarted() {
codemap_needs_initialization = true; codemap_needs_initialization = true;
CreateEntriesForRuntimeCallStats(); CreateEntriesForRuntimeCallStats();
} }
processor_.reset(new SamplingEventsProcessor(isolate_, generator_.get(), processor_.reset(new SamplingEventsProcessor(
sampling_interval_)); isolate_, generator_.get(), sampling_interval_, use_precise_sampling_));
if (profiler_listener_) { if (profiler_listener_) {
profiler_listener_->set_observer(processor_.get()); profiler_listener_->set_observer(processor_.get());
} else { } else {
......
...@@ -179,7 +179,7 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor ...@@ -179,7 +179,7 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
: public ProfilerEventsProcessor { : public ProfilerEventsProcessor {
public: public:
SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator, SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
base::TimeDelta period); base::TimeDelta period, bool use_precise_sampling);
~SamplingEventsProcessor() override; ~SamplingEventsProcessor() override;
// SamplingCircularQueue has stricter alignment requirements than a normal new // SamplingCircularQueue has stricter alignment requirements than a normal new
...@@ -210,6 +210,8 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor ...@@ -210,6 +210,8 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
kTickSampleQueueLength> ticks_buffer_; kTickSampleQueueLength> ticks_buffer_;
std::unique_ptr<sampler::Sampler> sampler_; std::unique_ptr<sampler::Sampler> sampler_;
const base::TimeDelta period_; // Samples & code events processing period. const base::TimeDelta period_; // Samples & code events processing period.
const bool use_precise_sampling_; // Whether or not busy-waiting is used for
// low sampling intervals on Windows.
}; };
class V8_EXPORT_PRIVATE CpuProfiler { class V8_EXPORT_PRIVATE CpuProfiler {
...@@ -227,6 +229,7 @@ class V8_EXPORT_PRIVATE CpuProfiler { ...@@ -227,6 +229,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
typedef v8::CpuProfilingMode ProfilingMode; typedef v8::CpuProfilingMode ProfilingMode;
void set_sampling_interval(base::TimeDelta value); void set_sampling_interval(base::TimeDelta value);
void set_use_precise_sampling(bool);
void CollectSample(); void CollectSample();
void StartProfiling(const char* title, bool record_samples = false, void StartProfiling(const char* title, bool record_samples = false,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers); ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
...@@ -258,6 +261,7 @@ class V8_EXPORT_PRIVATE CpuProfiler { ...@@ -258,6 +261,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
Isolate* const isolate_; Isolate* const isolate_;
base::TimeDelta sampling_interval_; base::TimeDelta sampling_interval_;
bool use_precise_sampling_ = true;
std::unique_ptr<CpuProfilesCollection> profiles_; std::unique_ptr<CpuProfilesCollection> profiles_;
std::unique_ptr<ProfileGenerator> generator_; std::unique_ptr<ProfileGenerator> generator_;
std::unique_ptr<ProfilerEventsProcessor> processor_; std::unique_ptr<ProfilerEventsProcessor> processor_;
......
...@@ -82,7 +82,8 @@ TEST(StartStop) { ...@@ -82,7 +82,8 @@ TEST(StartStop) {
ProfileGenerator generator(&profiles); ProfileGenerator generator(&profiles);
std::unique_ptr<ProfilerEventsProcessor> processor( std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(isolate, &generator, new SamplingEventsProcessor(isolate, &generator,
v8::base::TimeDelta::FromMicroseconds(100))); v8::base::TimeDelta::FromMicroseconds(100),
true));
processor->Start(); processor->Start();
processor->StopSynchronously(); processor->StopSynchronously();
} }
...@@ -164,7 +165,7 @@ TEST(CodeEvents) { ...@@ -164,7 +165,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 SamplingEventsProcessor( ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(100)); isolate, generator, v8::base::TimeDelta::FromMicroseconds(100), true);
processor->Start(); processor->Start();
ProfilerListener profiler_listener(isolate, processor); ProfilerListener profiler_listener(isolate, processor);
isolate->logger()->AddCodeEventListener(&profiler_listener); isolate->logger()->AddCodeEventListener(&profiler_listener);
...@@ -222,9 +223,9 @@ TEST(TickEvents) { ...@@ -222,9 +223,9 @@ 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 SamplingEventsProcessor(
new SamplingEventsProcessor(CcTest::i_isolate(), generator, CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100)); v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
processor->Start(); processor->Start();
...@@ -291,9 +292,9 @@ TEST(Issue1398) { ...@@ -291,9 +292,9 @@ 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 SamplingEventsProcessor(
new SamplingEventsProcessor(CcTest::i_isolate(), generator, CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100)); v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
processor->Start(); processor->Start();
...@@ -1149,9 +1150,9 @@ static void TickLines(bool optimize) { ...@@ -1149,9 +1150,9 @@ 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 SamplingEventsProcessor(
new SamplingEventsProcessor(CcTest::i_isolate(), generator, CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100)); v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
// TODO(delphick): Stop using the CpuProfiler internals here: This forces // TODO(delphick): Stop using the CpuProfiler internals here: This forces
...@@ -2833,6 +2834,29 @@ TEST(FastStopProfiling) { ...@@ -2833,6 +2834,29 @@ TEST(FastStopProfiling) {
CHECK_LT(duration, kWaitThreshold.InMillisecondsF()); CHECK_LT(duration, kWaitThreshold.InMillisecondsF());
} }
TEST(LowPrecisionSamplingStartStopInternal) {
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
ProfileGenerator generator(&profiles);
std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(isolate, &generator,
v8::base::TimeDelta::FromMicroseconds(100),
false));
processor->Start();
processor->StopSynchronously();
}
TEST(LowPrecisionSamplingStartStopPublic) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
cpu_profiler->SetUsePreciseSampling(false);
v8::Local<v8::String> profile_name = v8_str("");
cpu_profiler->StartProfiling(profile_name, true);
cpu_profiler->StopProfiling(profile_name);
cpu_profiler->Dispose();
}
enum class EntryCountMode { kAll, kOnlyInlined }; enum class EntryCountMode { kAll, kOnlyInlined };
// Count the number of unique source positions. // Count the number of unique source positions.
......
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