From 3e37155aca48e63f0dcae697de6fd2b9cdf2782a Mon Sep 17 00:00:00 2001 From: ssid Date: Tue, 25 Aug 2015 08:33:20 -0700 Subject: [PATCH] Add support to create memory allocator dump in base::DiscardableMemory The clients that use discardable memory need to make a memory dump for tracing. But, the client do not know if the memory is purged or not. So, discardable manager dumps the live segments and the clients would dump all the allocations, without the knowledge from the manager. To make the memory dumps consistent, new api is added to the base::discardable memory interface to create a memory allocator. this method creates dump only if the memory is live according to the manager. Note: This still does not mean that the memory is resident in the system, and the OS could have purged this discardable segment. This method only helps to make the memory dumps consistent across all systems. Also, the clients may not keep track the size of each segment they allocate. So, this api adds the size when creating the dump. See doc https://goo.gl/AFSTRP. BUG=503168 Review URL: https://codereview.chromium.org/1306243003 Cr-Commit-Position: refs/heads/master@{#345332} --- base/memory/discardable_memory.h | 13 ++++++ .../test/test_discardable_memory_allocator.cc | 6 +++ .../discardable_memory_allocator.cc | 18 ++++++++ ...child_discardable_shared_memory_manager.cc | 15 +++++++ .../child_discardable_shared_memory_manager.h | 5 +++ .../common/discardable_shared_memory_heap.cc | 43 +++++++++++++++++++ .../common/discardable_shared_memory_heap.h | 14 ++++++ ...discardable_shared_memory_heap_unittest.cc | 29 +++++++++++++ .../host_discardable_shared_memory_manager.cc | 13 ++++++ gpu/skia_runner/in_process_graphics_system.cc | 22 +++++++++- 10 files changed, 177 insertions(+), 1 deletion(-) diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h index fc189e74634113..c64fc4f7cf37af 100644 --- a/base/memory/discardable_memory.h +++ b/base/memory/discardable_memory.h @@ -11,6 +11,11 @@ namespace base { +namespace trace_event { +class MemoryAllocatorDump; +class ProcessMemoryDump; +} + // Discardable memory is used to cache large objects without worrying about // blowing out memory, both on mobile devices where there is no swap, and // desktop devices where unused free memory should be used to help the user @@ -59,6 +64,14 @@ class BASE_EXPORT DiscardableMemory { template T* data_as() const { return reinterpret_cast(data()); } + + // Used for dumping the statistics of discardable memory allocated in tracing. + // Returns a new MemoryAllocatorDump in the |pmd| with the size of the + // discardable memory. The MemoryAllocatorDump created is owned by |pmd|. See + // ProcessMemoryDump::CreateAllocatorDump. + virtual trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + trace_event::ProcessMemoryDump* pmd) const = 0; }; } // namespace base diff --git a/base/test/test_discardable_memory_allocator.cc b/base/test/test_discardable_memory_allocator.cc index 23d529c324d746..eef1c982446633 100644 --- a/base/test/test_discardable_memory_allocator.cc +++ b/base/test/test_discardable_memory_allocator.cc @@ -20,6 +20,12 @@ class DiscardableMemoryImpl : public DiscardableMemory { void Unlock() override {} void* data() const override { return data_.get(); } + trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + trace_event::ProcessMemoryDump* pmd) const override { + return nullptr; + } + private: scoped_ptr data_; }; diff --git a/components/html_viewer/discardable_memory_allocator.cc b/components/html_viewer/discardable_memory_allocator.cc index 7f362239b2d5f0..87f58e94d67864 100644 --- a/components/html_viewer/discardable_memory_allocator.cc +++ b/components/html_viewer/discardable_memory_allocator.cc @@ -6,6 +6,9 @@ #include "base/memory/discardable_memory.h" #include "base/stl_util.h" +#include "base/trace_event/memory_allocator_dump.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/process_memory_dump.h" namespace html_viewer { @@ -53,6 +56,21 @@ class DiscardableMemoryAllocator::DiscardableMemoryChunkImpl return nullptr; } + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const override { + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, size_); + + // Memory is allocated from system allocator (malloc). + pmd->AddSuballocation(dump->guid(), + base::trace_event::MemoryDumpManager::GetInstance() + ->system_allocator_pool_name()); + return dump; + } + size_t size() const { return size_; } void Discard() { diff --git a/content/child/child_discardable_shared_memory_manager.cc b/content/child/child_discardable_shared_memory_manager.cc index ff8fe4357881ed..dd432f8c8db213 100644 --- a/content/child/child_discardable_shared_memory_manager.cc +++ b/content/child/child_discardable_shared_memory_manager.cc @@ -61,6 +61,12 @@ class DiscardableMemoryImpl : public base::DiscardableMemory { return reinterpret_cast(span_->start() * base::GetPageSize()); } + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const override { + return manager_->CreateMemoryAllocatorDump(span_.get(), name, pmd); + } + private: ChildDiscardableSharedMemoryManager* const manager_; scoped_ptr span_; @@ -261,6 +267,15 @@ void ChildDiscardableSharedMemoryManager::ReleaseSpan( MemoryUsageChanged(heap_.GetSize(), heap_.GetSizeOfFreeLists()); } +base::trace_event::MemoryAllocatorDump* +ChildDiscardableSharedMemoryManager::CreateMemoryAllocatorDump( + DiscardableSharedMemoryHeap::Span* span, + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const { + base::AutoLock lock(lock_); + return heap_.CreateMemoryAllocatorDump(span, name, pmd); +} + scoped_ptr ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( size_t size, diff --git a/content/child/child_discardable_shared_memory_manager.h b/content/child/child_discardable_shared_memory_manager.h index 6986955f094e68..4eb327d41c1d1d 100644 --- a/content/child/child_discardable_shared_memory_manager.h +++ b/content/child/child_discardable_shared_memory_manager.h @@ -40,6 +40,11 @@ class CONTENT_EXPORT ChildDiscardableSharedMemoryManager void UnlockSpan(DiscardableSharedMemoryHeap::Span* span); void ReleaseSpan(scoped_ptr span); + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + DiscardableSharedMemoryHeap::Span* span, + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const; + private: scoped_ptr AllocateLockedDiscardableSharedMemory(size_t size, diff --git a/content/common/discardable_shared_memory_heap.cc b/content/common/discardable_shared_memory_heap.cc index 958fa82554efec..8996979a730afc 100644 --- a/content/common/discardable_shared_memory_heap.cc +++ b/content/common/discardable_shared_memory_heap.cc @@ -60,6 +60,27 @@ bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const { return heap_->IsMemoryResident(shared_memory_.get()); } +bool DiscardableSharedMemoryHeap::ScopedMemorySegment::ContainsSpan( + Span* span) const { + return shared_memory_ == span->shared_memory(); +} + +base::trace_event::MemoryAllocatorDump* +DiscardableSharedMemoryHeap::ScopedMemorySegment::CreateMemoryAllocatorDump( + Span* span, + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const { + DCHECK_EQ(shared_memory_, span->shared_memory()); + base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + static_cast(span->length())); + + pmd->AddSuballocation(dump->guid(), + base::StringPrintf("discardable/segment_%d", id_)); + return dump; +} + void DiscardableSharedMemoryHeap::ScopedMemorySegment::OnMemoryDump( base::trace_event::ProcessMemoryDump* pmd) const { heap_->OnMemoryDump(shared_memory_.get(), size_, id_, pmd); @@ -398,4 +419,26 @@ DiscardableSharedMemoryHeap::GetSegmentGUIDForTracing(uint64 tracing_process_id, "discardable-x-process/%" PRIx64 "/%d", tracing_process_id, segment_id)); } +base::trace_event::MemoryAllocatorDump* +DiscardableSharedMemoryHeap::CreateMemoryAllocatorDump( + Span* span, + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const { + if (!span->shared_memory()) { + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, 0u); + return dump; + } + + ScopedVector::const_iterator it = + std::find_if(memory_segments_.begin(), memory_segments_.end(), + [span](const ScopedMemorySegment* segment) { + return segment->ContainsSpan(span); + }); + DCHECK(it != memory_segments_.end()); + return (*it)->CreateMemoryAllocatorDump(span, name, pmd); +} + } // namespace content diff --git a/content/common/discardable_shared_memory_heap.h b/content/common/discardable_shared_memory_heap.h index 7ded677c3cc756..5e482a6e7f4402 100644 --- a/content/common/discardable_shared_memory_heap.h +++ b/content/common/discardable_shared_memory_heap.h @@ -94,6 +94,13 @@ class CONTENT_EXPORT DiscardableSharedMemoryHeap { uint64 tracing_process_id, int32 segment_id); + // Returns a MemoryAllocatorDump for a given span on |pmd| with the size of + // the span. + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + Span* span, + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const; + private: class ScopedMemorySegment { public: @@ -107,6 +114,13 @@ class CONTENT_EXPORT DiscardableSharedMemoryHeap { bool IsUsed() const; bool IsResident() const; + bool ContainsSpan(Span* span) const; + + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + Span* span, + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const; + // Used for dumping memory statistics from the segment to chrome://tracing. void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) const; diff --git a/content/common/discardable_shared_memory_heap_unittest.cc b/content/common/discardable_shared_memory_heap_unittest.cc index c80d2c2e4bfd0f..20594ecf937368 100644 --- a/content/common/discardable_shared_memory_heap_unittest.cc +++ b/content/common/discardable_shared_memory_heap_unittest.cc @@ -302,5 +302,34 @@ TEST(DiscardableSharedMemoryHeapTest, DeletedCallback) { EXPECT_TRUE(deleted); } +TEST(DiscardableSharedMemoryHeapTest, CreateMemoryAllocatorDumpTest) { + size_t block_size = base::GetPageSize(); + DiscardableSharedMemoryHeap heap(block_size); + int next_discardable_shared_memory_id = 0; + + scoped_ptr memory( + new base::DiscardableSharedMemory); + ASSERT_TRUE(memory->CreateAndMap(block_size)); + scoped_ptr span = + heap.Grow(memory.Pass(), block_size, next_discardable_shared_memory_id++, + base::Bind(NullTask)); + + // Check if allocator dump is created when span exists. + scoped_ptr pmd( + new base::trace_event::ProcessMemoryDump(nullptr)); + EXPECT_TRUE(heap.CreateMemoryAllocatorDump(span.get(), "discardable/test1", + pmd.get())); + + // Unlock, Purge and release shared memory. + span->shared_memory()->Unlock(0, 0); + bool rv = span->shared_memory()->Purge(base::Time::Now()); + EXPECT_TRUE(rv); + heap.ReleasePurgedMemory(); + + // Check that allocator dump is created after memory is purged. + EXPECT_TRUE(heap.CreateMemoryAllocatorDump(span.get(), "discardable/test2", + pmd.get())); +} + } // namespace } // namespace content diff --git a/content/common/host_discardable_shared_memory_manager.cc b/content/common/host_discardable_shared_memory_manager.cc index 7590c1f9bb4c68..f436037471223d 100644 --- a/content/common/host_discardable_shared_memory_manager.cc +++ b/content/common/host_discardable_shared_memory_manager.cc @@ -64,6 +64,19 @@ class DiscardableMemoryImpl : public base::DiscardableMemory { return shared_memory_->memory(); } + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const override { + // The memory could have been purged, but we still create a dump with + // mapped_size. So, the size can be inaccurate. + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + shared_memory_->mapped_size()); + return dump; + } + private: scoped_ptr shared_memory_; const base::Closure deleted_callback_; diff --git a/gpu/skia_runner/in_process_graphics_system.cc b/gpu/skia_runner/in_process_graphics_system.cc index e5294b1777fb78..c9f02e0659db0d 100644 --- a/gpu/skia_runner/in_process_graphics_system.cc +++ b/gpu/skia_runner/in_process_graphics_system.cc @@ -10,6 +10,9 @@ #include "base/memory/discardable_memory.h" #include "base/memory/discardable_memory_allocator.h" #include "base/thread_task_runner_handle.h" +#include "base/trace_event/memory_allocator_dump.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/process_memory_dump.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_lib.h" #include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h" @@ -21,13 +24,30 @@ namespace { // TODO(hendrikw): Replace TestDiscardableMemoryAllocator and move to base? class NonDiscardableMemory : public base::DiscardableMemory { public: - explicit NonDiscardableMemory(size_t size) : data_(new uint8_t[size]) {} + explicit NonDiscardableMemory(size_t size) + : data_(new uint8_t[size]), size_(size) {} bool Lock() override { return false; } void Unlock() override {} void* data() const override { return data_.get(); } + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const override { + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, size_); + + // Memory is allocated from system allocator (malloc). + pmd->AddSuballocation(dump->guid(), + base::trace_event::MemoryDumpManager::GetInstance() + ->system_allocator_pool_name()); + return dump; + } + private: scoped_ptr data_; + size_t size_; }; class NonDiscardableMemoryAllocator : public base::DiscardableMemoryAllocator {