summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authordmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-18 09:45:44 +0000
committerdmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-18 09:45:44 +0000
commit9e805771746a126e33537c1e0e419a5fa14463be (patch)
tree21b5ded846adbab5721962ff0909b1b41c3ee275 /third_party
parent97e60a6c5f7ec7b5f493ad3cf4e42d40ca2379e8 (diff)
downloadchromium_src-9e805771746a126e33537c1e0e419a5fa14463be.zip
chromium_src-9e805771746a126e33537c1e0e419a5fa14463be.tar.gz
chromium_src-9e805771746a126e33537c1e0e419a5fa14463be.tar.bz2
Reserve a dedicated arena for every construction of mmap_address_map in order to reduce memory usage for HEAP_PROFILE_MMAP.
Large memory usage is observed for heap profiling while profiling mmap(). This change fixes the bloat by reserving a dedicated arena for every construction of mmap_address_map. This change is planned to be upstreamed. If another approach is chosen in the upstream, this change will be replaced. BUG=123759 TEST=run all existing tests. Review URL: http://codereview.chromium.org/9963095 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132771 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
-rw-r--r--third_party/tcmalloc/chromium/src/heap-profile-table.cc57
-rw-r--r--third_party/tcmalloc/chromium/src/heap-profile-table.h8
-rw-r--r--third_party/tcmalloc/chromium/src/heap-profiler.cc47
3 files changed, 79 insertions, 33 deletions
diff --git a/third_party/tcmalloc/chromium/src/heap-profile-table.cc b/third_party/tcmalloc/chromium/src/heap-profile-table.cc
index 1ef1858..696f41e 100644
--- a/third_party/tcmalloc/chromium/src/heap-profile-table.cc
+++ b/third_party/tcmalloc/chromium/src/heap-profile-table.cc
@@ -123,7 +123,12 @@ static bool ByAllocatedSpace(HeapProfileTable::Stats* a,
//----------------------------------------------------------------------
HeapProfileTable::HeapProfileTable(Allocator alloc, DeAllocator dealloc)
- : alloc_(alloc), dealloc_(dealloc) {
+ : alloc_(alloc),
+ dealloc_(dealloc),
+ num_alloc_buckets_(0),
+ mmap_table_(NULL),
+ num_available_mmap_buckets_(0),
+ mmap_address_map_(NULL) {
// Initialize the overall profile stats.
memset(&total_, 0, sizeof(total_));
@@ -131,16 +136,10 @@ HeapProfileTable::HeapProfileTable(Allocator alloc, DeAllocator dealloc)
const int alloc_table_bytes = kHashTableSize * sizeof(*alloc_table_);
alloc_table_ = reinterpret_cast<Bucket**>(alloc_(alloc_table_bytes));
memset(alloc_table_, 0, alloc_table_bytes);
- num_alloc_buckets_ = 0;
-
- // Initialize the mmap table.
- mmap_table_ = NULL;
- num_available_mmap_buckets_ = 0;
// Make malloc and mmap allocation maps.
alloc_address_map_ =
new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_);
- mmap_address_map_ = NULL;
}
HeapProfileTable::~HeapProfileTable() {
@@ -355,7 +354,8 @@ HeapProfileTable::MakeSortedBucketList() const {
return list;
}
-void HeapProfileTable::RefreshMMapData() {
+void HeapProfileTable::RefreshMMapData(Allocator mmap_alloc,
+ DeAllocator mmap_dealloc) {
// Make the table
static const int mmap_table_bytes = kHashTableSize * sizeof(*mmap_table_);
if (mmap_table_ == NULL) {
@@ -365,8 +365,8 @@ void HeapProfileTable::RefreshMMapData() {
num_available_mmap_buckets_ = 0;
ClearMMapData();
- mmap_address_map_ =
- new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_);
+ mmap_address_map_ = new(alloc_(sizeof(AllocationMap)))
+ AllocationMap(mmap_alloc, mmap_dealloc);
MemoryRegionMap::LockHolder l;
for (MemoryRegionMap::RegionIterator r =
@@ -388,12 +388,12 @@ void HeapProfileTable::RefreshMMapData() {
}
void HeapProfileTable::ClearMMapData() {
- if (mmap_address_map_ != NULL) {
- mmap_address_map_->Iterate(ZeroBucketCountsIterator, this);
- mmap_address_map_->~AllocationMap();
- dealloc_(mmap_address_map_);
- mmap_address_map_ = NULL;
- }
+ if (mmap_address_map_ == NULL) return;
+
+ mmap_address_map_->Iterate(ZeroBucketCountsIterator, this);
+ mmap_address_map_->~AllocationMap();
+ dealloc_(mmap_address_map_);
+ mmap_address_map_ = NULL;
}
void HeapProfileTable::IterateOrderedAllocContexts(
@@ -505,22 +505,21 @@ bool HeapProfileTable::WriteProfile(const char* file_name,
AllocationMap* allocations) {
RAW_VLOG(1, "Dumping non-live heap profile to %s", file_name);
RawFD fd = RawOpenForWriting(file_name);
- if (fd != kIllegalRawFD) {
- RawWrite(fd, kProfileHeader, strlen(kProfileHeader));
- char buf[512];
- int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile",
- NULL);
- RawWrite(fd, buf, len);
- const DumpArgs args(fd, NULL);
- allocations->Iterate<const DumpArgs&>(DumpNonLiveIterator, args);
- RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader));
- DumpProcSelfMaps(fd);
- RawClose(fd);
- return true;
- } else {
+ if (fd == kIllegalRawFD) {
RAW_LOG(ERROR, "Failed dumping filtered heap profile to %s", file_name);
return false;
}
+ RawWrite(fd, kProfileHeader, strlen(kProfileHeader));
+ char buf[512];
+ int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile",
+ NULL);
+ RawWrite(fd, buf, len);
+ const DumpArgs args(fd, NULL);
+ allocations->Iterate<const DumpArgs&>(DumpNonLiveIterator, args);
+ RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader));
+ DumpProcSelfMaps(fd);
+ RawClose(fd);
+ return true;
}
void HeapProfileTable::CleanupOldProfiles(const char* prefix) {
diff --git a/third_party/tcmalloc/chromium/src/heap-profile-table.h b/third_party/tcmalloc/chromium/src/heap-profile-table.h
index 447943d..61493fc 100644
--- a/third_party/tcmalloc/chromium/src/heap-profile-table.h
+++ b/third_party/tcmalloc/chromium/src/heap-profile-table.h
@@ -190,7 +190,13 @@ class HeapProfileTable {
// Refresh the internal mmap information from MemoryRegionMap. Results of
// FillOrderedProfile and IterateOrderedAllocContexts will contain mmap'ed
// memory regions as at calling RefreshMMapData.
- void RefreshMMapData();
+ // 'mmap_alloc' is an allocator for an address map. A function which calls
+ // LowLevelAlloc::AllocWithArena is expected like the constractor.
+ // 'mmap_dealloc' is a corresponding deallocator to 'mmap_alloc'.
+ // They are introduced to avoid expected memory fragmentation and bloat in
+ // an arena. A dedicated arena for this function allows disposing whole the
+ // arena after ClearMMapData.
+ void RefreshMMapData(Allocator mmap_alloc, DeAllocator mmap_dealloc);
// Clear the internal mmap information. Results of FillOrderedProfile and
// IterateOrderedAllocContexts won't contain mmap'ed memory regions after
diff --git a/third_party/tcmalloc/chromium/src/heap-profiler.cc b/third_party/tcmalloc/chromium/src/heap-profiler.cc
index 85d1aad..73f31f7 100644
--- a/third_party/tcmalloc/chromium/src/heap-profiler.cc
+++ b/third_party/tcmalloc/chromium/src/heap-profiler.cc
@@ -143,7 +143,7 @@ static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED);
// Simple allocator for heap profiler's internal memory
//----------------------------------------------------------------------
-static LowLevelAlloc::Arena *heap_profiler_memory;
+static LowLevelAlloc::Arena* heap_profiler_memory;
static void* ProfilerMalloc(size_t bytes) {
return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory);
@@ -152,6 +152,36 @@ static void ProfilerFree(void* p) {
LowLevelAlloc::Free(p);
}
+//----------------------------------------------------------------------
+// Another allocator for heap profiler's internal mmap address map
+//
+// Large amount of memory is consumed if we use an arena 'heap_profiler_memory'
+// for the internal mmap address map. It looks like memory fragmentation
+// because of repeated allocation/deallocation in the arena.
+//
+// 'mmap_heap_profiler_memory' is a dedicated arena for the mmap address map.
+// This arena is reserved for every construction of the mmap address map, and
+// disposed after every use.
+//----------------------------------------------------------------------
+
+static LowLevelAlloc::Arena* mmap_heap_profiler_memory = NULL;
+
+static void* MMapProfilerMalloc(size_t bytes) {
+ return LowLevelAlloc::AllocWithArena(bytes, mmap_heap_profiler_memory);
+}
+static void MMapProfilerFree(void* p) {
+ LowLevelAlloc::Free(p);
+}
+
+// This function should be called from a locked scope.
+// It returns false if failed in deleting the arena.
+static bool DeleteMMapProfilerArenaIfExistsLocked() {
+ if (mmap_heap_profiler_memory == NULL) return true;
+ if (!LowLevelAlloc::DeleteArena(mmap_heap_profiler_memory)) return false;
+ mmap_heap_profiler_memory = NULL;
+ return true;
+}
+
// We use buffers of this size in DoGetHeapProfile.
// The size is 1 << 20 in the original google-perftools. Changed it to
// 5 << 20 since a larger buffer is requried for deeper profiling in Chromium.
@@ -200,7 +230,12 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) {
int bytes_written = 0;
if (is_on) {
if (FLAGS_mmap_profile) {
- heap_profile->RefreshMMapData();
+ if (!DeleteMMapProfilerArenaIfExistsLocked()) {
+ RAW_LOG(FATAL, "Memory leak in HeapProfiler:");
+ }
+ mmap_heap_profiler_memory =
+ LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena());
+ heap_profile->RefreshMMapData(MMapProfilerMalloc, MMapProfilerFree);
}
if (deep_profile) {
bytes_written = deep_profile->FillOrderedProfile(buf, buflen - 1);
@@ -209,6 +244,9 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) {
}
if (FLAGS_mmap_profile) {
heap_profile->ClearMMapData();
+ if (!DeleteMMapProfilerArenaIfExistsLocked()) {
+ RAW_LOG(FATAL, "Memory leak in HeapProfiler:");
+ }
}
}
buf[bytes_written] = '\0';
@@ -532,6 +570,9 @@ extern "C" void HeapProfilerStop() {
// free profile
heap_profile->~HeapProfileTable();
+ if (!DeleteMMapProfilerArenaIfExistsLocked()) {
+ RAW_LOG(FATAL, "Memory leak in HeapProfiler:");
+ }
ProfilerFree(heap_profile);
heap_profile = NULL;
@@ -553,7 +594,7 @@ extern "C" void HeapProfilerStop() {
is_on = false;
}
-extern "C" void HeapProfilerDump(const char *reason) {
+extern "C" void HeapProfilerDump(const char* reason) {
SpinLockHolder l(&heap_lock);
if (is_on && !dumping) {
DumpProfileLocked(reason);