Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: third_party/tcmalloc/chromium/src/central_freelist.cc

Issue 9320005: [NOT TO COMMIT!] Replace third_party/tcmalloc/chromium with tcmalloc r136 (the latest). (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2008, Google Inc. 1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 13 matching lines...) Expand all
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 // --- 30 // ---
31 // Author: Sanjay Ghemawat <opensource@google.com> 31 // Author: Sanjay Ghemawat <opensource@google.com>
32 32
33 #include "config.h" 33 #include "config.h"
34 #include <algorithm>
34 #include "central_freelist.h" 35 #include "central_freelist.h"
35 #include "free_list.h" // for FL_Next, FL_Push, etc
36 #include "internal_logging.h" // for ASSERT, MESSAGE 36 #include "internal_logging.h" // for ASSERT, MESSAGE
37 #include "linked_list.h" // for SLL_Next, SLL_Push, etc
37 #include "page_heap.h" // for PageHeap 38 #include "page_heap.h" // for PageHeap
38 #include "static_vars.h" // for Static 39 #include "static_vars.h" // for Static
39 40
41 using std::min;
42 using std::max;
43
40 namespace tcmalloc { 44 namespace tcmalloc {
41 45
42 void CentralFreeList::Init(size_t cl) { 46 void CentralFreeList::Init(size_t cl) {
43 size_class_ = cl; 47 size_class_ = cl;
44 tcmalloc::DLL_Init(&empty_); 48 tcmalloc::DLL_Init(&empty_);
45 tcmalloc::DLL_Init(&nonempty_); 49 tcmalloc::DLL_Init(&nonempty_);
50 num_spans_ = 0;
46 counter_ = 0; 51 counter_ = 0;
47 52
53 max_cache_size_ = kMaxNumTransferEntries;
48 #ifdef TCMALLOC_SMALL_BUT_SLOW 54 #ifdef TCMALLOC_SMALL_BUT_SLOW
49 // Disable the transfer cache for the small footprint case. 55 // Disable the transfer cache for the small footprint case.
50 cache_size_ = 0; 56 cache_size_ = 0;
51 #else 57 #else
52 cache_size_ = 16; 58 cache_size_ = 16;
53 #endif 59 #endif
60 if (cl > 0) {
61 // Limit the maximum size of the cache based on the size class. If this
62 // is not done, large size class objects will consume a lot of memory if
63 // they just sit in the transfer cache.
64 int32_t bytes = Static::sizemap()->ByteSizeForClass(cl);
65 int32_t objs_to_move = Static::sizemap()->num_objects_to_move(cl);
66
67 ASSERT(objs_to_move > 0 && bytes > 0);
68 // Limit each size class cache to at most 1MB of objects or one entry,
69 // whichever is greater. Total transfer cache memory used across all
70 // size classes then can't be greater than approximately
71 // 1MB * kMaxNumTransferEntries.
72 // min and max are in parens to avoid macro-expansion on windows.
73 max_cache_size_ = (min)(max_cache_size_,
74 (max)(1, (1024 * 1024) / (bytes * objs_to_move)));
75 cache_size_ = (min)(cache_size_, max_cache_size_);
76 }
54 used_slots_ = 0; 77 used_slots_ = 0;
55 ASSERT(cache_size_ <= kNumTransferEntries); 78 ASSERT(cache_size_ <= max_cache_size_);
56 } 79 }
57 80
58 void CentralFreeList::ReleaseListToSpans(void* start) { 81 void CentralFreeList::ReleaseListToSpans(void* start) {
59 while (start) { 82 while (start) {
60 void *next = FL_Next(start); 83 void *next = SLL_Next(start);
61 ReleaseToSpans(start); 84 ReleaseToSpans(start);
62 start = next; 85 start = next;
63 } 86 }
64 } 87 }
65 88
66 // MapObjectToSpan should logically be part of ReleaseToSpans. But 89 // MapObjectToSpan should logically be part of ReleaseToSpans. But
67 // this triggers an optimization bug in gcc 4.5.0. Moving to a 90 // this triggers an optimization bug in gcc 4.5.0. Moving to a
68 // separate function, and making sure that function isn't inlined, 91 // separate function, and making sure that function isn't inlined,
69 // seems to fix the problem. It also should be fixed for gcc 4.5.1. 92 // seems to fix the problem. It also should be fixed for gcc 4.5.1.
70 static 93 static
(...skipping 15 matching lines...) Expand all
86 if (span->objects == NULL) { 109 if (span->objects == NULL) {
87 tcmalloc::DLL_Remove(span); 110 tcmalloc::DLL_Remove(span);
88 tcmalloc::DLL_Prepend(&nonempty_, span); 111 tcmalloc::DLL_Prepend(&nonempty_, span);
89 Event(span, 'N', 0); 112 Event(span, 'N', 0);
90 } 113 }
91 114
92 // The following check is expensive, so it is disabled by default 115 // The following check is expensive, so it is disabled by default
93 if (false) { 116 if (false) {
94 // Check that object does not occur in list 117 // Check that object does not occur in list
95 int got = 0; 118 int got = 0;
96 for (void* p = span->objects; p != NULL; p = FL_Next(p)){ 119 for (void* p = span->objects; p != NULL; p = *((void**) p)) {
97 ASSERT(p != object); 120 ASSERT(p != object);
98 got++; 121 got++;
99 } 122 }
100 ASSERT(got + span->refcount == 123 ASSERT(got + span->refcount ==
101 (span->length<<kPageShift) / 124 (span->length<<kPageShift) /
102 Static::sizemap()->ByteSizeForClass(span->sizeclass)); 125 Static::sizemap()->ByteSizeForClass(span->sizeclass));
103 } 126 }
104 127
105 counter_++; 128 counter_++;
106 span->refcount--; 129 span->refcount--;
107 if (span->refcount == 0) { 130 if (span->refcount == 0) {
108 Event(span, '#', 0); 131 Event(span, '#', 0);
109 counter_ -= ((span->length<<kPageShift) / 132 counter_ -= ((span->length<<kPageShift) /
110 Static::sizemap()->ByteSizeForClass(span->sizeclass)); 133 Static::sizemap()->ByteSizeForClass(span->sizeclass));
111 tcmalloc::DLL_Remove(span); 134 tcmalloc::DLL_Remove(span);
135 --num_spans_;
112 136
113 // Release central list lock while operating on pageheap 137 // Release central list lock while operating on pageheap
114 lock_.Unlock(); 138 lock_.Unlock();
115 { 139 {
116 SpinLockHolder h(Static::pageheap_lock()); 140 SpinLockHolder h(Static::pageheap_lock());
117 Static::pageheap()->Delete(span); 141 Static::pageheap()->Delete(span);
118 } 142 }
119 lock_.Lock(); 143 lock_.Lock();
120 } else { 144 } else {
121 FL_Push(&(span->objects), object); 145 *(reinterpret_cast<void**>(object)) = span->objects;
146 span->objects = object;
122 } 147 }
123 } 148 }
124 149
125 bool CentralFreeList::EvictRandomSizeClass( 150 bool CentralFreeList::EvictRandomSizeClass(
126 int locked_size_class, bool force) { 151 int locked_size_class, bool force) {
127 static int race_counter = 0; 152 static int race_counter = 0;
128 int t = race_counter++; // Updated without a lock, but who cares. 153 int t = race_counter++; // Updated without a lock, but who cares.
129 if (t >= kNumClasses) { 154 if (t >= kNumClasses) {
130 while (t >= kNumClasses) { 155 while (t >= kNumClasses) {
131 t -= kNumClasses; 156 t -= kNumClasses;
132 } 157 }
133 race_counter = t; 158 race_counter = t;
134 } 159 }
135 ASSERT(t >= 0); 160 ASSERT(t >= 0);
136 ASSERT(t < kNumClasses); 161 ASSERT(t < kNumClasses);
137 if (t == locked_size_class) return false; 162 if (t == locked_size_class) return false;
138 return Static::central_cache()[t].ShrinkCache(locked_size_class, force); 163 return Static::central_cache()[t].ShrinkCache(locked_size_class, force);
139 } 164 }
140 165
141 bool CentralFreeList::MakeCacheSpace() { 166 bool CentralFreeList::MakeCacheSpace() {
142 // Is there room in the cache? 167 // Is there room in the cache?
143 if (used_slots_ < cache_size_) return true; 168 if (used_slots_ < cache_size_) return true;
144 // Check if we can expand this cache? 169 // Check if we can expand this cache?
145 if (cache_size_ == kNumTransferEntries) return false; 170 if (cache_size_ == max_cache_size_) return false;
146 // Ok, we'll try to grab an entry from some other size class. 171 // Ok, we'll try to grab an entry from some other size class.
147 if (EvictRandomSizeClass(size_class_, false) || 172 if (EvictRandomSizeClass(size_class_, false) ||
148 EvictRandomSizeClass(size_class_, true)) { 173 EvictRandomSizeClass(size_class_, true)) {
149 // Succeeded in evicting, we're going to make our cache larger. 174 // Succeeded in evicting, we're going to make our cache larger.
150 // However, we may have dropped and re-acquired the lock in 175 // However, we may have dropped and re-acquired the lock in
151 // EvictRandomSizeClass (via ShrinkCache and the LockInverter), so the 176 // EvictRandomSizeClass (via ShrinkCache and the LockInverter), so the
152 // cache_size may have changed. Therefore, check and verify that it is 177 // cache_size may have changed. Therefore, check and verify that it is
153 // still OK to increase the cache_size. 178 // still OK to increase the cache_size.
154 if (cache_size_ < kNumTransferEntries) { 179 if (cache_size_ < max_cache_size_) {
155 cache_size_++; 180 cache_size_++;
156 return true; 181 return true;
157 } 182 }
158 } 183 }
159 return false; 184 return false;
160 } 185 }
161 186
162 187
163 namespace { 188 namespace {
164 class LockInverter { 189 class LockInverter {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 cache_size_--; 226 cache_size_--;
202 return true; 227 return true;
203 } 228 }
204 229
205 void CentralFreeList::InsertRange(void *start, void *end, int N) { 230 void CentralFreeList::InsertRange(void *start, void *end, int N) {
206 SpinLockHolder h(&lock_); 231 SpinLockHolder h(&lock_);
207 if (N == Static::sizemap()->num_objects_to_move(size_class_) && 232 if (N == Static::sizemap()->num_objects_to_move(size_class_) &&
208 MakeCacheSpace()) { 233 MakeCacheSpace()) {
209 int slot = used_slots_++; 234 int slot = used_slots_++;
210 ASSERT(slot >=0); 235 ASSERT(slot >=0);
211 ASSERT(slot < kNumTransferEntries); 236 ASSERT(slot < max_cache_size_);
212 TCEntry *entry = &tc_slots_[slot]; 237 TCEntry *entry = &tc_slots_[slot];
213 entry->head = start; 238 entry->head = start;
214 entry->tail = end; 239 entry->tail = end;
215 return; 240 return;
216 } 241 }
217 ReleaseListToSpans(start); 242 ReleaseListToSpans(start);
218 } 243 }
219 244
220 int CentralFreeList::RemoveRange(void **start, void **end, int N) { 245 int CentralFreeList::RemoveRange(void **start, void **end, int N) {
221 ASSERT(N > 0); 246 ASSERT(N > 0);
222 lock_.Lock(); 247 lock_.Lock();
223 if (N == Static::sizemap()->num_objects_to_move(size_class_) && 248 if (N == Static::sizemap()->num_objects_to_move(size_class_) &&
224 used_slots_ > 0) { 249 used_slots_ > 0) {
225 int slot = --used_slots_; 250 int slot = --used_slots_;
226 ASSERT(slot >= 0); 251 ASSERT(slot >= 0);
227 TCEntry *entry = &tc_slots_[slot]; 252 TCEntry *entry = &tc_slots_[slot];
228 *start = entry->head; 253 *start = entry->head;
229 *end = entry->tail; 254 *end = entry->tail;
230 lock_.Unlock(); 255 lock_.Unlock();
231 return N; 256 return N;
232 } 257 }
233 258
234 int result = 0; 259 int result = 0;
235 void* head = NULL; 260 void* head = NULL;
236 void* tail = NULL; 261 void* tail = NULL;
237 // TODO: Prefetch multiple TCEntries? 262 // TODO: Prefetch multiple TCEntries?
238 tail = FetchFromSpansSafe(); 263 tail = FetchFromSpansSafe();
239 if (tail != NULL) { 264 if (tail != NULL) {
240 FL_Push(&head, tail); 265 SLL_SetNext(tail, NULL);
266 head = tail;
241 result = 1; 267 result = 1;
242 while (result < N) { 268 while (result < N) {
243 void *t = FetchFromSpans(); 269 void *t = FetchFromSpans();
244 if (!t) break; 270 if (!t) break;
245 FL_Push(&head, t); 271 SLL_Push(&head, t);
246 result++; 272 result++;
247 } 273 }
248 } 274 }
249 lock_.Unlock(); 275 lock_.Unlock();
250 *start = head; 276 *start = head;
251 *end = tail; 277 *end = tail;
252 return result; 278 return result;
253 } 279 }
254 280
255 281
256 void* CentralFreeList::FetchFromSpansSafe() { 282 void* CentralFreeList::FetchFromSpansSafe() {
257 void *t = FetchFromSpans(); 283 void *t = FetchFromSpans();
258 if (!t) { 284 if (!t) {
259 Populate(); 285 Populate();
260 t = FetchFromSpans(); 286 t = FetchFromSpans();
261 } 287 }
262 return t; 288 return t;
263 } 289 }
264 290
265 void* CentralFreeList::FetchFromSpans() { 291 void* CentralFreeList::FetchFromSpans() {
266 if (tcmalloc::DLL_IsEmpty(&nonempty_)) return NULL; 292 if (tcmalloc::DLL_IsEmpty(&nonempty_)) return NULL;
267 Span* span = nonempty_.next; 293 Span* span = nonempty_.next;
268 294
269 ASSERT(span->objects != NULL); 295 ASSERT(span->objects != NULL);
270 span->refcount++; 296 span->refcount++;
271 void *result = FL_Pop(&(span->objects)); 297 void* result = span->objects;
298 span->objects = *(reinterpret_cast<void**>(result));
272 if (span->objects == NULL) { 299 if (span->objects == NULL) {
273 // Move to empty list 300 // Move to empty list
274 tcmalloc::DLL_Remove(span); 301 tcmalloc::DLL_Remove(span);
275 tcmalloc::DLL_Prepend(&empty_, span); 302 tcmalloc::DLL_Prepend(&empty_, span);
276 Event(span, 'E', 0); 303 Event(span, 'E', 0);
277 } 304 }
278 counter_--; 305 counter_--;
279 return result; 306 return result;
280 } 307 }
281 308
282 // Fetch memory from the system and add to the central cache freelist. 309 // Fetch memory from the system and add to the central cache freelist.
283 void CentralFreeList::Populate() { 310 void CentralFreeList::Populate() {
284 // Release central list lock while operating on pageheap 311 // Release central list lock while operating on pageheap
285 lock_.Unlock(); 312 lock_.Unlock();
286 const size_t npages = Static::sizemap()->class_to_pages(size_class_); 313 const size_t npages = Static::sizemap()->class_to_pages(size_class_);
287 314
288 Span* span; 315 Span* span;
289 { 316 {
290 SpinLockHolder h(Static::pageheap_lock()); 317 SpinLockHolder h(Static::pageheap_lock());
291 span = Static::pageheap()->New(npages); 318 span = Static::pageheap()->New(npages);
292 if (span) Static::pageheap()->RegisterSizeClass(span, size_class_); 319 if (span) Static::pageheap()->RegisterSizeClass(span, size_class_);
293 } 320 }
294 if (span == NULL) { 321 if (span == NULL) {
295 MESSAGE("tcmalloc: allocation failed", npages << kPageShift); 322 Log(kLog, __FILE__, __LINE__,
323 "tcmalloc: allocation failed", npages << kPageShift);
296 lock_.Lock(); 324 lock_.Lock();
297 return; 325 return;
298 } 326 }
299 ASSERT(span->length == npages); 327 ASSERT(span->length == npages);
300 // Cache sizeclass info eagerly. Locking is not necessary. 328 // Cache sizeclass info eagerly. Locking is not necessary.
301 // (Instead of being eager, we could just replace any stale info 329 // (Instead of being eager, we could just replace any stale info
302 // about this span, but that seems to be no better in practice.) 330 // about this span, but that seems to be no better in practice.)
303 for (int i = 0; i < npages; i++) { 331 for (int i = 0; i < npages; i++) {
304 Static::pageheap()->CacheSizeClass(span->start + i, size_class_); 332 Static::pageheap()->CacheSizeClass(span->start + i, size_class_);
305 } 333 }
306 334
307 // Split the block into pieces and add to the free-list 335 // Split the block into pieces and add to the free-list
308 // TODO: coloring of objects to avoid cache conflicts? 336 // TODO: coloring of objects to avoid cache conflicts?
309 void* list = NULL; 337 void** tail = &span->objects;
310 char* ptr = reinterpret_cast<char*>(span->start << kPageShift); 338 char* ptr = reinterpret_cast<char*>(span->start << kPageShift);
311 char* limit = ptr + (npages << kPageShift); 339 char* limit = ptr + (npages << kPageShift);
312 const size_t size = Static::sizemap()->ByteSizeForClass(size_class_); 340 const size_t size = Static::sizemap()->ByteSizeForClass(size_class_);
313 int num = 0; 341 int num = 0;
314 while (ptr + size <= limit) { 342 while (ptr + size <= limit) {
315 FL_Push(&list, ptr); 343 *tail = ptr;
344 tail = reinterpret_cast<void**>(ptr);
316 ptr += size; 345 ptr += size;
317 num++; 346 num++;
318 } 347 }
319 ASSERT(ptr <= limit); 348 ASSERT(ptr <= limit);
320 span->objects = list; 349 *tail = NULL;
321 span->refcount = 0; // No sub-object in use yet 350 span->refcount = 0; // No sub-object in use yet
322 351
323 // Add span to list of non-empty spans 352 // Add span to list of non-empty spans
324 lock_.Lock(); 353 lock_.Lock();
325 tcmalloc::DLL_Prepend(&nonempty_, span); 354 tcmalloc::DLL_Prepend(&nonempty_, span);
355 ++num_spans_;
326 counter_ += num; 356 counter_ += num;
327 } 357 }
328 358
329 int CentralFreeList::tc_length() { 359 int CentralFreeList::tc_length() {
330 SpinLockHolder h(&lock_); 360 SpinLockHolder h(&lock_);
331 return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_); 361 return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_);
332 } 362 }
333 363
364 size_t CentralFreeList::OverheadBytes() {
365 SpinLockHolder h(&lock_);
366 if (size_class_ == 0) { // 0 holds the 0-sized allocations
367 return 0;
368 }
369 const size_t pages_per_span = Static::sizemap()->class_to_pages(size_class_);
370 const size_t object_size = Static::sizemap()->class_to_size(size_class_);
371 ASSERT(object_size > 0);
372 const size_t overhead_per_span = (pages_per_span * kPageSize) % object_size;
373 return num_spans_ * overhead_per_span;
374 }
375
334 } // namespace tcmalloc 376 } // namespace tcmalloc
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/central_freelist.h ('k') | third_party/tcmalloc/chromium/src/common.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698