[cpu-profiler] Enable logging for the lifetime of each CpuProfiler

Implements ProfilerCodeObserver, a class to track the generation and
movement of code on the heap for the lifetime of each CpuProfiler. When
sampling is inactive, logged code is committed directly to the CodeMap.
During profiling, ProfilerCodeObserver redirects these events onto the
profiling thread for later dispatch.

Bug: v8:9151
Change-Id: Ib5b152446d2a3838e1b00a80253fc4fbd2f6e8c3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1604143
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Cr-Commit-Position: refs/heads/master@{#62943}
This commit is contained in:
Andrew Comminos 2019-07-18 16:18:18 -07:00 committed by Commit Bot
parent 5ce023df29
commit 8f97640136
9 changed files with 331 additions and 138 deletions

View File

@ -307,6 +307,15 @@ enum CpuProfilingNamingMode {
kDebugNaming,
};
enum CpuProfilingLoggingMode {
// Enables logging when a profile is active, and disables logging when all
// profiles are detached.
kLazyLogging,
// Enables logging for the lifetime of the CpuProfiler. Calls to
// StartRecording are faster, at the expense of runtime overhead.
kEagerLogging,
};
/**
* Optional profiling attributes.
*/
@ -357,7 +366,8 @@ class V8_EXPORT CpuProfiler {
* |Dispose| method.
*/
static CpuProfiler* New(Isolate* isolate,
CpuProfilingNamingMode = kDebugNaming);
CpuProfilingNamingMode = kDebugNaming,
CpuProfilingLoggingMode = kLazyLogging);
/**
* Synchronously collect current stack sample in all profilers attached to

View File

@ -9805,9 +9805,11 @@ int CpuProfile::GetSamplesCount() const {
return reinterpret_cast<const i::CpuProfile*>(this)->samples_count();
}
CpuProfiler* CpuProfiler::New(Isolate* isolate, CpuProfilingNamingMode mode) {
return reinterpret_cast<CpuProfiler*>(
new i::CpuProfiler(reinterpret_cast<i::Isolate*>(isolate), mode));
CpuProfiler* CpuProfiler::New(Isolate* isolate,
CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode) {
return reinterpret_cast<CpuProfiler*>(new i::CpuProfiler(
reinterpret_cast<i::Isolate*>(isolate), naming_mode, logging_mode));
}
void CpuProfiler::Dispose() { delete reinterpret_cast<i::CpuProfiler*>(this); }

View File

@ -47,21 +47,56 @@ class CpuSampler : public sampler::Sampler {
SamplingEventsProcessor* processor_;
};
ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
ProfileGenerator* generator)
ProfilingScope::ProfilingScope(Isolate* isolate, ProfilerListener* listener)
: isolate_(isolate), listener_(listener) {
size_t profiler_count = isolate_->num_cpu_profilers();
profiler_count++;
isolate_->set_num_cpu_profilers(profiler_count);
isolate_->set_is_profiling(true);
isolate_->wasm_engine()->EnableCodeLogging(isolate_);
Logger* logger = isolate_->logger();
logger->AddCodeEventListener(listener_);
// Populate the ProfilerCodeObserver with the initial functions and
// callbacks on the heap.
DCHECK(isolate_->heap()->HasBeenSetUp());
if (!FLAG_prof_browser_mode) {
logger->LogCodeObjects();
}
logger->LogCompiledFunctions();
logger->LogAccessorCallbacks();
}
ProfilingScope::~ProfilingScope() {
isolate_->logger()->RemoveCodeEventListener(listener_);
size_t profiler_count = isolate_->num_cpu_profilers();
DCHECK_GT(profiler_count, 0);
profiler_count--;
isolate_->set_num_cpu_profilers(profiler_count);
if (profiler_count == 0) isolate_->set_is_profiling(false);
}
ProfilerEventsProcessor::ProfilerEventsProcessor(
Isolate* isolate, ProfileGenerator* generator,
ProfilerCodeObserver* code_observer)
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
generator_(generator),
code_observer_(code_observer),
running_(1),
last_code_event_id_(0),
last_processed_code_event_id_(0),
isolate_(isolate),
profiling_scope_(isolate) {}
isolate_(isolate) {
DCHECK(!code_observer_->processor());
code_observer_->set_processor(this);
}
SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
ProfileGenerator* generator,
base::TimeDelta period,
bool use_precise_sampling)
: ProfilerEventsProcessor(isolate, generator),
SamplingEventsProcessor::SamplingEventsProcessor(
Isolate* isolate, ProfileGenerator* generator,
ProfilerCodeObserver* code_observer, base::TimeDelta period,
bool use_precise_sampling)
: ProfilerEventsProcessor(isolate, generator, code_observer),
sampler_(new CpuSampler(isolate, this)),
period_(period),
use_precise_sampling_(use_precise_sampling) {
@ -70,7 +105,10 @@ SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
SamplingEventsProcessor::~SamplingEventsProcessor() { sampler_->Stop(); }
ProfilerEventsProcessor::~ProfilerEventsProcessor() = default;
ProfilerEventsProcessor::~ProfilerEventsProcessor() {
DCHECK_EQ(code_observer_->processor(), this);
code_observer_->clear_processor();
}
void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
event.generic.order = ++last_code_event_id_;
@ -123,17 +161,7 @@ void ProfilerEventsProcessor::StopSynchronously() {
bool ProfilerEventsProcessor::ProcessCodeEvent() {
CodeEventsContainer record;
if (events_buffer_.Dequeue(&record)) {
switch (record.generic.type) {
#define PROFILER_TYPE_CASE(type, clss) \
case CodeEventRecord::type: \
record.clss##_.UpdateCodeMap(generator_->code_map()); \
break;
CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
#undef PROFILER_TYPE_CASE
default: return true; // Skip record.
}
code_observer_->CodeEventHandlerInternal(record);
last_processed_code_event_id_ = record.generic.order;
return true;
}
@ -262,6 +290,62 @@ void* SamplingEventsProcessor::operator new(size_t size) {
void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate)
: isolate_(isolate), processor_(nullptr) {
CreateEntriesForRuntimeCallStats();
LogBuiltins();
}
void ProfilerCodeObserver::CodeEventHandler(
const CodeEventsContainer& evt_rec) {
if (processor_) {
processor_->CodeEventHandler(evt_rec);
return;
}
CodeEventHandlerInternal(evt_rec);
}
void ProfilerCodeObserver::CodeEventHandlerInternal(
const CodeEventsContainer& evt_rec) {
CodeEventsContainer record = evt_rec;
switch (evt_rec.generic.type) {
#define PROFILER_TYPE_CASE(type, clss) \
case CodeEventRecord::type: \
record.clss##_.UpdateCodeMap(&code_map_); \
break;
CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
#undef PROFILER_TYPE_CASE
default:
break;
}
}
void ProfilerCodeObserver::CreateEntriesForRuntimeCallStats() {
RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
RuntimeCallCounter* counter = rcs->GetCounter(i);
DCHECK(counter->name());
auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
"native V8Runtime");
code_map_.AddCode(reinterpret_cast<Address>(counter), entry, 1);
}
}
void ProfilerCodeObserver::LogBuiltins() {
Builtins* builtins = isolate_->builtins();
DCHECK(builtins->is_initialized());
for (int i = 0; i < Builtins::builtin_count; i++) {
CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
Builtins::Name id = static_cast<Builtins::Name>(i);
rec->instruction_start = builtins->builtin(id).InstructionStart();
rec->builtin_id = id;
CodeEventHandlerInternal(evt_rec);
}
}
int CpuProfiler::GetProfilesCount() {
// The count of profiles doesn't depend on a security token.
return static_cast<int>(profiles_->profiles()->size());
@ -324,29 +408,37 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager)
} // namespace
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode)
: CpuProfiler(isolate, naming_mode, new CpuProfilesCollection(isolate),
nullptr, nullptr) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode)
: CpuProfiler(isolate, naming_mode, logging_mode,
new CpuProfilesCollection(isolate), nullptr, nullptr) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode,
CpuProfilesCollection* test_profiles,
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor)
: isolate_(isolate),
naming_mode_(naming_mode),
logging_mode_(logging_mode),
base_sampling_interval_(base::TimeDelta::FromMicroseconds(
FLAG_cpu_profiler_sampling_interval)),
profiles_(test_profiles),
generator_(test_generator),
processor_(test_processor),
code_observer_(isolate),
is_profiling_(false) {
profiles_->set_cpu_profiler(this);
GetProfilersManager()->AddProfiler(isolate, this);
if (logging_mode == kEagerLogging) EnableLogging();
}
CpuProfiler::~CpuProfiler() {
DCHECK(!is_profiling_);
GetProfilersManager()->RemoveProfiler(isolate_, this);
DisableLogging();
}
void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
@ -362,20 +454,26 @@ void CpuProfiler::set_use_precise_sampling(bool value) {
void CpuProfiler::ResetProfiles() {
profiles_.reset(new CpuProfilesCollection(isolate_));
profiles_->set_cpu_profiler(this);
profiler_listener_.reset();
generator_.reset();
if (!profiling_scope_) profiler_listener_.reset();
}
void CpuProfiler::CreateEntriesForRuntimeCallStats() {
RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
CodeMap* code_map = generator_->code_map();
for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
RuntimeCallCounter* counter = rcs->GetCounter(i);
DCHECK(counter->name());
auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
"native V8Runtime");
code_map->AddCode(reinterpret_cast<Address>(counter), entry, 1);
void CpuProfiler::EnableLogging() {
if (profiling_scope_) return;
if (!profiler_listener_) {
profiler_listener_.reset(
new ProfilerListener(isolate_, &code_observer_, naming_mode_));
}
profiling_scope_.reset(
new ProfilingScope(isolate_, profiler_listener_.get()));
}
void CpuProfiler::DisableLogging() {
if (!profiling_scope_) return;
DCHECK(profiler_listener_);
profiling_scope_.reset();
}
base::TimeDelta CpuProfiler::ComputeSamplingInterval() const {
@ -418,36 +516,23 @@ void CpuProfiler::StartProcessorIfNotStarted() {
processor_->AddCurrentStack();
return;
}
isolate_->wasm_engine()->EnableCodeLogging(isolate_);
Logger* logger = isolate_->logger();
bool codemap_needs_initialization = false;
if (!profiling_scope_) {
DCHECK_EQ(logging_mode_, kLazyLogging);
EnableLogging();
}
if (!generator_) {
generator_.reset(new ProfileGenerator(profiles_.get()));
codemap_needs_initialization = true;
CreateEntriesForRuntimeCallStats();
generator_.reset(
new ProfileGenerator(profiles_.get(), code_observer_.code_map()));
}
base::TimeDelta sampling_interval = ComputeSamplingInterval();
processor_.reset(new SamplingEventsProcessor(
isolate_, generator_.get(), sampling_interval, use_precise_sampling_));
if (profiler_listener_) {
profiler_listener_->set_observer(processor_.get());
} else {
profiler_listener_.reset(
new ProfilerListener(isolate_, processor_.get(), naming_mode_));
}
logger->AddCodeEventListener(profiler_listener_.get());
processor_.reset(
new SamplingEventsProcessor(isolate_, generator_.get(), &code_observer_,
sampling_interval, use_precise_sampling_));
is_profiling_ = true;
// Enumerate stuff we already have in the heap.
DCHECK(isolate_->heap()->HasBeenSetUp());
if (codemap_needs_initialization) {
if (!FLAG_prof_browser_mode) {
logger->LogCodeObjects();
}
logger->LogCompiledFunctions();
logger->LogAccessorCallbacks();
LogBuiltins();
}
// Enable stack sampling.
processor_->AddCurrentStack();
processor_->StartSynchronously();
@ -471,26 +556,14 @@ void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
}
void CpuProfiler::StopProcessor() {
Logger* logger = isolate_->logger();
is_profiling_ = false;
logger->RemoveCodeEventListener(profiler_listener_.get());
processor_->StopSynchronously();
processor_.reset();
}
void CpuProfiler::LogBuiltins() {
Builtins* builtins = isolate_->builtins();
DCHECK(builtins->is_initialized());
for (int i = 0; i < Builtins::builtin_count; i++) {
CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
Builtins::Name id = static_cast<Builtins::Name>(i);
rec->instruction_start = builtins->builtin(id).InstructionStart();
rec->builtin_id = id;
processor_->Enqueue(evt_rec);
DCHECK(profiling_scope_);
if (logging_mode_ == kLazyLogging) {
DisableLogging();
}
}
} // namespace internal
} // namespace v8

View File

@ -129,28 +129,20 @@ class CodeEventsContainer {
};
};
// Maintains the number of active CPU profilers in an isolate.
// Maintains the number of active CPU profilers in an isolate, and routes
// logging to a given ProfilerListener.
class ProfilingScope {
public:
explicit ProfilingScope(Isolate* isolate) : isolate_(isolate) {
size_t profiler_count = isolate_->num_cpu_profilers();
profiler_count++;
isolate_->set_num_cpu_profilers(profiler_count);
isolate_->set_is_profiling(true);
}
~ProfilingScope() {
size_t profiler_count = isolate_->num_cpu_profilers();
DCHECK_GT(profiler_count, 0);
profiler_count--;
isolate_->set_num_cpu_profilers(profiler_count);
if (profiler_count == 0) isolate_->set_is_profiling(false);
}
ProfilingScope(Isolate* isolate, ProfilerListener* listener);
~ProfilingScope();
private:
Isolate* const isolate_;
ProfilerListener* const listener_;
};
class ProfilerCodeObserver;
// This class implements both the profile events processor thread and
// methods called by event producers: VM and stack sampler threads.
class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
@ -175,7 +167,8 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
virtual void SetSamplingInterval(base::TimeDelta) {}
protected:
ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator);
ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
ProfilerCodeObserver* code_observer);
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent();
@ -188,6 +181,7 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
virtual SampleProcessingResult ProcessOneSample() = 0;
ProfileGenerator* generator_;
ProfilerCodeObserver* code_observer_;
base::Atomic32 running_;
base::ConditionVariable running_cond_;
base::Mutex running_mutex_;
@ -196,13 +190,13 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
std::atomic<unsigned> last_code_event_id_;
unsigned last_processed_code_event_id_;
Isolate* isolate_;
ProfilingScope profiling_scope_;
};
class V8_EXPORT_PRIVATE SamplingEventsProcessor
: public ProfilerEventsProcessor {
public:
SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
ProfilerCodeObserver* code_observer,
base::TimeDelta period, bool use_precise_sampling);
~SamplingEventsProcessor() override;
@ -241,11 +235,47 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
// low sampling intervals on Windows.
};
// Builds and maintains a CodeMap tracking code objects on the VM heap. While
// alive, logs generated code, callbacks, and builtins from the isolate.
// Redirects events to the profiler events processor when present.
class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
public:
explicit ProfilerCodeObserver(Isolate*);
void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
CodeMap* code_map() { return &code_map_; }
private:
friend class ProfilerEventsProcessor;
void CodeEventHandlerInternal(const CodeEventsContainer& evt_rec);
void CreateEntriesForRuntimeCallStats();
void LogBuiltins();
ProfilerEventsProcessor* processor() { return processor_; }
// Redirects code events to be enqueued on the given events processor.
void set_processor(ProfilerEventsProcessor* processor) {
processor_ = processor;
}
// Stops redirection of code events onto an events processor.
void clear_processor() { processor_ = nullptr; }
Isolate* const isolate_;
CodeMap code_map_;
ProfilerEventsProcessor* processor_;
};
class V8_EXPORT_PRIVATE CpuProfiler {
public:
explicit CpuProfiler(Isolate* isolate, CpuProfilingNamingMode = kDebugNaming);
explicit CpuProfiler(Isolate* isolate, CpuProfilingNamingMode = kDebugNaming,
CpuProfilingLoggingMode = kLazyLogging);
CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode,
CpuProfilesCollection* profiles, ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor);
@ -255,6 +285,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
using ProfilingMode = v8::CpuProfilingMode;
using NamingMode = v8::CpuProfilingNamingMode;
using LoggingMode = v8::CpuProfilingLoggingMode;
base::TimeDelta sampling_interval() const { return base_sampling_interval_; }
void set_sampling_interval(base::TimeDelta value);
@ -284,8 +315,9 @@ class V8_EXPORT_PRIVATE CpuProfiler {
void StopProcessorIfLastProfile(const char* title);
void StopProcessor();
void ResetProfiles();
void LogBuiltins();
void CreateEntriesForRuntimeCallStats();
void EnableLogging();
void DisableLogging();
// Computes a sampling interval sufficient to accomodate attached profiles.
base::TimeDelta ComputeSamplingInterval() const;
@ -295,6 +327,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
Isolate* const isolate_;
const NamingMode naming_mode_;
const LoggingMode logging_mode_;
bool use_precise_sampling_ = true;
// Sampling interval to which per-profile sampling intervals will be clamped
// to a multiple of, or used as the default if unspecified.
@ -303,6 +336,8 @@ class V8_EXPORT_PRIVATE CpuProfiler {
std::unique_ptr<ProfileGenerator> generator_;
std::unique_ptr<ProfilerEventsProcessor> processor_;
std::unique_ptr<ProfilerListener> profiler_listener_;
std::unique_ptr<ProfilingScope> profiling_scope_;
ProfilerCodeObserver code_observer_;
bool is_profiling_;
DISALLOW_COPY_AND_ASSIGN(CpuProfiler);

View File

@ -28,7 +28,7 @@ CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
instruction_start_(instruction_start) {}
inline CodeEntry* ProfileGenerator::FindEntry(Address address) {
CodeEntry* entry = code_map_.FindEntry(address);
CodeEntry* entry = code_map_->FindEntry(address);
if (entry) entry->mark_used();
return entry;
}

View File

@ -825,8 +825,9 @@ void CpuProfilesCollection::AddPathToCurrentProfiles(
current_profiles_semaphore_.Signal();
}
ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
: profiles_(profiles) {}
ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles,
CodeMap* code_map)
: profiles_(profiles), code_map_(code_map) {}
void ProfileGenerator::RecordTickSample(const TickSample& sample) {
ProfileStackTrace stack_trace;

View File

@ -494,18 +494,18 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
class V8_EXPORT_PRIVATE ProfileGenerator {
public:
explicit ProfileGenerator(CpuProfilesCollection* profiles);
explicit ProfileGenerator(CpuProfilesCollection* profiles, CodeMap* code_map);
void RecordTickSample(const TickSample& sample);
CodeMap* code_map() { return &code_map_; }
CodeMap* code_map() { return code_map_; }
private:
CodeEntry* FindEntry(Address address);
CodeEntry* EntryForVMState(StateTag tag);
CpuProfilesCollection* profiles_;
CodeMap code_map_;
CodeMap* const code_map_;
DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
};

View File

@ -79,9 +79,10 @@ static const char* reason(const i::DeoptimizeReason reason) {
TEST(StartStop) {
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
ProfileGenerator generator(&profiles);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator generator(&profiles, code_observer.code_map());
std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(isolate, &generator,
new SamplingEventsProcessor(isolate, &generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100),
true));
processor->Start();
@ -163,9 +164,12 @@ TEST(CodeEvents) {
i::AbstractCode moved_code = CreateCode(&env);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(100), true);
isolate, generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
processor->Start();
ProfilerListener profiler_listener(isolate, processor);
isolate->logger()->AddCodeEventListener(&profiler_listener);
@ -222,11 +226,14 @@ TEST(TickEvents) {
i::AbstractCode frame3_code = CreateCode(&env);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
CcTest::i_isolate(), generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
processor);
profiles->StartProfiling("");
processor->Start();
ProfilerListener profiler_listener(isolate, processor);
@ -291,11 +298,14 @@ TEST(Issue1398) {
i::AbstractCode code = CreateCode(&env);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
CcTest::i_isolate(), generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
processor);
profiles->StartProfiling("");
processor->Start();
ProfilerListener profiler_listener(isolate, processor);
@ -1154,11 +1164,14 @@ static void TickLines(bool optimize) {
CHECK_NE(code_address, kNullAddress);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
CcTest::i_isolate(), generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
processor);
profiles->StartProfiling("");
// TODO(delphick): Stop using the CpuProfiler internals here: This forces
// LogCompiledFunctions so that source positions are collected everywhere.
@ -2488,7 +2501,6 @@ TEST(DeoptAtFirstLevelInlinedSource) {
iprofiler->DeleteProfile(iprofile);
}
// deopt at the second level inlined function
TEST(DeoptAtSecondLevelInlinedSource) {
if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
@ -3062,9 +3074,10 @@ TEST(FastStopProfiling) {
TEST(LowPrecisionSamplingStartStopInternal) {
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
ProfileGenerator generator(&profiles);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator generator(&profiles, code_observer.code_map());
std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(isolate, &generator,
new SamplingEventsProcessor(isolate, &generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100),
false));
processor->Start();
@ -3187,11 +3200,15 @@ TEST(ProflilerSubsampling) {
i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
processor);
// Create a new CpuProfile that wants samples at 8us.
CpuProfile profile(&profiler, "",
@ -3228,11 +3245,15 @@ TEST(DynamicResampling) {
i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
processor);
// Set a 1us base sampling rate, dividing all possible intervals.
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(1));
@ -3286,11 +3307,15 @@ TEST(DynamicResamplingWithBaseInterval) {
i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfileGenerator* generator = new ProfileGenerator(profiles);
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, generator, v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
ProfilerCodeObserver code_observer(isolate);
ProfileGenerator* generator =
new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
processor);
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(7));
@ -3338,6 +3363,50 @@ TEST(DynamicResamplingWithBaseInterval) {
profiles->StopProfiling("5us");
}
// Tests that functions compiled after a started profiler is stopped are still
// visible when the profiler is started again. (https://crbug.com/v8/9151)
TEST(Bug9151StaleCodeEntries) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::Local<v8::FunctionTemplate> func_template =
v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample);
v8::Local<v8::Function> func =
func_template->GetFunction(env.local()).ToLocalChecked();
func->SetName(v8_str("CallCollectSample"));
env->Global()->Set(env.local(), v8_str("CallCollectSample"), func).FromJust();
v8::CpuProfiler* profiler =
v8::CpuProfiler::New(env->GetIsolate(), kDebugNaming, kEagerLogging);
v8::Local<v8::String> profile_name = v8_str("");
// Warm up the profiler to create the initial code map.
profiler->StartProfiling(profile_name);
profiler->StopProfiling(profile_name);
// Log a function compilation (executed once to force a compilation).
CompileRun(R"(
function start() {
CallCollectSample();
}
start();
)");
// Restart the profiler, and execute both the JS function and callback.
profiler->StartProfiling(profile_name, true);
CompileRun("start();");
v8::CpuProfile* profile = profiler->StopProfiling(profile_name);
auto* root = profile->GetTopDownRoot();
auto* toplevel = GetChild(env.local(), root, "");
auto* start = FindChild(env.local(), toplevel, "start");
CHECK(start);
auto* callback = FindChild(env.local(), start, "CallCollectSample");
CHECK(callback);
}
enum class EntryCountMode { kAll, kOnlyInlined };
// Count the number of unique source positions.

View File

@ -381,7 +381,8 @@ TEST(RecordTickSample) {
CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("");
ProfileGenerator generator(&profiles);
CodeMap code_map;
ProfileGenerator generator(&profiles, &code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
@ -449,7 +450,8 @@ TEST(SampleIds) {
CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
ProfileGenerator generator(&profiles);
CodeMap code_map;
ProfileGenerator generator(&profiles, &code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
@ -503,7 +505,8 @@ TEST(NoSamples) {
CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("");
ProfileGenerator generator(&profiles);
CodeMap code_map;
ProfileGenerator generator(&profiles, &code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);