123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
- // Copyright 2009 Google Inc. All Rights Reserved.
- // Author: fikes@google.com (Andrew Fikes)
- //
- // Use of this source code is governed by a BSD-style license that can
- // be found in the LICENSE file.
- #include "config_for_unittests.h"
- #include "page_heap.h"
- #include "system-alloc.h"
- #include <stdio.h>
- #include "base/logging.h"
- #include "common.h"
- DECLARE_int64(tcmalloc_heap_limit_mb);
- namespace {
- // The system will only release memory if the block size is equal or hight than
- // system page size.
- static bool HaveSystemRelease =
- TCMalloc_SystemRelease(
- TCMalloc_SystemAlloc(getpagesize(), NULL, 0), getpagesize());
- static void CheckStats(const tcmalloc::PageHeap* ph,
- uint64_t system_pages,
- uint64_t free_pages,
- uint64_t unmapped_pages) {
- tcmalloc::PageHeap::Stats stats = ph->stats();
- if (!HaveSystemRelease) {
- free_pages += unmapped_pages;
- unmapped_pages = 0;
- }
- EXPECT_EQ(system_pages, stats.system_bytes >> kPageShift);
- EXPECT_EQ(free_pages, stats.free_bytes >> kPageShift);
- EXPECT_EQ(unmapped_pages, stats.unmapped_bytes >> kPageShift);
- }
- static void TestPageHeap_Stats() {
- tcmalloc::PageHeap* ph = new tcmalloc::PageHeap();
- // Empty page heap
- CheckStats(ph, 0, 0, 0);
- // Allocate a span 's1'
- tcmalloc::Span* s1 = ph->New(256);
- CheckStats(ph, 256, 0, 0);
- // Split span 's1' into 's1', 's2'. Delete 's2'
- tcmalloc::Span* s2 = ph->Split(s1, 128);
- ph->Delete(s2);
- CheckStats(ph, 256, 128, 0);
- // Unmap deleted span 's2'
- ph->ReleaseAtLeastNPages(1);
- CheckStats(ph, 256, 0, 128);
- // Delete span 's1'
- ph->Delete(s1);
- CheckStats(ph, 256, 128, 128);
- delete ph;
- }
- static void TestPageHeap_Limit() {
- tcmalloc::PageHeap* ph = new tcmalloc::PageHeap();
- CHECK_EQ(kMaxPages, 1 << (20 - kPageShift));
- // We do not know much is taken from the system for other purposes,
- // so we detect the proper limit:
- {
- FLAGS_tcmalloc_heap_limit_mb = 1;
- tcmalloc::Span* s = NULL;
- while((s = ph->New(kMaxPages)) == NULL) {
- FLAGS_tcmalloc_heap_limit_mb++;
- }
- FLAGS_tcmalloc_heap_limit_mb += 9;
- ph->Delete(s);
- // We are [10, 11) mb from the limit now.
- }
- // Test AllocLarge and GrowHeap first:
- {
- tcmalloc::Span * spans[10];
- for (int i=0; i<10; ++i) {
- spans[i] = ph->New(kMaxPages);
- EXPECT_NE(spans[i], NULL);
- }
- EXPECT_EQ(ph->New(kMaxPages), NULL);
- for (int i=0; i<10; i += 2) {
- ph->Delete(spans[i]);
- }
- tcmalloc::Span *defragmented = ph->New(5 * kMaxPages);
- if (HaveSystemRelease) {
- // EnsureLimit should release deleted normal spans
- EXPECT_NE(defragmented, NULL);
- EXPECT_TRUE(ph->CheckExpensive());
- ph->Delete(defragmented);
- }
- else
- {
- EXPECT_EQ(defragmented, NULL);
- EXPECT_TRUE(ph->CheckExpensive());
- }
- for (int i=1; i<10; i += 2) {
- ph->Delete(spans[i]);
- }
- }
- // Once again, testing small lists this time (twice smaller spans):
- {
- tcmalloc::Span * spans[20];
- for (int i=0; i<20; ++i) {
- spans[i] = ph->New(kMaxPages >> 1);
- EXPECT_NE(spans[i], NULL);
- }
- // one more half size allocation may be possible:
- tcmalloc::Span * lastHalf = ph->New(kMaxPages >> 1);
- EXPECT_EQ(ph->New(kMaxPages >> 1), NULL);
- for (int i=0; i<20; i += 2) {
- ph->Delete(spans[i]);
- }
- for(Length len = kMaxPages >> 2; len < 5 * kMaxPages; len = len << 1)
- {
- if(len <= kMaxPages >> 1 || HaveSystemRelease) {
- tcmalloc::Span *s = ph->New(len);
- EXPECT_NE(s, NULL);
- ph->Delete(s);
- }
- }
- EXPECT_TRUE(ph->CheckExpensive());
- for (int i=1; i<20; i += 2) {
- ph->Delete(spans[i]);
- }
- if (lastHalf != NULL) {
- ph->Delete(lastHalf);
- }
- }
- delete ph;
- }
- } // namespace
- int main(int argc, char **argv) {
- TestPageHeap_Stats();
- TestPageHeap_Limit();
- printf("PASS\n");
- // on windows as part of library destructors we call getenv which
- // calls malloc which fails due to our exhausted heap limit. It then
- // causes fancy stack overflow because log message we're printing
- // for failed allocation somehow cause malloc calls too
- //
- // To keep us out of trouble we just drop malloc limit
- FLAGS_tcmalloc_heap_limit_mb = 0;
- return 0;
- }
|