blob: dd1edb88b0d4e33b6e1a415e235753b70313ab58 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h"
#include <inttypes.h>
#include "base/strings/stringprintf.h"
#include "base/trace_event/memory_dump_manager.h"
#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
#include "v8/include/cppgc/heap-statistics.h"
namespace blink {
namespace {
constexpr const char* HeapTypeString(
BlinkGCMemoryDumpProvider::HeapType heap_type) {
switch (heap_type) {
case BlinkGCMemoryDumpProvider::HeapType::kBlinkMainThread:
return "main";
case BlinkGCMemoryDumpProvider::HeapType::kBlinkWorkerThread:
return "workers";
}
}
} // namespace
BlinkGCMemoryDumpProvider::BlinkGCMemoryDumpProvider(
ThreadState* thread_state,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
BlinkGCMemoryDumpProvider::HeapType heap_type)
: thread_state_(thread_state),
heap_type_(heap_type),
dump_base_name_(
"blink_gc/" + std::string(HeapTypeString(heap_type_)) + "/heap" +
(heap_type_ == HeapType::kBlinkWorkerThread
? "/" + base::StringPrintf(
"worker_0x%" PRIXPTR,
reinterpret_cast<uintptr_t>(thread_state_))
: "")) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "BlinkGC", task_runner);
}
BlinkGCMemoryDumpProvider::~BlinkGCMemoryDumpProvider() {
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
this);
}
bool BlinkGCMemoryDumpProvider::OnMemoryDump(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* process_memory_dump) {
::cppgc::HeapStatistics::DetailLevel detail_level =
args.level_of_detail ==
base::trace_event::MemoryDumpLevelOfDetail::DETAILED
? ::cppgc::HeapStatistics::kDetailed
: ::cppgc::HeapStatistics::kBrief;
::cppgc::HeapStatistics stats =
ThreadState::Current()->cpp_heap().CollectStatistics(detail_level);
auto* heap_dump = process_memory_dump->CreateAllocatorDump(dump_base_name_);
heap_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
stats.physical_size_bytes);
heap_dump->AddScalar("allocated_objects_size",
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
stats.used_size_bytes);
if (detail_level == ::cppgc::HeapStatistics::kBrief) {
return true;
}
// Detailed statistics.
for (const ::cppgc::HeapStatistics::SpaceStatistics& space_stats :
stats.space_stats) {
std::string arena_dump_name = dump_base_name_ + "/" + space_stats.name;
auto* arena_dump =
process_memory_dump->CreateAllocatorDump(arena_dump_name);
arena_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
space_stats.physical_size_bytes);
arena_dump->AddScalar("allocated_objects_size",
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
space_stats.used_size_bytes);
size_t page_count = 0;
for (const ::cppgc::HeapStatistics::PageStatistics& page_stats :
space_stats.page_stats) {
auto* page_dump = process_memory_dump->CreateAllocatorDump(
arena_dump_name + "/pages/page_" +
base::NumberToString(page_count++));
page_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
page_stats.physical_size_bytes);
page_dump->AddScalar("allocated_objects_size",
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
page_stats.used_size_bytes);
}
const ::cppgc::HeapStatistics::FreeListStatistics& free_list_stats =
space_stats.free_list_stats;
for (wtf_size_t i = 0; i < free_list_stats.bucket_size.size(); ++i) {
constexpr size_t kDigits = 8;
std::string original_bucket_size =
base::NumberToString(free_list_stats.bucket_size[i]);
std::string padded_bucket_size =
std::string(kDigits - original_bucket_size.length(), '0') +
original_bucket_size;
auto* free_list_bucket_dump = process_memory_dump->CreateAllocatorDump(
arena_dump_name + "/freelist/bucket_" + padded_bucket_size);
free_list_bucket_dump->AddScalar(
"free_size", base::trace_event::MemoryAllocatorDump::kUnitsBytes,
free_list_stats.free_size[i]);
}
const ::cppgc::HeapStatistics::ObjectStatistics& object_stats =
space_stats.object_stats;
for (wtf_size_t i = 1; i < object_stats.num_types; i++) {
if (object_stats.type_name[i].empty())
continue;
auto* class_dump = process_memory_dump->CreateAllocatorDump(
arena_dump_name + "/classes/" + object_stats.type_name[i]);
class_dump->AddScalar(
"object_count", base::trace_event::MemoryAllocatorDump::kUnitsObjects,
object_stats.type_count[i]);
class_dump->AddScalar("object_size",
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
object_stats.type_bytes[i]);
}
}
return true;
}
} // namespace blink