| 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 15 matching lines...) Expand all Loading... |
| 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 |
| 36 #include "linked_list.h" | 36 #include "internal_logging.h" // for ASSERT, MESSAGE |
| 37 #include "static_vars.h" | 37 #include "linked_list.h" // for SLL_Next, SLL_Push, etc |
| 38 #include "page_heap.h" // for PageHeap |
| 39 #include "static_vars.h" // for Static |
| 38 | 40 |
| 39 namespace tcmalloc { | 41 namespace tcmalloc { |
| 40 | 42 |
| 41 void CentralFreeList::Init(size_t cl) { | 43 void CentralFreeList::Init(size_t cl) { |
| 42 size_class_ = cl; | 44 size_class_ = cl; |
| 43 tcmalloc::DLL_Init(&empty_); | 45 tcmalloc::DLL_Init(&empty_); |
| 44 tcmalloc::DLL_Init(&nonempty_); | 46 tcmalloc::DLL_Init(&nonempty_); |
| 45 counter_ = 0; | 47 counter_ = 0; |
| 46 | 48 |
| 47 cache_size_ = 1; | 49 #ifdef TCMALLOC_SMALL_BUT_SLOW |
| 50 // Disable the transfer cache for the small footprint case. |
| 51 cache_size_ = 0; |
| 52 #else |
| 53 cache_size_ = 16; |
| 54 #endif |
| 48 used_slots_ = 0; | 55 used_slots_ = 0; |
| 49 ASSERT(cache_size_ <= kNumTransferEntries); | 56 ASSERT(cache_size_ <= kNumTransferEntries); |
| 50 } | 57 } |
| 51 | 58 |
| 52 void CentralFreeList::ReleaseListToSpans(void* start) { | 59 void CentralFreeList::ReleaseListToSpans(void* start) { |
| 53 while (start) { | 60 while (start) { |
| 54 void *next = SLL_Next(start); | 61 void *next = SLL_Next(start); |
| 55 ReleaseToSpans(start); | 62 ReleaseToSpans(start); |
| 56 start = next; | 63 start = next; |
| 57 } | 64 } |
| 58 } | 65 } |
| 59 | 66 |
| 60 void CentralFreeList::ReleaseToSpans(void* object) { | 67 // MapObjectToSpan should logically be part of ReleaseToSpans. But |
| 68 // this triggers an optimization bug in gcc 4.5.0. Moving to a |
| 69 // 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. |
| 71 static |
| 72 #if __GNUC__ == 4 && __GNUC_MINOR__ == 5 && __GNUC_PATCHLEVEL__ == 0 |
| 73 __attribute__ ((noinline)) |
| 74 #endif |
| 75 Span* MapObjectToSpan(void* object) { |
| 61 const PageID p = reinterpret_cast<uintptr_t>(object) >> kPageShift; | 76 const PageID p = reinterpret_cast<uintptr_t>(object) >> kPageShift; |
| 62 Span* span = Static::pageheap()->GetDescriptor(p); | 77 Span* span = Static::pageheap()->GetDescriptor(p); |
| 78 return span; |
| 79 } |
| 80 |
| 81 void CentralFreeList::ReleaseToSpans(void* object) { |
| 82 Span* span = MapObjectToSpan(object); |
| 63 ASSERT(span != NULL); | 83 ASSERT(span != NULL); |
| 64 ASSERT(span->refcount > 0); | 84 ASSERT(span->refcount > 0); |
| 65 | 85 |
| 66 // If span is empty, move it to non-empty list | 86 // If span is empty, move it to non-empty list |
| 67 if (span->objects == NULL) { | 87 if (span->objects == NULL) { |
| 68 tcmalloc::DLL_Remove(span); | 88 tcmalloc::DLL_Remove(span); |
| 69 tcmalloc::DLL_Prepend(&nonempty_, span); | 89 tcmalloc::DLL_Prepend(&nonempty_, span); |
| 70 Event(span, 'N', 0); | 90 Event(span, 'N', 0); |
| 71 } | 91 } |
| 72 | 92 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 | 142 |
| 123 bool CentralFreeList::MakeCacheSpace() { | 143 bool CentralFreeList::MakeCacheSpace() { |
| 124 // Is there room in the cache? | 144 // Is there room in the cache? |
| 125 if (used_slots_ < cache_size_) return true; | 145 if (used_slots_ < cache_size_) return true; |
| 126 // Check if we can expand this cache? | 146 // Check if we can expand this cache? |
| 127 if (cache_size_ == kNumTransferEntries) return false; | 147 if (cache_size_ == kNumTransferEntries) return false; |
| 128 // Ok, we'll try to grab an entry from some other size class. | 148 // Ok, we'll try to grab an entry from some other size class. |
| 129 if (EvictRandomSizeClass(size_class_, false) || | 149 if (EvictRandomSizeClass(size_class_, false) || |
| 130 EvictRandomSizeClass(size_class_, true)) { | 150 EvictRandomSizeClass(size_class_, true)) { |
| 131 // Succeeded in evicting, we're going to make our cache larger. | 151 // Succeeded in evicting, we're going to make our cache larger. |
| 132 cache_size_++; | 152 // However, we may have dropped and re-acquired the lock in |
| 133 return true; | 153 // EvictRandomSizeClass (via ShrinkCache and the LockInverter), so the |
| 154 // cache_size may have changed. Therefore, check and verify that it is |
| 155 // still OK to increase the cache_size. |
| 156 if (cache_size_ < kNumTransferEntries) { |
| 157 cache_size_++; |
| 158 return true; |
| 159 } |
| 134 } | 160 } |
| 135 return false; | 161 return false; |
| 136 } | 162 } |
| 137 | 163 |
| 138 | 164 |
| 139 namespace { | 165 namespace { |
| 140 class LockInverter { | 166 class LockInverter { |
| 141 private: | 167 private: |
| 142 SpinLock *held_, *temp_; | 168 SpinLock *held_, *temp_; |
| 143 public: | 169 public: |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 tcmalloc::DLL_Prepend(&nonempty_, span); | 330 tcmalloc::DLL_Prepend(&nonempty_, span); |
| 305 counter_ += num; | 331 counter_ += num; |
| 306 } | 332 } |
| 307 | 333 |
| 308 int CentralFreeList::tc_length() { | 334 int CentralFreeList::tc_length() { |
| 309 SpinLockHolder h(&lock_); | 335 SpinLockHolder h(&lock_); |
| 310 return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_); | 336 return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_); |
| 311 } | 337 } |
| 312 | 338 |
| 313 } // namespace tcmalloc | 339 } // namespace tcmalloc |
| OLD | NEW |