blob: dfa336c5f5cb6287cf1f35561277fc0994e6f55e [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.
Brian Silverman20350ac2021-11-17 18:19:55 -08004//
Austin Schuh745610d2015-09-06 18:19:50 -07005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008//
Austin Schuh745610d2015-09-06 18:19:50 -07009// * 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.
Brian Silverman20350ac2021-11-17 18:19:55 -080018//
Austin Schuh745610d2015-09-06 18:19:50 -070019// 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.
Brian Silverman20350ac2021-11-17 18:19:55 -080092 ATTRIBUTE_ALWAYS_INLINE
Austin Schuh745610d2015-09-06 18:19:50 -070093 void* get(Number k) const {
94 if ((k >> BITS) > 0) {
95 return NULL;
96 }
97 return array_[k];
98 }
99
100 // REQUIRES "k" is in range "[0,2^BITS-1]".
101 // REQUIRES "k" has been ensured before.
102 //
103 // Sets the value 'v' for key 'k'.
104 void set(Number k, void* v) {
105 array_[k] = v;
106 }
107
108 // Return the first non-NULL pointer found in this map for
109 // a page number >= k. Returns NULL if no such number is found.
110 void* Next(Number k) const {
111 while (k < (1 << BITS)) {
112 if (array_[k] != NULL) return array_[k];
113 k++;
114 }
115 return NULL;
116 }
117};
118
119// Two-level radix tree
120template <int BITS>
121class TCMalloc_PageMap2 {
122 private:
Brian Silverman20350ac2021-11-17 18:19:55 -0800123 static const int LEAF_BITS = (BITS + 1) / 2;
Austin Schuh745610d2015-09-06 18:19:50 -0700124 static const int LEAF_LENGTH = 1 << LEAF_BITS;
125
Brian Silverman20350ac2021-11-17 18:19:55 -0800126 static const int ROOT_BITS = BITS - LEAF_BITS;
127 static const int ROOT_LENGTH = 1 << ROOT_BITS;
128
Austin Schuh745610d2015-09-06 18:19:50 -0700129 // Leaf node
130 struct Leaf {
131 void* values[LEAF_LENGTH];
132 };
133
Brian Silverman20350ac2021-11-17 18:19:55 -0800134 Leaf* root_[ROOT_LENGTH]; // Pointers to child nodes
Austin Schuh745610d2015-09-06 18:19:50 -0700135 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
Brian Silverman20350ac2021-11-17 18:19:55 -0800145 ATTRIBUTE_ALWAYS_INLINE
Austin Schuh745610d2015-09-06 18:19:50 -0700146 void* get(Number k) const {
147 const Number i1 = k >> LEAF_BITS;
148 const Number i2 = k & (LEAF_LENGTH-1);
149 if ((k >> BITS) > 0 || root_[i1] == NULL) {
150 return NULL;
151 }
152 return root_[i1]->values[i2];
153 }
154
155 void set(Number k, void* v) {
156 const Number i1 = k >> LEAF_BITS;
157 const Number i2 = k & (LEAF_LENGTH-1);
158 ASSERT(i1 < ROOT_LENGTH);
159 root_[i1]->values[i2] = v;
160 }
161
162 bool Ensure(Number start, size_t n) {
163 for (Number key = start; key <= start + n - 1; ) {
164 const Number i1 = key >> LEAF_BITS;
165
166 // Check for overflow
167 if (i1 >= ROOT_LENGTH)
168 return false;
169
170 // Make 2nd level node if necessary
171 if (root_[i1] == NULL) {
172 Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
173 if (leaf == NULL) return false;
174 memset(leaf, 0, sizeof(*leaf));
175 root_[i1] = leaf;
176 }
177
178 // Advance key past whatever is covered by this leaf node
179 key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
180 }
181 return true;
182 }
183
184 void PreallocateMoreMemory() {
185 // Allocate enough to keep track of all possible pages
Brian Silverman20350ac2021-11-17 18:19:55 -0800186 if (BITS < 20) {
187 Ensure(0, Number(1) << BITS);
188 }
Austin Schuh745610d2015-09-06 18:19:50 -0700189 }
190
191 void* Next(Number k) const {
Brian Silverman20350ac2021-11-17 18:19:55 -0800192 while (k < (Number(1) << BITS)) {
Austin Schuh745610d2015-09-06 18:19:50 -0700193 const Number i1 = k >> LEAF_BITS;
194 Leaf* leaf = root_[i1];
195 if (leaf != NULL) {
196 // Scan forward in leaf
197 for (Number i2 = k & (LEAF_LENGTH - 1); i2 < LEAF_LENGTH; i2++) {
198 if (leaf->values[i2] != NULL) {
199 return leaf->values[i2];
200 }
201 }
202 }
203 // Skip to next top-level entry
204 k = (i1 + 1) << LEAF_BITS;
205 }
206 return NULL;
207 }
208};
209
210// Three-level radix tree
211template <int BITS>
212class TCMalloc_PageMap3 {
213 private:
214 // How many bits should we consume at each interior level
215 static const int INTERIOR_BITS = (BITS + 2) / 3; // Round-up
216 static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS;
217
218 // How many bits should we consume at leaf level
219 static const int LEAF_BITS = BITS - 2*INTERIOR_BITS;
220 static const int LEAF_LENGTH = 1 << LEAF_BITS;
221
222 // Interior node
223 struct Node {
224 Node* ptrs[INTERIOR_LENGTH];
225 };
226
227 // Leaf node
228 struct Leaf {
229 void* values[LEAF_LENGTH];
230 };
231
Brian Silverman20350ac2021-11-17 18:19:55 -0800232 Node root_; // Root of radix tree
Austin Schuh745610d2015-09-06 18:19:50 -0700233 void* (*allocator_)(size_t); // Memory allocator
234
235 Node* NewNode() {
236 Node* result = reinterpret_cast<Node*>((*allocator_)(sizeof(Node)));
237 if (result != NULL) {
238 memset(result, 0, sizeof(*result));
239 }
240 return result;
241 }
242
243 public:
244 typedef uintptr_t Number;
245
246 explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) {
247 allocator_ = allocator;
Brian Silverman20350ac2021-11-17 18:19:55 -0800248 memset(&root_, 0, sizeof(root_));
Austin Schuh745610d2015-09-06 18:19:50 -0700249 }
250
Brian Silverman20350ac2021-11-17 18:19:55 -0800251 ATTRIBUTE_ALWAYS_INLINE
Austin Schuh745610d2015-09-06 18:19:50 -0700252 void* get(Number k) const {
253 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
254 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
255 const Number i3 = k & (LEAF_LENGTH-1);
256 if ((k >> BITS) > 0 ||
Brian Silverman20350ac2021-11-17 18:19:55 -0800257 root_.ptrs[i1] == NULL || root_.ptrs[i1]->ptrs[i2] == NULL) {
Austin Schuh745610d2015-09-06 18:19:50 -0700258 return NULL;
259 }
Brian Silverman20350ac2021-11-17 18:19:55 -0800260 return reinterpret_cast<Leaf*>(root_.ptrs[i1]->ptrs[i2])->values[i3];
Austin Schuh745610d2015-09-06 18:19:50 -0700261 }
262
263 void set(Number k, void* v) {
264 ASSERT(k >> BITS == 0);
265 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
266 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
267 const Number i3 = k & (LEAF_LENGTH-1);
Brian Silverman20350ac2021-11-17 18:19:55 -0800268 reinterpret_cast<Leaf*>(root_.ptrs[i1]->ptrs[i2])->values[i3] = v;
Austin Schuh745610d2015-09-06 18:19:50 -0700269 }
270
271 bool Ensure(Number start, size_t n) {
272 for (Number key = start; key <= start + n - 1; ) {
273 const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS);
274 const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH-1);
275
276 // Check for overflow
277 if (i1 >= INTERIOR_LENGTH || i2 >= INTERIOR_LENGTH)
278 return false;
279
280 // Make 2nd level node if necessary
Brian Silverman20350ac2021-11-17 18:19:55 -0800281 if (root_.ptrs[i1] == NULL) {
Austin Schuh745610d2015-09-06 18:19:50 -0700282 Node* n = NewNode();
283 if (n == NULL) return false;
Brian Silverman20350ac2021-11-17 18:19:55 -0800284 root_.ptrs[i1] = n;
Austin Schuh745610d2015-09-06 18:19:50 -0700285 }
286
287 // Make leaf node if necessary
Brian Silverman20350ac2021-11-17 18:19:55 -0800288 if (root_.ptrs[i1]->ptrs[i2] == NULL) {
Austin Schuh745610d2015-09-06 18:19:50 -0700289 Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
290 if (leaf == NULL) return false;
291 memset(leaf, 0, sizeof(*leaf));
Brian Silverman20350ac2021-11-17 18:19:55 -0800292 root_.ptrs[i1]->ptrs[i2] = reinterpret_cast<Node*>(leaf);
Austin Schuh745610d2015-09-06 18:19:50 -0700293 }
294
295 // Advance key past whatever is covered by this leaf node
296 key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
297 }
298 return true;
299 }
300
301 void PreallocateMoreMemory() {
302 }
303
304 void* Next(Number k) const {
305 while (k < (Number(1) << BITS)) {
306 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
307 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
Brian Silverman20350ac2021-11-17 18:19:55 -0800308 if (root_.ptrs[i1] == NULL) {
Austin Schuh745610d2015-09-06 18:19:50 -0700309 // Advance to next top-level entry
310 k = (i1 + 1) << (LEAF_BITS + INTERIOR_BITS);
311 } else {
Brian Silverman20350ac2021-11-17 18:19:55 -0800312 Leaf* leaf = reinterpret_cast<Leaf*>(root_.ptrs[i1]->ptrs[i2]);
Austin Schuh745610d2015-09-06 18:19:50 -0700313 if (leaf != NULL) {
314 for (Number i3 = (k & (LEAF_LENGTH-1)); i3 < LEAF_LENGTH; i3++) {
315 if (leaf->values[i3] != NULL) {
316 return leaf->values[i3];
317 }
318 }
319 }
320 // Advance to next interior entry
321 k = ((k >> LEAF_BITS) + 1) << LEAF_BITS;
322 }
323 }
324 return NULL;
325 }
326};
327
328#endif // TCMALLOC_PAGEMAP_H_