summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjamesr@chromium.org <jamesr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-06 18:33:31 +0000
committerjamesr@chromium.org <jamesr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-06 18:33:31 +0000
commit9c92338c5f8770c440799d24387c3733fd6d826b (patch)
tree271f123e2ae934a45dc6fef91db6d4abe327d2dd
parenta97063189b7596ec805dab89f0d2fa7222c63191 (diff)
downloadchromium_src-9c92338c5f8770c440799d24387c3733fd6d826b.zip
chromium_src-9c92338c5f8770c440799d24387c3733fd6d826b.tar.gz
chromium_src-9c92338c5f8770c440799d24387c3733fd6d826b.tar.bz2
Tracks the amount of committed vs uncommitted memory in tcmalloc's page heap's freelists
Keeps track of the number of reserved but not committed pages in the freelist and uses that to calculate a waste metric, which is the ratio of committed pages vs pages used by the application. This is exposed in the GetStats() call (which is used for about:tcmalloc) and through GetNumericalProperty() in MallocExtension. BUG=none TEST=open about:tcmalloc and monitor 'WASTE' columns while using the browser Review URL: http://codereview.chromium.org/251065 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28133 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--third_party/tcmalloc/page_heap.cc24
-rw-r--r--third_party/tcmalloc/page_heap.h9
-rw-r--r--third_party/tcmalloc/tcmalloc.cc31
3 files changed, 53 insertions, 11 deletions
diff --git a/third_party/tcmalloc/page_heap.cc b/third_party/tcmalloc/page_heap.cc
index b46e728..f92cfc4 100644
--- a/third_party/tcmalloc/page_heap.cc
+++ b/third_party/tcmalloc/page_heap.cc
@@ -51,6 +51,7 @@ PageHeap::PageHeap()
pagemap_cache_(0),
free_pages_(0),
system_bytes_(0),
+ committed_bytes_(0),
scavenge_counter_(0),
// Start scavenging at kMaxPages list
scavenge_index_(kMaxPages-1) {
@@ -153,11 +154,13 @@ Span* PageHeap::Split(Span* span, Length n) {
void PageHeap::CommitSpan(Span* span) {
TCMalloc_SystemCommit(reinterpret_cast<void*>(span->start << kPageShift),
static_cast<size_t>(span->length << kPageShift));
+ committed_bytes_ += span->length << kPageShift;
}
void PageHeap::DecommitSpan(Span* span) {
TCMalloc_SystemRelease(reinterpret_cast<void*>(span->start << kPageShift),
static_cast<size_t>(span->length << kPageShift));
+ committed_bytes_ -= span->length << kPageShift;
}
Span* PageHeap::Carve(Span* span, Length n) {
@@ -233,6 +236,14 @@ void PageHeap::Delete(Span* span) {
// Merge preceding span into this span
ASSERT(prev->start + prev->length == p);
const Length len = prev->length;
+ if (prev->location == Span::ON_RETURNED_FREELIST) {
+ // We're about to put the merge span into the returned freelist and call
+ // DecommitSpan() on it, which will mark the entire span including this
+ // one as released and decrease committed_bytes_ by the size of the
+ // merged span. To make the math work out we temporarily increase the
+ // committed_bytes_ amount.
+ committed_bytes_ += prev->length << kPageShift;
+ }
DLL_Remove(prev);
DeleteSpan(prev);
span->start -= len;
@@ -245,6 +256,10 @@ void PageHeap::Delete(Span* span) {
// Merge next span into this span
ASSERT(next->start == p+n);
const Length len = next->length;
+ if (next->location == Span::ON_RETURNED_FREELIST) {
+ // See the comment below 'if (prev->location ...' for explanation.
+ committed_bytes_ += next->length << kPageShift;
+ }
DLL_Remove(next);
DeleteSpan(next);
span->length += len;
@@ -299,8 +314,7 @@ void PageHeap::IncrementalScavenge(Length n) {
Span* s = slist->normal.prev;
ASSERT(s->location == Span::ON_NORMAL_FREELIST);
DLL_Remove(s);
- TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift),
- static_cast<size_t>(s->length << kPageShift));
+ DecommitSpan(s);
s->location = Span::ON_RETURNED_FREELIST;
DLL_Prepend(&slist->returned, s);
@@ -430,6 +444,7 @@ bool PageHeap::GrowHeap(Length n) {
uint64_t old_system_bytes = system_bytes_;
system_bytes_ += (ask << kPageShift);
+ committed_bytes_ += (ask << kPageShift);
const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
ASSERT(p > 0);
@@ -491,7 +506,7 @@ bool PageHeap::CheckList(Span* list, Length min_pages, Length max_pages,
return true;
}
-static void ReleaseFreeList(Span* list, Span* returned) {
+void PageHeap::ReleaseFreeList(Span* list, Span* returned) {
// Walk backwards through list so that when we push these
// spans on the "returned" list, we preserve the order.
while (!DLL_IsEmpty(list)) {
@@ -500,8 +515,7 @@ static void ReleaseFreeList(Span* list, Span* returned) {
DLL_Prepend(returned, s);
ASSERT(s->location == Span::ON_NORMAL_FREELIST);
s->location = Span::ON_RETURNED_FREELIST;
- TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift),
- static_cast<size_t>(s->length << kPageShift));
+ DecommitSpan(s);
}
}
diff --git a/third_party/tcmalloc/page_heap.h b/third_party/tcmalloc/page_heap.h
index aec933d..100cae4 100644
--- a/third_party/tcmalloc/page_heap.h
+++ b/third_party/tcmalloc/page_heap.h
@@ -121,6 +121,8 @@ class PageHeap {
// Return number of bytes allocated from system
inline uint64_t SystemBytes() const { return system_bytes_; }
+ inline uint64_t CommittedBytes() const { return committed_bytes_; }
+
// Return number of free bytes in heap
uint64_t FreeBytes() const {
return (static_cast<uint64_t>(free_pages_) << kPageShift);
@@ -188,6 +190,9 @@ class PageHeap {
// Bytes allocated from system
uint64_t system_bytes_;
+ // Bytes committed, always <= system_bytes_.
+ uint64_t committed_bytes_;
+
bool GrowHeap(Length n);
// REQUIRES: span->length >= n
@@ -220,6 +225,10 @@ class PageHeap {
// IncrementalScavenge(n) is called whenever n pages are freed.
void IncrementalScavenge(Length n);
+ // Releases all memory held in the given list's 'normal' freelist and adds
+ // it to the 'released' freelist.
+ void ReleaseFreeList(Span* list, Span* returned);
+
// Number of pages to deallocate before doing more scavenging
int64_t scavenge_counter_;
diff --git a/third_party/tcmalloc/tcmalloc.cc b/third_party/tcmalloc/tcmalloc.cc
index e3bbb81..97cc414 100644
--- a/third_party/tcmalloc/tcmalloc.cc
+++ b/third_party/tcmalloc/tcmalloc.cc
@@ -367,6 +367,7 @@ size_t InvalidGetAllocatedSize(void* ptr) {
// Extract interesting stats
struct TCMallocStats {
uint64_t system_bytes; // Bytes alloced from system
+ uint64_t committed_bytes; // Bytes alloced and committed from system
uint64_t thread_bytes; // Bytes in thread caches
uint64_t central_bytes; // Bytes in central cache
uint64_t transfer_bytes; // Bytes in central transfer cache
@@ -398,6 +399,7 @@ static void ExtractStats(TCMallocStats* r, uint64_t* class_count) {
{ //scope
SpinLockHolder h(Static::pageheap_lock());
r->system_bytes = Static::pageheap()->SystemBytes();
+ r->committed_bytes = Static::pageheap()->CommittedBytes();
r->metadata_bytes = tcmalloc::metadata_system_bytes();
r->pageheap_bytes = Static::pageheap()->FreeBytes();
}
@@ -411,6 +413,20 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
static const double MB = 1048576.0;
+ const uint64_t bytes_in_use = stats.system_bytes
+ - stats.pageheap_bytes
+ - stats.central_bytes
+ - stats.transfer_bytes
+ - stats.thread_bytes;
+
+ out->printf("WASTE: %7.1f MB committed but not used\n"
+ "WASTE: %7.1f MB bytes committed, %7.1f MB bytes in use\n"
+ "WASTE: committed/used ratio of %f\n",
+ (stats.committed_bytes - bytes_in_use) / MB,
+ stats.committed_bytes / MB,
+ bytes_in_use / MB,
+ stats.committed_bytes / static_cast<double>(bytes_in_use));
+
if (level >= 2) {
out->printf("------------------------------------------------\n");
uint64_t cumulative = 0;
@@ -435,14 +451,9 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
DumpSystemAllocatorStats(out);
}
- const uint64_t bytes_in_use = stats.system_bytes
- - stats.pageheap_bytes
- - stats.central_bytes
- - stats.transfer_bytes
- - stats.thread_bytes;
-
out->printf("------------------------------------------------\n"
"MALLOC: %12" PRIu64 " (%7.1f MB) Heap size\n"
+ "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes committed\n"
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes in use by application\n"
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in page heap\n"
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in central cache\n"
@@ -453,6 +464,7 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
"MALLOC: %12" PRIu64 " (%7.1f MB) Metadata allocated\n"
"------------------------------------------------\n",
stats.system_bytes, stats.system_bytes / MB,
+ stats.committed_bytes, stats.committed_bytes / MB,
bytes_in_use, bytes_in_use / MB,
stats.pageheap_bytes, stats.pageheap_bytes / MB,
stats.central_bytes, stats.central_bytes / MB,
@@ -571,6 +583,13 @@ class TCMallocImplementation : public MallocExtension {
return true;
}
+ if (strcmp(name, "generic.committed_bytes") == 0) {
+ TCMallocStats stats;
+ ExtractStats(&stats, NULL);
+ *value = Static::pageheap()->CommittedBytes();
+ return true;
+ }
+
if (strcmp(name, "tcmalloc.slack_bytes") == 0) {
// We assume that bytes in the page heap are not fragmented too
// badly, and are therefore available for allocation.