Skip to content

Commit

Permalink
Add support to create memory allocator dump in base::DiscardableMemory
Browse files Browse the repository at this point in the history
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}
  • Loading branch information
ssiddhartha authored and Commit bot committed Aug 25, 2015
1 parent 68c9284 commit 3e37155
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 1 deletion.
13 changes: 13 additions & 0 deletions base/memory/discardable_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -59,6 +64,14 @@ class BASE_EXPORT DiscardableMemory {
template<typename T> T* data_as() const {
return reinterpret_cast<T*>(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
Expand Down
6 changes: 6 additions & 0 deletions base/test/test_discardable_memory_allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t[]> data_;
};
Expand Down
18 changes: 18 additions & 0 deletions components/html_viewer/discardable_memory_allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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() {
Expand Down
15 changes: 15 additions & 0 deletions content/child/child_discardable_shared_memory_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ class DiscardableMemoryImpl : public base::DiscardableMemory {
return reinterpret_cast<void*>(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<DiscardableSharedMemoryHeap::Span> span_;
Expand Down Expand Up @@ -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<base::DiscardableSharedMemory>
ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
size_t size,
Expand Down
5 changes: 5 additions & 0 deletions content/child/child_discardable_shared_memory_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class CONTENT_EXPORT ChildDiscardableSharedMemoryManager
void UnlockSpan(DiscardableSharedMemoryHeap::Span* span);
void ReleaseSpan(scoped_ptr<DiscardableSharedMemoryHeap::Span> span);

base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
DiscardableSharedMemoryHeap::Span* span,
const char* name,
base::trace_event::ProcessMemoryDump* pmd) const;

private:
scoped_ptr<base::DiscardableSharedMemory>
AllocateLockedDiscardableSharedMemory(size_t size,
Expand Down
43 changes: 43 additions & 0 deletions content/common/discardable_shared_memory_heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t>(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);
Expand Down Expand Up @@ -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<ScopedMemorySegment>::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
14 changes: 14 additions & 0 deletions content/common/discardable_shared_memory_heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;

Expand Down
29 changes: 29 additions & 0 deletions content/common/discardable_shared_memory_heap_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<base::DiscardableSharedMemory> memory(
new base::DiscardableSharedMemory);
ASSERT_TRUE(memory->CreateAndMap(block_size));
scoped_ptr<DiscardableSharedMemoryHeap::Span> 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<base::trace_event::ProcessMemoryDump> 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
13 changes: 13 additions & 0 deletions content/common/host_discardable_shared_memory_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<base::DiscardableSharedMemory> shared_memory_;
const base::Closure deleted_callback_;
Expand Down
22 changes: 21 additions & 1 deletion gpu/skia_runner/in_process_graphics_system.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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<uint8_t[]> data_;
size_t size_;
};

class NonDiscardableMemoryAllocator : public base::DiscardableMemoryAllocator {
Expand Down

0 comments on commit 3e37155

Please sign in to comment.