[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:
parent
c8206043e1
commit
8b3cd48db8
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user