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

[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/+/1604143Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Cr-Commit-Position: refs/heads/master@{#62943}
parent 5ce023df
......@@ -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
......
......@@ -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); }
......
This diff is collapsed.
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
};
......
This diff is collapsed.
......@@ -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);
......
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