[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 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;
};

View File

@ -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<i::Isolate*>(isolate));
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:
std::unordered_multimap<Isolate*, CpuProfiler*> 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<DiscardedSamplesDelegate> delegate) {

View File

@ -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<DiscardedSamplesDelegate> delegate = nullptr);

View File

@ -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