[api][profiler] Surface CpuProfiler memory in HeapCodeStatistics

The goal of the PR is to add to telemetry a metric estimating the space
occupied by the codemap retained by a CpuProfiler and its underlying
CodeObserver.

This change is motivated by the addition of kEagerLogger to CpuProfiler
which when enabled let a CpuProfiler build a CodeMap without an active
session. This metric will help us understand better the space consumed
by a profiler in that scenario and will also help detect memory leaks.

Bug: chromium:1241491
Change-Id: Iadb1ed52b4c1ac70bc554942b4fa795cdf1212f3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3224567
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Auto-Submit: Corentin Pescheloche <cpescheloche@fb.com>
Cr-Commit-Position: refs/heads/main@{#77703}
This commit is contained in:
Corentin Pescheloche 2021-11-01 13:30:38 -07:00 committed by V8 LUCI CQ
parent 71bffcced0
commit 0bf11af7e4
5 changed files with 41 additions and 11 deletions

View File

@ -201,11 +201,13 @@ class V8_EXPORT HeapCodeStatistics {
size_t code_and_metadata_size() { return code_and_metadata_size_; } size_t code_and_metadata_size() { return code_and_metadata_size_; }
size_t bytecode_and_metadata_size() { return bytecode_and_metadata_size_; } size_t bytecode_and_metadata_size() { return bytecode_and_metadata_size_; }
size_t external_script_source_size() { return external_script_source_size_; } size_t external_script_source_size() { return external_script_source_size_; }
size_t cpu_profiler_metadata_size() { return cpu_profiler_metadata_size_; }
private: private:
size_t code_and_metadata_size_; size_t code_and_metadata_size_;
size_t bytecode_and_metadata_size_; size_t bytecode_and_metadata_size_;
size_t external_script_source_size_; size_t external_script_source_size_;
size_t cpu_profiler_metadata_size_;
friend class Isolate; friend class Isolate;
}; };

View File

