| 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 | 
|---|