| // Copyright 2015 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 "platform/heap/BlinkGCMemoryDumpProvider.h" |
| |
| #include <unordered_map> |
| |
| #include "base/trace_event/heap_profiler_allocation_context_tracker.h" |
| #include "base/trace_event/memory_allocator_dump.h" |
| #include "base/trace_event/process_memory_dump.h" |
| #include "base/trace_event/trace_event_memory_overhead.h" |
| #include "platform/heap/Handle.h" |
| #include "platform/instrumentation/tracing/web_memory_allocator_dump.h" |
| #include "platform/wtf/StdLibExtras.h" |
| #include "platform/wtf/Threading.h" |
| #include "public/platform/Platform.h" |
| |
| namespace blink { |
| namespace { |
| |
| void DumpMemoryTotals(base::trace_event::ProcessMemoryDump* memory_dump) { |
| base::trace_event::MemoryAllocatorDump* allocator_dump = |
| memory_dump->CreateAllocatorDump("blink_gc"); |
| allocator_dump->AddScalar("size", "bytes", |
| ProcessHeap::TotalAllocatedSpace()); |
| |
| base::trace_event::MemoryAllocatorDump* objects_dump = |
| memory_dump->CreateAllocatorDump("blink_gc/allocated_objects"); |
| |
| // ThreadHeap::markedObjectSize() can be underestimated if we're still in the |
| // process of lazy sweeping. |
| objects_dump->AddScalar("size", "bytes", |
| ProcessHeap::TotalAllocatedObjectSize() + |
| ProcessHeap::TotalMarkedObjectSize()); |
| } |
| |
| void ReportAllocation(Address address, size_t size, const char* type_name) { |
| BlinkGCMemoryDumpProvider::Instance()->insert(address, size, type_name); |
| } |
| |
| void ReportFree(Address address) { |
| BlinkGCMemoryDumpProvider::Instance()->Remove(address); |
| } |
| |
| } // namespace |
| |
| BlinkGCMemoryDumpProvider* BlinkGCMemoryDumpProvider::Instance() { |
| DEFINE_STATIC_LOCAL(BlinkGCMemoryDumpProvider, instance, ()); |
| return &instance; |
| } |
| |
| BlinkGCMemoryDumpProvider::~BlinkGCMemoryDumpProvider() = default; |
| |
| bool BlinkGCMemoryDumpProvider::OnMemoryDump( |
| const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* memory_dump) { |
| using base::trace_event::MemoryDumpLevelOfDetail; |
| MemoryDumpLevelOfDetail level_of_detail = args.level_of_detail; |
| // In the case of a detailed dump perform a mark-only GC pass to collect |
| // more detailed stats. |
| if (level_of_detail == MemoryDumpLevelOfDetail::DETAILED) |
| ThreadState::Current()->CollectGarbage(BlinkGC::kNoHeapPointersOnStack, |
| BlinkGC::kTakeSnapshot, |
| BlinkGC::kForcedGC); |
| DumpMemoryTotals(memory_dump); |
| |
| if (allocation_register_.is_enabled()) { |
| // Overhead should always be reported, regardless of light vs. heavy. |
| base::trace_event::TraceEventMemoryOverhead overhead; |
| std::unordered_map<base::trace_event::AllocationContext, |
| base::trace_event::AllocationMetrics> |
| metrics_by_context; |
| if (level_of_detail == MemoryDumpLevelOfDetail::DETAILED) { |
| allocation_register_.UpdateAndReturnsMetrics(metrics_by_context); |
| } |
| allocation_register_.EstimateTraceMemoryOverhead(&overhead); |
| memory_dump->DumpHeapUsage(metrics_by_context, overhead, "blink_gc"); |
| } |
| |
| // Merge all dumps collected by ThreadHeap::collectGarbage. |
| if (level_of_detail == MemoryDumpLevelOfDetail::DETAILED) |
| memory_dump->TakeAllDumpsFrom(current_process_memory_dump_.get()); |
| return true; |
| } |
| |
| void BlinkGCMemoryDumpProvider::OnHeapProfilingEnabled(bool enabled) { |
| if (enabled) { |
| allocation_register_.SetEnabled(); |
| HeapAllocHooks::SetAllocationHook(ReportAllocation); |
| HeapAllocHooks::SetFreeHook(ReportFree); |
| } else { |
| HeapAllocHooks::SetAllocationHook(nullptr); |
| HeapAllocHooks::SetFreeHook(nullptr); |
| allocation_register_.SetDisabled(); |
| } |
| } |
| |
| base::trace_event::MemoryAllocatorDump* |
| BlinkGCMemoryDumpProvider::CreateMemoryAllocatorDumpForCurrentGC( |
| const String& absolute_name) { |
| // TODO(bashi): Change type name of |absoluteName|. |
| return current_process_memory_dump_->CreateAllocatorDump( |
| absolute_name.Utf8().data()); |
| } |
| |
| void BlinkGCMemoryDumpProvider::ClearProcessDumpForCurrentGC() { |
| current_process_memory_dump_->Clear(); |
| } |
| |
| BlinkGCMemoryDumpProvider::BlinkGCMemoryDumpProvider() |
| : current_process_memory_dump_(new base::trace_event::ProcessMemoryDump( |
| nullptr, |
| {base::trace_event::MemoryDumpLevelOfDetail::DETAILED})) {} |
| |
| void BlinkGCMemoryDumpProvider::insert(Address address, |
| size_t size, |
| const char* type_name) { |
| base::trace_event::AllocationContext context; |
| if (!base::trace_event::AllocationContextTracker:: |
| GetInstanceForCurrentThread() |
| ->GetContextSnapshot(&context)) |
| return; |
| context.type_name = type_name; |
| if (!allocation_register_.is_enabled()) |
| return; |
| allocation_register_.Insert(address, size, context); |
| } |
| |
| void BlinkGCMemoryDumpProvider::Remove(Address address) { |
| if (!allocation_register_.is_enabled()) |
| return; |
| allocation_register_.Remove(address); |
| } |
| |
| } // namespace blink |