blob: dd9442313af98f2efee5a7e817a8b473a1ac4c0d [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2005, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// ---
32// Author: Sanjay Ghemawat <opensource@google.com>
33//
34// A data structure used by the caching malloc. It maps from page# to
35// a pointer that contains info about that page. We use two
36// representations: one for 32-bit addresses, and another for 64 bit
37// addresses. Both representations provide the same interface. The
38// first representation is implemented as a flat array, the seconds as
39// a three-level radix tree that strips away approximately 1/3rd of
40// the bits every time.
41//
42// The BITS parameter should be the number of bits required to hold
43// a page number. E.g., with 32 bit pointers and 4K pages (i.e.,
44// page offset fits in lower 12 bits), BITS == 20.
45
46#ifndef TCMALLOC_PAGEMAP_H_
47#define TCMALLOC_PAGEMAP_H_
48
49#include "config.h"
50
51#include <stddef.h> // for NULL, size_t
52#include <string.h> // for memset
53#if defined HAVE_STDINT_H
54#include <stdint.h>
55#elif defined HAVE_INTTYPES_H
56#include <inttypes.h>
57#else
58#include <sys/types.h>
59#endif
60#include "internal_logging.h" // for ASSERT
61
62// Single-level array
63template <int BITS>
64class TCMalloc_PageMap1 {
65 private:
66 static const int LENGTH = 1 << BITS;
67
68 void** array_;
69
70 public:
71 typedef uintptr_t Number;
72
73 explicit TCMalloc_PageMap1(void* (*allocator)(size_t)) {
74 array_ = reinterpret_cast<void**>((*allocator)(sizeof(void*) << BITS));
75 memset(array_, 0, sizeof(void*) << BITS);
76 }
77
78 // Ensure that the map contains initialized entries "x .. x+n-1".
79 // Returns true if successful, false if we could not allocate memory.
80 bool Ensure(Number x, size_t n) {
81 // Nothing to do since flat array was allocated at start. All
82 // that's left is to check for overflow (that is, we don't want to
83 // ensure a number y where array_[y] would be an out-of-bounds
84 // access).
85 return n <= LENGTH - x; // an overflow-free way to do "x + n <= LENGTH"
86 }
87
88 void PreallocateMoreMemory() {}
89
90 // Return the current value for KEY. Returns NULL if not yet set,
91 // or if k is out of range.
92 void* get(Number k) const {
93 if ((k >> BITS) > 0) {
94 return NULL;
95 }
96 return array_[k];
97 }
98
99 // REQUIRES "k" is in range "[0,2^BITS-1]".
100 // REQUIRES "k" has been ensured before.
101 //
102 // Sets the value 'v' for key 'k'.
103 void set(Number k, void* v) {
104 array_[k] = v;
105 }
106
107 // Return the first non-NULL pointer found in this map for
108 // a page number >= k. Returns NULL if no such number is found.
109 void* Next(Number k) const {
110 while (k < (1 << BITS)) {
111 if (array_[k] != NULL) return array_[k];
112 k++;
113 }
114 return NULL;
115 }
116};
117
118// Two-level radix tree
119template <int BITS>
120class TCMalloc_PageMap2 {
121 private:
122 // Put 32 entries in the root and (2^BITS)/32 entries in each leaf.
123 static const int ROOT_BITS = 5;
124 static const int ROOT_LENGTH = 1 << ROOT_BITS;
125
126 static const int LEAF_BITS = BITS - ROOT_BITS;
127 static const int LEAF_LENGTH = 1 << LEAF_BITS;
128
129 // Leaf node
130 struct Leaf {
131 void* values[LEAF_LENGTH];
132 };
133
134 Leaf* root_[ROOT_LENGTH]; // Pointers to 32 child nodes
135 void* (*allocator_)(size_t); // Memory allocator
136
137 public:
138 typedef uintptr_t Number;
139
140 explicit TCMalloc_PageMap2(void* (*allocator)(size_t)) {
141 allocator_ = allocator;
142 memset(root_, 0, sizeof(root_));
143 }
144
145 void* get(Number k) const {
146 const Number i1 = k >> LEAF_BITS;
147 const Number i2 = k & (LEAF_LENGTH-1);
148 if ((k >> BITS) > 0 || root_[i1] == NULL) {
149 return NULL;
150 }
151 return root_[i1]->values[i2];
152 }
153
154 void set(Number k, void* v) {
155 const Number i1 = k >> LEAF_BITS;
156 const Number i2 = k & (LEAF_LENGTH-1);
157 ASSERT(i1 < ROOT_LENGTH);
158 root_[i1]->values[i2] = v;
159 }
160
161 bool Ensure(Number start, size_t n) {
162 for (Number key = start; key <= start + n - 1; ) {
163 const Number i1 = key >> LEAF_BITS;
164
165 // Check for overflow
166 if (i1 >= ROOT_LENGTH)
167 return false;
168
169 // Make 2nd level node if necessary
170 if (root_[i1] == NULL) {
171 Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
172 if (leaf == NULL) return false;
173 memset(leaf, 0, sizeof(*leaf));
174 root_[i1] = leaf;
175 }
176
177 // Advance key past whatever is covered by this leaf node
178 key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
179 }
180 return true;
181 }
182
183 void PreallocateMoreMemory() {
184 // Allocate enough to keep track of all possible pages
185 Ensure(0, 1 << BITS);
186 }
187
188 void* Next(Number k) const {
189 while (k < (1 << BITS)) {
190 const Number i1 = k >> LEAF_BITS;
191 Leaf* leaf = root_[i1];
192 if (leaf != NULL) {
193 // Scan forward in leaf
194 for (Number i2 = k & (LEAF_LENGTH - 1); i2 < LEAF_LENGTH; i2++) {
195 if (leaf->values[i2] != NULL) {
196 return leaf->values[i2];
197 }
198 }
199 }
200 // Skip to next top-level entry
201 k = (i1 + 1) << LEAF_BITS;
202 }
203 return NULL;
204 }
205};
206
207// Three-level radix tree
208template <int BITS>
209class TCMalloc_PageMap3 {
210 private:
211 // How many bits should we consume at each interior level
212 static const int INTERIOR_BITS = (BITS + 2) / 3; // Round-up
213 static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS;
214
215 // How many bits should we consume at leaf level
216 static const int LEAF_BITS = BITS - 2*INTERIOR_BITS;
217 static const int LEAF_LENGTH = 1 << LEAF_BITS;
218
219 // Interior node
220 struct Node {
221 Node* ptrs[INTERIOR_LENGTH];
222 };
223
224 // Leaf node
225 struct Leaf {
226 void* values[LEAF_LENGTH];
227 };
228
229 Node* root_; // Root of radix tree
230 void* (*allocator_)(size_t); // Memory allocator
231
232 Node* NewNode() {
233 Node* result = reinterpret_cast<Node*>((*allocator_)(sizeof(Node)));
234 if (result != NULL) {
235 memset(result, 0, sizeof(*result));
236 }
237 return result;
238 }
239
240 public:
241 typedef uintptr_t Number;
242
243 explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) {
244 allocator_ = allocator;
245 root_ = NewNode();
246 }
247
248 void* get(Number k) const {
249 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
250 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
251 const Number i3 = k & (LEAF_LENGTH-1);
252 if ((k >> BITS) > 0 ||
253 root_->ptrs[i1] == NULL || root_->ptrs[i1]->ptrs[i2] == NULL) {
254 return NULL;
255 }
256 return reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3];
257 }
258
259 void set(Number k, void* v) {
260 ASSERT(k >> BITS == 0);
261 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
262 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
263 const Number i3 = k & (LEAF_LENGTH-1);
264 reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3] = v;
265 }
266
267 bool Ensure(Number start, size_t n) {
268 for (Number key = start; key <= start + n - 1; ) {
269 const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS);
270 const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH-1);
271
272 // Check for overflow
273 if (i1 >= INTERIOR_LENGTH || i2 >= INTERIOR_LENGTH)
274 return false;
275
276 // Make 2nd level node if necessary
277 if (root_->ptrs[i1] == NULL) {
278 Node* n = NewNode();
279 if (n == NULL) return false;
280 root_->ptrs[i1] = n;
281 }
282
283 // Make leaf node if necessary
284 if (root_->ptrs[i1]->ptrs[i2] == NULL) {
285 Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
286 if (leaf == NULL) return false;
287 memset(leaf, 0, sizeof(*leaf));
288 root_->ptrs[i1]->ptrs[i2] = reinterpret_cast<Node*>(leaf);
289 }
290
291 // Advance key past whatever is covered by this leaf node
292 key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
293 }
294 return true;
295 }
296
297 void PreallocateMoreMemory() {
298 }
299
300 void* Next(Number k) const {
301 while (k < (Number(1) << BITS)) {
302 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
303 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
304 if (root_->ptrs[i1] == NULL) {
305 // Advance to next top-level entry
306 k = (i1 + 1) << (LEAF_BITS + INTERIOR_BITS);
307 } else {
308 Leaf* leaf = reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2]);
309 if (leaf != NULL) {
310 for (Number i3 = (k & (LEAF_LENGTH-1)); i3 < LEAF_LENGTH; i3++) {
311 if (leaf->values[i3] != NULL) {
312 return leaf->values[i3];
313 }
314 }
315 }
316 // Advance to next interior entry
317 k = ((k >> LEAF_BITS) + 1) << LEAF_BITS;
318 }
319 }
320 return NULL;
321 }
322};
323
324#endif // TCMALLOC_PAGEMAP_H_