source: webkit/trunk/JavaScriptCore/wtf/TCPageMap.h@ 57853

Last change on this file since 57853 was 41443, checked in by [email protected], 16 years ago

<rdar://problem/6354858> FastMallocZone's enumeration code reports fragmented administration space

Reviewed by Oliver Hunt.

The handling of MALLOC_ADMIN_REGION_RANGE_TYPE in FastMalloc's zone was incorrect. It was attempting
to record the memory containing and individual span as an administrative region, when all memory
allocated via MetaDataAlloc should in fact be recorded. This was causing memory regions allocated
via MetaDataAlloc to appear as "VM_ALLOCATE ?" in vmmap output. They are now correctly reported as
"MALLOC_OTHER" regions associated with the JavaScriptCore FastMalloc zone.

Memory is allocated via MetaDataAlloc from two locations: PageHeapAllocator, and TCMalloc_PageMap{2,3}.
These two cases are handled differently.

PageHeapAllocator is extended to keep a linked list of memory regions that it has allocated. The
first object in an allocated region contains the link to the previously allocated region. To record
the administrative regions of a PageHeapAllocator we can simply walk the linked list and record
each allocated region we encounter.

TCMalloc_PageMaps allocate memory via MetaDataAlloc to store each level of the radix tree. To record
the administrative regions of a TCMalloc_PageMap we walk the tree and record the storage used for nodes
at each position rather than the nodes themselves.

A small performance improvement is achieved by coalescing adjacent memory regions inside the PageMapMemoryUsageRecorder
so that fewer calls in to the range recorder are necessary. We further reduce the number of calls to the
range recorder by aggregating the in-use ranges of a given memory region into a local buffer before recording
them with a single call. A similar approach is also used by AdminRegionRecorder.

  • wtf/FastMalloc.cpp:

(WTF::PageHeapAllocator::Init):
(WTF::PageHeapAllocator::New):
(WTF::PageHeapAllocator::recordAdministrativeRegions):
(WTF::TCMallocStats::FreeObjectFinder::isFreeObject):
(WTF::TCMallocStats::PageMapMemoryUsageRecorder::~PageMapMemoryUsageRecorder):
(WTF::TCMallocStats::PageMapMemoryUsageRecorder::recordPendingRegions):
(WTF::TCMallocStats::PageMapMemoryUsageRecorder::visit):
(WTF::TCMallocStats::AdminRegionRecorder::AdminRegionRecorder):
(WTF::TCMallocStats::AdminRegionRecorder::recordRegion):
(WTF::TCMallocStats::AdminRegionRecorder::visit):
(WTF::TCMallocStats::AdminRegionRecorder::recordPendingRegions):
(WTF::TCMallocStats::AdminRegionRecorder::~AdminRegionRecorder):
(WTF::TCMallocStats::FastMallocZone::enumerate):
(WTF::TCMallocStats::FastMallocZone::FastMallocZone):
(WTF::TCMallocStats::FastMallocZone::init):

  • wtf/TCPageMap.h:

(TCMalloc_PageMap2::visitValues):
(TCMalloc_PageMap2::visitAllocations):
(TCMalloc_PageMap3::visitValues):
(TCMalloc_PageMap3::visitAllocations):

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