blob: e82a1da8ef9be3c6d2620a91fe9b3d4bb69cee07 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright 2009 Google Inc. All Rights Reserved.
3// Author: fikes@google.com (Andrew Fikes)
4//
5// Use of this source code is governed by a BSD-style license that can
6// be found in the LICENSE file.
7
8#include "config_for_unittests.h"
9#include "page_heap.h"
10#include "system-alloc.h"
11#include <stdio.h>
12#include "base/logging.h"
13#include "common.h"
14
15DECLARE_int64(tcmalloc_heap_limit_mb);
16
17namespace {
18
19// The system will only release memory if the block size is equal or hight than
20// system page size.
21static bool HaveSystemRelease =
22 TCMalloc_SystemRelease(
23 TCMalloc_SystemAlloc(getpagesize(), NULL, 0), getpagesize());
24
25static void CheckStats(const tcmalloc::PageHeap* ph,
26 uint64_t system_pages,
27 uint64_t free_pages,
28 uint64_t unmapped_pages) {
29 tcmalloc::PageHeap::Stats stats = ph->stats();
30
31 if (!HaveSystemRelease) {
32 free_pages += unmapped_pages;
33 unmapped_pages = 0;
34 }
35
36 EXPECT_EQ(system_pages, stats.system_bytes >> kPageShift);
37 EXPECT_EQ(free_pages, stats.free_bytes >> kPageShift);
38 EXPECT_EQ(unmapped_pages, stats.unmapped_bytes >> kPageShift);
39}
40
41static void TestPageHeap_Stats() {
42 tcmalloc::PageHeap* ph = new tcmalloc::PageHeap();
43
44 // Empty page heap
45 CheckStats(ph, 0, 0, 0);
46
47 // Allocate a span 's1'
48 tcmalloc::Span* s1 = ph->New(256);
49 CheckStats(ph, 256, 0, 0);
50
51 // Split span 's1' into 's1', 's2'. Delete 's2'
52 tcmalloc::Span* s2 = ph->Split(s1, 128);
53 ph->Delete(s2);
54 CheckStats(ph, 256, 128, 0);
55
56 // Unmap deleted span 's2'
57 ph->ReleaseAtLeastNPages(1);
58 CheckStats(ph, 256, 0, 128);
59
60 // Delete span 's1'
61 ph->Delete(s1);
62 CheckStats(ph, 256, 128, 128);
63
64 delete ph;
65}
66
67static void TestPageHeap_Limit() {
68 tcmalloc::PageHeap* ph = new tcmalloc::PageHeap();
69
70 CHECK_EQ(kMaxPages, 1 << (20 - kPageShift));
71
72 // We do not know much is taken from the system for other purposes,
73 // so we detect the proper limit:
74 {
75 FLAGS_tcmalloc_heap_limit_mb = 1;
76 tcmalloc::Span* s = NULL;
77 while((s = ph->New(kMaxPages)) == NULL) {
78 FLAGS_tcmalloc_heap_limit_mb++;
79 }
80 FLAGS_tcmalloc_heap_limit_mb += 9;
81 ph->Delete(s);
82 // We are [10, 11) mb from the limit now.
83 }
84
85 // Test AllocLarge and GrowHeap first:
86 {
87 tcmalloc::Span * spans[10];
88 for (int i=0; i<10; ++i) {
89 spans[i] = ph->New(kMaxPages);
90 EXPECT_NE(spans[i], NULL);
91 }
92 EXPECT_EQ(ph->New(kMaxPages), NULL);
93
94 for (int i=0; i<10; i += 2) {
95 ph->Delete(spans[i]);
96 }
97
98 tcmalloc::Span *defragmented = ph->New(5 * kMaxPages);
99
100 if (HaveSystemRelease) {
101 // EnsureLimit should release deleted normal spans
102 EXPECT_NE(defragmented, NULL);
103 EXPECT_TRUE(ph->CheckExpensive());
104 ph->Delete(defragmented);
105 }
106 else
107 {
108 EXPECT_EQ(defragmented, NULL);
109 EXPECT_TRUE(ph->CheckExpensive());
110 }
111
112 for (int i=1; i<10; i += 2) {
113 ph->Delete(spans[i]);
114 }
115 }
116
117 // Once again, testing small lists this time (twice smaller spans):
118 {
119 tcmalloc::Span * spans[20];
120 for (int i=0; i<20; ++i) {
121 spans[i] = ph->New(kMaxPages >> 1);
122 EXPECT_NE(spans[i], NULL);
123 }
124 // one more half size allocation may be possible:
125 tcmalloc::Span * lastHalf = ph->New(kMaxPages >> 1);
126 EXPECT_EQ(ph->New(kMaxPages >> 1), NULL);
127
128 for (int i=0; i<20; i += 2) {
129 ph->Delete(spans[i]);
130 }
131
132 for(Length len = kMaxPages >> 2; len < 5 * kMaxPages; len = len << 1)
133 {
134 if(len <= kMaxPages >> 1 || HaveSystemRelease) {
135 tcmalloc::Span *s = ph->New(len);
136 EXPECT_NE(s, NULL);
137 ph->Delete(s);
138 }
139 }
140
141 EXPECT_TRUE(ph->CheckExpensive());
142
143 for (int i=1; i<20; i += 2) {
144 ph->Delete(spans[i]);
145 }
146
147 if (lastHalf != NULL) {
148 ph->Delete(lastHalf);
149 }
150 }
151
152 delete ph;
153}
154
155} // namespace
156
157int main(int argc, char **argv) {
158 TestPageHeap_Stats();
159 TestPageHeap_Limit();
160 printf("PASS\n");
161 // on windows as part of library destructors we call getenv which
162 // calls malloc which fails due to our exhausted heap limit. It then
163 // causes fancy stack overflow because log message we're printing
164 // for failed allocation somehow cause malloc calls too
165 //
166 // To keep us out of trouble we just drop malloc limit
167 FLAGS_tcmalloc_heap_limit_mb = 0;
168 return 0;
169}