@ -6144,7 +6144,8 @@ HeapObjectStatistics::HeapObjectStatistics()
HeapCodeStatistics::HeapCodeStatistics() HeapCodeStatistics::HeapCodeStatistics()
: code_and_metadata_size_(0), : code_and_metadata_size_(0),
bytecode_and_metadata_size_(0), bytecode_and_metadata_size_(0),
external_script_source_size_(0) {} external_script_source_size_(0),
cpu_profiler_metadata_size_(0) {}
bool v8::V8::InitializeICU(const char* icu_data_file) { bool v8::V8::InitializeICU(const char* icu_data_file) {
return i::InitializeICU(icu_data_file); return i::InitializeICU(icu_data_file);
@ -8897,6 +8898,10 @@ bool Isolate::GetHeapCodeAndMetadataStatistics(
isolate->bytecode_and_metadata_size(); isolate->bytecode_and_metadata_size();
code_statistics->external_script_source_size_ = code_statistics->external_script_source_size_ =
isolate->external_script_source_size(); isolate->external_script_source_size();
code_statistics->cpu_profiler_metadata_size_ =
i::CpuProfiler::GetAllProfilersMemorySize(
reinterpret_cast<i::Isolate*>(isolate));
return true; return true;
} }

View File

@ -471,6 +471,16 @@ class CpuProfilersManager {
} }
} }
size_t GetAllProfilersMemorySize(Isolate* isolate) {
base::MutexGuard lock(&mutex_);
size_t estimated_memory = 0;
auto range = profilers_.equal_range(isolate);
for (auto it = range.first; it != range.second; ++it) {
estimated_memory += it->second->GetEstimatedMemoryUsage();
}
return estimated_memory;
}
private: private:
std::unordered_multimap<Isolate*, CpuProfiler*> profilers_; std::unordered_multimap<Isolate*, CpuProfiler*> profilers_;
base::Mutex mutex_; base::Mutex mutex_;
@ -578,6 +588,15 @@ void CpuProfiler::CollectSample() {
} }
} }
// static
size_t CpuProfiler::GetAllProfilersMemorySize(Isolate* isolate) {
return GetProfilersManager()->GetAllProfilersMemorySize(isolate);
}
size_t CpuProfiler::GetEstimatedMemoryUsage() const {
return code_observer_->GetEstimatedMemoryUsage();
}
CpuProfilingStatus CpuProfiler::StartProfiling( CpuProfilingStatus CpuProfiler::StartProfiling(
const char* title, CpuProfilingOptions options, const char* title, CpuProfilingOptions options,
std::unique_ptr<DiscardedSamplesDelegate> delegate) { std::unique_ptr<DiscardedSamplesDelegate> delegate) {

View File

@ -333,6 +333,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
CpuProfiler& operator=(const CpuProfiler&) = delete; CpuProfiler& operator=(const CpuProfiler&) = delete;
static void CollectSample(Isolate* isolate); static void CollectSample(Isolate* isolate);
static size_t GetAllProfilersMemorySize(Isolate* isolate);
using ProfilingMode = v8::CpuProfilingMode; using ProfilingMode = v8::CpuProfilingMode;
using NamingMode = v8::CpuProfilingNamingMode; using NamingMode = v8::CpuProfilingNamingMode;
@ -343,6 +344,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
void set_sampling_interval(base::TimeDelta value); void set_sampling_interval(base::TimeDelta value);
void set_use_precise_sampling(bool); void set_use_precise_sampling(bool);
void CollectSample(); void CollectSample();
size_t GetEstimatedMemoryUsage() const;
StartProfilingStatus StartProfiling( StartProfilingStatus StartProfiling(
const char* title, CpuProfilingOptions options = {}, const char* title, CpuProfilingOptions options = {},
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr); std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);

View File

@ -4331,7 +4331,7 @@ TEST(ClearUnusedWithEagerLogging) {
CodeMap* code_map = profiler.code_map_for_test(); CodeMap* code_map = profiler.code_map_for_test();
size_t initial_size = code_map->size(); size_t initial_size = code_map->size();
size_t profiler_size = code_observer->GetEstimatedMemoryUsage(); size_t profiler_size = profiler.GetEstimatedMemoryUsage();
{ {
// Create and run a new script and function, generating 2 code objects. // Create and run a new script and function, generating 2 code objects.
@ -4343,7 +4343,8 @@ TEST(ClearUnusedWithEagerLogging) {
"function some_func() {}" "function some_func() {}"
"some_func();"); "some_func();");
CHECK_GT(code_map->size(), initial_size); CHECK_GT(code_map->size(), initial_size);
CHECK_GT(code_observer->GetEstimatedMemoryUsage(), profiler_size); CHECK_GT(profiler.GetEstimatedMemoryUsage(), profiler_size);
CHECK_GT(profiler.GetAllProfilersMemorySize(isolate), profiler_size);
} }
// Clear the compilation cache so that there are no more references to the // Clear the compilation cache so that there are no more references to the
@ -4354,7 +4355,8 @@ TEST(ClearUnusedWithEagerLogging) {
// Verify that the CodeMap's size is unchanged post-GC. // Verify that the CodeMap's size is unchanged post-GC.
CHECK_EQ(code_map->size(), initial_size); CHECK_EQ(code_map->size(), initial_size);
CHECK_EQ(code_observer->GetEstimatedMemoryUsage(), profiler_size); CHECK_EQ(profiler.GetEstimatedMemoryUsage(), profiler_size);
CHECK_EQ(profiler.GetAllProfilersMemorySize(isolate), profiler_size);
} }
// Ensure that ProfilerCodeObserver doesn't compute estimated size when race // Ensure that ProfilerCodeObserver doesn't compute estimated size when race
@ -4367,20 +4369,20 @@ TEST(SkipEstimatedSizeWhenActiveProfiling) {
CodeEntryStorage storage; CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
CpuProfiler profiler(isolate, kDebugNaming, kEagerLogging, profiles, nullptr, CpuProfiler profiler(isolate, kDebugNaming, kEagerLogging, profiles, nullptr,
nullptr, code_observer); nullptr, new ProfilerCodeObserver(isolate, storage));
CHECK_GT(code_observer->GetEstimatedMemoryUsage(), 0); CHECK_GT(profiler.GetAllProfilersMemorySize(isolate), 0);
CHECK_GT(profiler.GetEstimatedMemoryUsage(), 0);
profiler.StartProfiling(""); profiler.StartProfiling("");
CHECK_EQ(code_observer->GetEstimatedMemoryUsage(), 0); CHECK_EQ(profiler.GetAllProfilersMemorySize(isolate), 0);
CHECK_EQ(profiler.GetEstimatedMemoryUsage(), 0);
profiler.StopProfiling(""); profiler.StopProfiling("");
CHECK_GT(code_observer->GetEstimatedMemoryUsage(), 0); CHECK_GT(profiler.GetAllProfilersMemorySize(isolate), 0);
CHECK_GT(profiler.GetEstimatedMemoryUsage(), 0);
} }
} // namespace test_cpu_profiler } // namespace test_cpu_profiler