OLD | NEW |
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 14 matching lines...) Expand all Loading... |
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 "central_freelist.h" | 34 #include "central_freelist.h" |
35 | 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 | |
38 #include "page_heap.h" // for PageHeap | 37 #include "page_heap.h" // for PageHeap |
39 #include "static_vars.h" // for Static | 38 #include "static_vars.h" // for Static |
40 | 39 |
41 namespace tcmalloc { | 40 namespace tcmalloc { |
42 | 41 |
43 void CentralFreeList::Init(size_t cl) { | 42 void CentralFreeList::Init(size_t cl) { |
44 size_class_ = cl; | 43 size_class_ = cl; |
45 tcmalloc::DLL_Init(&empty_); | 44 tcmalloc::DLL_Init(&empty_); |
46 tcmalloc::DLL_Init(&nonempty_); | 45 tcmalloc::DLL_Init(&nonempty_); |
47 counter_ = 0; | 46 counter_ = 0; |
48 | 47 |
49 #ifdef TCMALLOC_SMALL_BUT_SLOW | 48 #ifdef TCMALLOC_SMALL_BUT_SLOW |
50 // Disable the transfer cache for the small footprint case. | 49 // Disable the transfer cache for the small footprint case. |
51 cache_size_ = 0; | 50 cache_size_ = 0; |
52 #else | 51 #else |
53 cache_size_ = 16; | 52 cache_size_ = 16; |
54 #endif | 53 #endif |
55 used_slots_ = 0; | 54 used_slots_ = 0; |
56 ASSERT(cache_size_ <= kNumTransferEntries); | 55 ASSERT(cache_size_ <= kNumTransferEntries); |
57 } | 56 } |
58 | 57 |
59 void CentralFreeList::ReleaseListToSpans(void* start) { | 58 void CentralFreeList::ReleaseListToSpans(void* start) { |
60 while (start) { | 59 while (start) { |
61 void *next = SLL_Next(start); | 60 void *next = FL_Next(start); |
62 ReleaseToSpans(start); | 61 ReleaseToSpans(start); |
63 start = next; | 62 start = next; |
64 } | 63 } |
65 } | 64 } |
66 | 65 |
67 // MapObjectToSpan should logically be part of ReleaseToSpans. But | 66 // MapObjectToSpan should logically be part of ReleaseToSpans. But |
68 // this triggers an optimization bug in gcc 4.5.0. Moving to a | 67 // this triggers an optimization bug in gcc 4.5.0. Moving to a |
69 // separate function, and making sure that function isn't inlined, | 68 // separate function, and making sure that function isn't inlined, |
70 // seems to fix the problem. It also should be fixed for gcc 4.5.1. | 69 // seems to fix the problem. It also should be fixed for gcc 4.5.1. |
71 static | 70 static |
(...skipping 15 matching lines...) Expand all Loading... |
87 if (span->objects == NULL) { | 86 if (span->objects == NULL) { |
88 tcmalloc::DLL_Remove(span); | 87 tcmalloc::DLL_Remove(span); |
89 tcmalloc::DLL_Prepend(&nonempty_, span); | 88 tcmalloc::DLL_Prepend(&nonempty_, span); |
90 Event(span, 'N', 0); | 89 Event(span, 'N', 0); |
91 } | 90 } |
92 | 91 |
93 // The following check is expensive, so it is disabled by default | 92 // The following check is expensive, so it is disabled by default |
94 if (false) { | 93 if (false) { |
95 // Check that object does not occur in list | 94 // Check that object does not occur in list |
96 int got = 0; | 95 int got = 0; |
97 for (void* p = span->objects; p != NULL; p = *((void**) p)) { | 96 for (void* p = span->objects; p != NULL; p = FL_Next(p)){ |
98 ASSERT(p != object); | 97 ASSERT(p != object); |
99 got++; | 98 got++; |
100 } | 99 } |
101 ASSERT(got + span->refcount == | 100 ASSERT(got + span->refcount == |
102 (span->length<<kPageShift) / | 101 (span->length<<kPageShift) / |
103 Static::sizemap()->ByteSizeForClass(span->sizeclass)); | 102 Static::sizemap()->ByteSizeForClass(span->sizeclass)); |
104 } | 103 } |
105 | 104 |
106 counter_++; | 105 counter_++; |
107 span->refcount--; | 106 span->refcount--; |
108 if (span->refcount == 0) { | 107 if (span->refcount == 0) { |
109 Event(span, '#', 0); | 108 Event(span, '#', 0); |
110 counter_ -= ((span->length<<kPageShift) / | 109 counter_ -= ((span->length<<kPageShift) / |
111 Static::sizemap()->ByteSizeForClass(span->sizeclass)); | 110 Static::sizemap()->ByteSizeForClass(span->sizeclass)); |
112 tcmalloc::DLL_Remove(span); | 111 tcmalloc::DLL_Remove(span); |
113 | 112 |
114 // Release central list lock while operating on pageheap | 113 // Release central list lock while operating on pageheap |
115 lock_.Unlock(); | 114 lock_.Unlock(); |
116 { | 115 { |
117 SpinLockHolder h(Static::pageheap_lock()); | 116 SpinLockHolder h(Static::pageheap_lock()); |
118 Static::pageheap()->Delete(span); | 117 Static::pageheap()->Delete(span); |
119 } | 118 } |
120 lock_.Lock(); | 119 lock_.Lock(); |
121 } else { | 120 } else { |
122 *(reinterpret_cast<void**>(object)) = span->objects; | 121 FL_Push(&(span->objects), object); |
123 span->objects = object; | |
124 } | 122 } |
125 } | 123 } |
126 | 124 |
127 bool CentralFreeList::EvictRandomSizeClass( | 125 bool CentralFreeList::EvictRandomSizeClass( |
128 int locked_size_class, bool force) { | 126 int locked_size_class, bool force) { |
129 static int race_counter = 0; | 127 static int race_counter = 0; |
130 int t = race_counter++; // Updated without a lock, but who cares. | 128 int t = race_counter++; // Updated without a lock, but who cares. |
131 if (t >= kNumClasses) { | 129 if (t >= kNumClasses) { |
132 while (t >= kNumClasses) { | 130 while (t >= kNumClasses) { |
133 t -= kNumClasses; | 131 t -= kNumClasses; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 lock_.Unlock(); | 230 lock_.Unlock(); |
233 return N; | 231 return N; |
234 } | 232 } |
235 | 233 |
236 int result = 0; | 234 int result = 0; |
237 void* head = NULL; | 235 void* head = NULL; |
238 void* tail = NULL; | 236 void* tail = NULL; |
239 // TODO: Prefetch multiple TCEntries? | 237 // TODO: Prefetch multiple TCEntries? |
240 tail = FetchFromSpansSafe(); | 238 tail = FetchFromSpansSafe(); |
241 if (tail != NULL) { | 239 if (tail != NULL) { |
242 SLL_SetNext(tail, NULL); | 240 FL_Push(&head, tail); |
243 head = tail; | |
244 result = 1; | 241 result = 1; |
245 while (result < N) { | 242 while (result < N) { |
246 void *t = FetchFromSpans(); | 243 void *t = FetchFromSpans(); |
247 if (!t) break; | 244 if (!t) break; |
248 SLL_Push(&head, t); | 245 FL_Push(&head, t); |
249 result++; | 246 result++; |
250 } | 247 } |
251 } | 248 } |
252 lock_.Unlock(); | 249 lock_.Unlock(); |
253 *start = head; | 250 *start = head; |
254 *end = tail; | 251 *end = tail; |
255 return result; | 252 return result; |
256 } | 253 } |
257 | 254 |
258 | 255 |
259 void* CentralFreeList::FetchFromSpansSafe() { | 256 void* CentralFreeList::FetchFromSpansSafe() { |
260 void *t = FetchFromSpans(); | 257 void *t = FetchFromSpans(); |
261 if (!t) { | 258 if (!t) { |
262 Populate(); | 259 Populate(); |
263 t = FetchFromSpans(); | 260 t = FetchFromSpans(); |
264 } | 261 } |
265 return t; | 262 return t; |
266 } | 263 } |
267 | 264 |
268 void* CentralFreeList::FetchFromSpans() { | 265 void* CentralFreeList::FetchFromSpans() { |
269 if (tcmalloc::DLL_IsEmpty(&nonempty_)) return NULL; | 266 if (tcmalloc::DLL_IsEmpty(&nonempty_)) return NULL; |
270 Span* span = nonempty_.next; | 267 Span* span = nonempty_.next; |
271 | 268 |
272 ASSERT(span->objects != NULL); | 269 ASSERT(span->objects != NULL); |
273 span->refcount++; | 270 span->refcount++; |
274 void* result = span->objects; | 271 void *result = FL_Pop(&(span->objects)); |
275 span->objects = *(reinterpret_cast<void**>(result)); | |
276 if (span->objects == NULL) { | 272 if (span->objects == NULL) { |
277 // Move to empty list | 273 // Move to empty list |
278 tcmalloc::DLL_Remove(span); | 274 tcmalloc::DLL_Remove(span); |
279 tcmalloc::DLL_Prepend(&empty_, span); | 275 tcmalloc::DLL_Prepend(&empty_, span); |
280 Event(span, 'E', 0); | 276 Event(span, 'E', 0); |
281 } | 277 } |
282 counter_--; | 278 counter_--; |
283 return result; | 279 return result; |
284 } | 280 } |
285 | 281 |
(...skipping 17 matching lines...) Expand all Loading... |
303 ASSERT(span->length == npages); | 299 ASSERT(span->length == npages); |
304 // Cache sizeclass info eagerly. Locking is not necessary. | 300 // Cache sizeclass info eagerly. Locking is not necessary. |
305 // (Instead of being eager, we could just replace any stale info | 301 // (Instead of being eager, we could just replace any stale info |
306 // about this span, but that seems to be no better in practice.) | 302 // about this span, but that seems to be no better in practice.) |
307 for (int i = 0; i < npages; i++) { | 303 for (int i = 0; i < npages; i++) { |
308 Static::pageheap()->CacheSizeClass(span->start + i, size_class_); | 304 Static::pageheap()->CacheSizeClass(span->start + i, size_class_); |
309 } | 305 } |
310 | 306 |
311 // Split the block into pieces and add to the free-list | 307 // Split the block into pieces and add to the free-list |
312 // TODO: coloring of objects to avoid cache conflicts? | 308 // TODO: coloring of objects to avoid cache conflicts? |
313 void** tail = &span->objects; | 309 void* list = NULL; |
314 char* ptr = reinterpret_cast<char*>(span->start << kPageShift); | 310 char* ptr = reinterpret_cast<char*>(span->start << kPageShift); |
315 char* limit = ptr + (npages << kPageShift); | 311 char* limit = ptr + (npages << kPageShift); |
316 const size_t size = Static::sizemap()->ByteSizeForClass(size_class_); | 312 const size_t size = Static::sizemap()->ByteSizeForClass(size_class_); |
317 int num = 0; | 313 int num = 0; |
318 while (ptr + size <= limit) { | 314 while (ptr + size <= limit) { |
319 *tail = ptr; | 315 FL_Push(&list, ptr); |
320 tail = reinterpret_cast<void**>(ptr); | |
321 ptr += size; | 316 ptr += size; |
322 num++; | 317 num++; |
323 } | 318 } |
324 ASSERT(ptr <= limit); | 319 ASSERT(ptr <= limit); |
325 *tail = NULL; | 320 span->objects = list; |
326 span->refcount = 0; // No sub-object in use yet | 321 span->refcount = 0; // No sub-object in use yet |
327 | 322 |
328 // Add span to list of non-empty spans | 323 // Add span to list of non-empty spans |
329 lock_.Lock(); | 324 lock_.Lock(); |
330 tcmalloc::DLL_Prepend(&nonempty_, span); | 325 tcmalloc::DLL_Prepend(&nonempty_, span); |
331 counter_ += num; | 326 counter_ += num; |
332 } | 327 } |
333 | 328 |
334 int CentralFreeList::tc_length() { | 329 int CentralFreeList::tc_length() { |
335 SpinLockHolder h(&lock_); | 330 SpinLockHolder h(&lock_); |
336 return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_); | 331 return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_); |
337 } | 332 } |
338 | 333 |
339 } // namespace tcmalloc | 334 } // namespace tcmalloc |
OLD | NEW |