diff --git a/src/page_heap.cc b/src/page_heap.cc index 85849cd..44ad654 100644 --- a/src/page_heap.cc +++ b/src/page_heap.cc @@ -241,22 +241,12 @@ void PageHeap::CommitSpan(Span* span) { stats_.total_commit_bytes += (span->length << kPageShift); } -bool PageHeap::TryDecommitWithoutLock(Span* span) { +bool PageHeap::DecommitSpan(Span* span) { ++stats_.decommit_count; - ASSERT(span->location == Span::ON_NORMAL_FREELIST); - span->location = Span::IN_USE; - Static::pageheap_lock()->Unlock(); bool rv = TCMalloc_SystemRelease(reinterpret_cast(span->start << kPageShift), static_cast(span->length << kPageShift)); - Static::pageheap_lock()->Lock(); - - // We're not really on any free list at this point, but lets - // indicate if we're returned or not. - span->location = Span::ON_NORMAL_FREELIST; - if (rv) { - span->location = Span::ON_RETURNED_FREELIST; stats_.committed_bytes -= span->length << kPageShift; stats_.total_decommit_bytes += (span->length << kPageShift); } @@ -330,19 +320,15 @@ Span* PageHeap::CheckAndHandlePreMerge(Span* span, Span* other) { if (other == NULL) { return other; } - - // If we're in aggressive decommit mode and span is decommitted, - // then we try to decommit adjacent span. We also remove from it's - // free list as part of that. + // if we're in aggressive decommit mode and span is decommitted, + // then we try to decommit adjacent span. if (aggressive_decommit_ && other->location == Span::ON_NORMAL_FREELIST && span->location == Span::ON_RETURNED_FREELIST) { - if (ReleaseSpan(other) != 0) { - return other; + bool worked = DecommitSpan(other); + if (!worked) { + return NULL; } - return NULL; - } - - if (other->location != span->location) { + } else if (other->location != span->location) { return NULL; } @@ -374,7 +360,7 @@ void PageHeap::MergeIntoFreeList(Span* span) { const Length n = span->length; if (aggressive_decommit_ && span->location == Span::ON_NORMAL_FREELIST) { - if (TryDecommitWithoutLock(span)) { + if (DecommitSpan(span)) { span->location = Span::ON_RETURNED_FREELIST; } } @@ -481,35 +467,18 @@ void PageHeap::IncrementalScavenge(Length n) { } } -Length PageHeap::ReleaseSpan(Span* span) { - // We're dropping very important and otherwise contended - // pageheap_lock around call to potentially very slow syscall to - // release pages. Those syscalls can be slow even with "advanced" - // things such as MADV_FREE and its better equivalents, because they - // have to walk actual page tables, and we sometimes deal with large - // spans, which sometimes takes lots of time to walk. Plus Linux - // grabs per-address space mmap_sem lock which could be extremely - // contended at times. So it is best if we avoid holding one - // contended lock while waiting for another. - // - // Note, we set span location to in-use, because our span could be found via - // pagemap in e.g. MergeIntoFreeList while we're not holding the lock. By - // marking it in-use we prevent this possibility. So span is removed from free - // list and marked "unmergable" and that guarantees safety during unlock-ful - // release. - ASSERT(span->location == Span::ON_NORMAL_FREELIST); - RemoveFromFreeList(span); +Length PageHeap::ReleaseSpan(Span* s) { + ASSERT(s->location == Span::ON_NORMAL_FREELIST); - Length n = span->length; - if (TryDecommitWithoutLock(span)) { - span->location = Span::ON_RETURNED_FREELIST; - } else { - n = 0; // Mark that we failed to return. - span->location = Span::ON_NORMAL_FREELIST; + if (DecommitSpan(s)) { + RemoveFromFreeList(s); + const Length n = s->length; + s->location = Span::ON_RETURNED_FREELIST; + MergeIntoFreeList(s); // Coalesces if possible. + return n; } - MergeIntoFreeList(span); // Coalesces if possible. - return n; + return 0; } Length PageHeap::ReleaseAtLeastNPages(Length num_pages) { diff --git a/src/page_heap.h b/src/page_heap.h index b234a7b..bf50394 100644 --- a/src/page_heap.h +++ b/src/page_heap.h @@ -314,7 +314,7 @@ class PERFTOOLS_DLL_DECL PageHeap { void CommitSpan(Span* span); // Decommit the span. - bool TryDecommitWithoutLock(Span* span); + bool DecommitSpan(Span* span); // Prepends span to appropriate free list, and adjusts stats. void PrependToFreeList(Span* span); @@ -326,12 +326,12 @@ class PERFTOOLS_DLL_DECL PageHeap { // IncrementalScavenge(n) is called whenever n pages are freed. void IncrementalScavenge(Length n); - // Attempts to decommit 'span' and move it to the returned freelist. + // Attempts to decommit 's' and move it to the returned freelist. // // Returns the length of the Span or zero if release failed. // - // REQUIRES: 'span' must be on the NORMAL freelist. - Length ReleaseSpan(Span *span); + // REQUIRES: 's' must be on the NORMAL freelist. + Length ReleaseSpan(Span *s); // Checks if we are allowed to take more memory from the system. // If limit is reached and allowRelease is true, tries to release diff --git a/src/tests/page_heap_test.cc b/src/tests/page_heap_test.cc index b99a6ad..3caacc0 100644 --- a/src/tests/page_heap_test.cc +++ b/src/tests/page_heap_test.cc @@ -11,19 +11,15 @@ #include -#include "base/logging.h" -#include "base/spinlock.h" -#include "common.h" #include "page_heap.h" #include "system-alloc.h" -#include "static_vars.h" +#include "base/logging.h" +#include "common.h" DECLARE_int64(tcmalloc_heap_limit_mb); namespace { -using tcmalloc::Static; - // The system will only release memory if the block size is equal or hight than // system page size. static bool HaveSystemRelease = @@ -48,7 +44,6 @@ static void CheckStats(const tcmalloc::PageHeap* ph, static void TestPageHeap_Stats() { std::unique_ptr ph(new tcmalloc::PageHeap()); - SpinLockHolder h(Static::pageheap_lock()); // Empty page heap CheckStats(ph.get(), 0, 0, 0); @@ -84,8 +79,6 @@ static void AllocateAllPageTables() { // Make a separate PageHeap from the main test so the test can start without // any pages in the lists. std::unique_ptr ph(new tcmalloc::PageHeap()); - SpinLockHolder h(Static::pageheap_lock()); - tcmalloc::Span *spans[kNumberMaxPagesSpans * 2]; for (int i = 0; i < kNumberMaxPagesSpans; ++i) { spans[i] = ph->New(kMaxPages); @@ -107,7 +100,6 @@ static void TestPageHeap_Limit() { AllocateAllPageTables(); std::unique_ptr ph(new tcmalloc::PageHeap()); - SpinLockHolder h(Static::pageheap_lock()); CHECK_EQ(kMaxPages, 1 << (20 - kPageShift)); @@ -196,8 +188,6 @@ static void TestPageHeap_Limit() { } // namespace int main(int argc, char **argv) { - Static::InitStaticVars(); - TestPageHeap_Stats(); TestPageHeap_Limit(); printf("PASS\n");