From 0bf11af7e4a5c42454af697054f10c7fccf43714 Mon Sep 17 00:00:00 2001 From: Corentin Pescheloche Date: Mon, 1 Nov 2021 13:30:38 -0700 Subject: [PATCH] [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 Commit-Queue: Camillo Bruni Auto-Submit: Corentin Pescheloche Cr-Commit-Position: refs/heads/main@{#77703} --- include/v8-statistics.h | 2 ++ src/api/api.cc | 7 ++++++- src/profiler/cpu-profiler.cc | 19 +++++++++++++++++++ src/profiler/cpu-profiler.h | 2 ++ test/cctest/test-cpu-profiler.cc | 22 ++++++++++++---------- 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/include/v8-statistics.h b/include/v8-statistics.h index 7f69e5d65e..ca20bc9f6c 100644 --- a/include/v8-statistics.h +++ b/include/v8-statistics.h @@ -201,11 +201,13 @@ class V8_EXPORT HeapCodeStatistics { size_t code_and_metadata_size() { return code_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 cpu_profiler_metadata_size() { return cpu_profiler_metadata_size_; } private: size_t code_and_metadata_size_; size_t bytecode_and_metadata_size_; size_t external_script_source_size_; + size_t cpu_profiler_metadata_size_; friend class Isolate; }; diff --git a/src/api/api.cc b/src/api/api.cc index be51eaca2a..19c59cd58a 100644 --- a/src/api/api.cc +++ b/src/api/api.cc @@ -6144,7 +6144,8 @@ HeapObjectStatistics::HeapObjectStatistics() HeapCodeStatistics::HeapCodeStatistics() : code_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) { return i::InitializeICU(icu_data_file); @@ -8897,6 +8898,10 @@ bool Isolate::GetHeapCodeAndMetadataStatistics( isolate->bytecode_and_metadata_size(); code_statistics->external_script_source_size_ = isolate->external_script_source_size(); + code_statistics->cpu_profiler_metadata_size_ = + i::CpuProfiler::GetAllProfilersMemorySize( + reinterpret_cast(isolate)); + return true; } diff --git a/src/profiler/cpu-profiler.cc b/src/profiler/cpu-profiler.cc index 829f2ab67f..111bd92b51 100644 --- a/src/profiler/cpu-profiler.cc +++ b/src/profiler/cpu-profiler.cc @@ -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: std::unordered_multimap profilers_; 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( const char* title, CpuProfilingOptions options, std::unique_ptr delegate) { diff --git a/src/profiler/cpu-profiler.h b/src/profiler/cpu-profiler.h index ea14d6c618..f42fdaa51b 100644 --- a/src/profiler/cpu-profiler.h +++ b/src/profiler/cpu-profiler.h @@ -333,6 +333,7 @@ class V8_EXPORT_PRIVATE CpuProfiler { CpuProfiler& operator=(const CpuProfiler&) = delete; static void CollectSample(Isolate* isolate); + static size_t GetAllProfilersMemorySize(Isolate* isolate); using ProfilingMode = v8::CpuProfilingMode; using NamingMode = v8::CpuProfilingNamingMode; @@ -343,6 +344,7 @@ class V8_EXPORT_PRIVATE CpuProfiler { void set_sampling_interval(base::TimeDelta value); void set_use_precise_sampling(bool); void CollectSample(); + size_t GetEstimatedMemoryUsage() const; StartProfilingStatus StartProfiling( const char* title, CpuProfilingOptions options = {}, std::unique_ptr delegate = nullptr); diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc index e78121d5a9..027b9a6979 100644 --- a/test/cctest/test-cpu-profiler.cc +++ b/test/cctest/test-cpu-profiler.cc @@ -4331,7 +4331,7 @@ TEST(ClearUnusedWithEagerLogging) { CodeMap* code_map = profiler.code_map_for_test(); 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. @@ -4343,7 +4343,8 @@ TEST(ClearUnusedWithEagerLogging) { "function some_func() {}" "some_func();"); 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 @@ -4354,7 +4355,8 @@ TEST(ClearUnusedWithEagerLogging) { // Verify that the CodeMap's size is unchanged post-GC. 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 @@ -4367,20 +4369,20 @@ TEST(SkipEstimatedSizeWhenActiveProfiling) { CodeEntryStorage storage; CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); - ProfilerCodeObserver* code_observer = - new ProfilerCodeObserver(isolate, storage); - 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(""); - CHECK_EQ(code_observer->GetEstimatedMemoryUsage(), 0); + CHECK_EQ(profiler.GetAllProfilersMemorySize(isolate), 0); + CHECK_EQ(profiler.GetEstimatedMemoryUsage(), 0); profiler.StopProfiling(""); - CHECK_GT(code_observer->GetEstimatedMemoryUsage(), 0); + CHECK_GT(profiler.GetAllProfilersMemorySize(isolate), 0); + CHECK_GT(profiler.GetEstimatedMemoryUsage(), 0); } } // namespace test_cpu_profiler