[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: Alexei Filippov <alph@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60866}
This commit is contained in:
Andrew Comminos 2019-03-14 00:25:55 -07:00 committed by Commit Bot
parent c8206043e1
commit 8b3cd48db8
5 changed files with 70 additions and 18 deletions

View File

@ -329,6 +329,15 @@ class V8_EXPORT CpuProfiler {
*/
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
* is allowed to have several profiles being collected at

View File

@ -10140,6 +10140,11 @@ void CpuProfiler::SetSamplingInterval(int 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() {
reinterpret_cast<i::CpuProfiler*>(this)->CollectSample();
}

View File

@ -55,10 +55,12 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
ProfileGenerator* generator,
base::TimeDelta period)
base::TimeDelta period,
bool use_precise_sampling)
: ProfilerEventsProcessor(isolate, generator),
sampler_(new CpuSampler(isolate, this)),
period_(period) {
period_(period),
use_precise_sampling_(use_precise_sampling) {
sampler_->Start();
}
@ -201,13 +203,16 @@ void SamplingEventsProcessor::Run() {
if (nextSampleTime > now) {
#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
// jitter, which is unacceptable for short profile intervals.
while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
}
} else // NOLINT
#endif
#else
USE(use_precise_sampling_);
#endif // V8_OS_WIN
{
// Allow another thread to interrupt the delay between samples in the
// event of profiler shutdown.
@ -333,6 +338,11 @@ void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
sampling_interval_ = value;
}
void CpuProfiler::set_use_precise_sampling(bool value) {
DCHECK(!is_profiling_);
use_precise_sampling_ = value;
}
void CpuProfiler::ResetProfiles() {
profiles_.reset(new CpuProfilesCollection(isolate_));
profiles_->set_cpu_profiler(this);
@ -394,8 +404,8 @@ void CpuProfiler::StartProcessorIfNotStarted() {
codemap_needs_initialization = true;
CreateEntriesForRuntimeCallStats();
}
processor_.reset(new SamplingEventsProcessor(isolate_, generator_.get(),
sampling_interval_));
processor_.reset(new SamplingEventsProcessor(
isolate_, generator_.get(), sampling_interval_, use_precise_sampling_));
if (profiler_listener_) {
profiler_listener_->set_observer(processor_.get());
} else {

View File

@ -179,7 +179,7 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
: public ProfilerEventsProcessor {
public:
SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
base::TimeDelta period);
base::TimeDelta period, bool use_precise_sampling);
~SamplingEventsProcessor() override;
// SamplingCircularQueue has stricter alignment requirements than a normal new
@ -210,6 +210,8 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
kTickSampleQueueLength> ticks_buffer_;
std::unique_ptr<sampler::Sampler> sampler_;
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 {
@ -227,6 +229,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
typedef v8::CpuProfilingMode ProfilingMode;
void set_sampling_interval(base::TimeDelta value);
void set_use_precise_sampling(bool);
void CollectSample();
void StartProfiling(const char* title, bool record_samples = false,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
@ -258,6 +261,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
Isolate* const isolate_;
base::TimeDelta sampling_interval_;
bool use_precise_sampling_ = true;
std::unique_ptr<CpuProfilesCollection> profiles_;
std::unique_ptr<ProfileGenerator> generator_;
std::unique_ptr<ProfilerEventsProcessor> processor_;

View File

@ -82,7 +82,8 @@ TEST(StartStop) {
ProfileGenerator generator(&profiles);
std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(isolate, &generator,
v8::base::TimeDelta::FromMicroseconds(100)));
v8::base::TimeDelta::FromMicroseconds(100),
true));
processor->Start();
processor->StopSynchronously();
}
@ -164,7 +165,7 @@ TEST(CodeEvents) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(100));
isolate, generator, v8::base::TimeDelta::FromMicroseconds(100), true);
processor->Start();
ProfilerListener profiler_listener(isolate, processor);
isolate->logger()->AddCodeEventListener(&profiler_listener);
@ -222,9 +223,9 @@ TEST(TickEvents) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100));
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false);
processor->Start();
@ -291,9 +292,9 @@ TEST(Issue1398) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100));
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false);
processor->Start();
@ -1149,9 +1150,9 @@ static void TickLines(bool optimize) {
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100));
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false);
// TODO(delphick): Stop using the CpuProfiler internals here: This forces
@ -2833,6 +2834,29 @@ TEST(FastStopProfiling) {
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 };
// Count the number of unique source positions.