central_freelist.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. // Copyright (c) 2008, Google Inc.
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // ---
  31. // Author: Sanjay Ghemawat <opensource@google.com>
  32. #include "config.h"
  33. #include <algorithm>
  34. #include "central_freelist.h"
  35. #include "internal_logging.h" // for ASSERT, MESSAGE
  36. #include "linked_list.h" // for SLL_Next, SLL_Push, etc
  37. #include "page_heap.h" // for PageHeap
  38. #include "static_vars.h" // for Static
  39. using std::min;
  40. using std::max;
  41. namespace tcmalloc {
  42. void CentralFreeList::Init(size_t cl) {
  43. size_class_ = cl;
  44. tcmalloc::DLL_Init(&empty_);
  45. tcmalloc::DLL_Init(&nonempty_);
  46. num_spans_ = 0;
  47. counter_ = 0;
  48. max_cache_size_ = kMaxNumTransferEntries;
  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
  55. if (cl > 0) {
  56. // Limit the maximum size of the cache based on the size class. If this
  57. // is not done, large size class objects will consume a lot of memory if
  58. // they just sit in the transfer cache.
  59. int32_t bytes = Static::sizemap()->ByteSizeForClass(cl);
  60. int32_t objs_to_move = Static::sizemap()->num_objects_to_move(cl);
  61. ASSERT(objs_to_move > 0 && bytes > 0);
  62. // Limit each size class cache to at most 1MB of objects or one entry,
  63. // whichever is greater. Total transfer cache memory used across all
  64. // size classes then can't be greater than approximately
  65. // 1MB * kMaxNumTransferEntries.
  66. // min and max are in parens to avoid macro-expansion on windows.
  67. max_cache_size_ = (min)(max_cache_size_,
  68. (max)(1, (1024 * 1024) / (bytes * objs_to_move)));
  69. cache_size_ = (min)(cache_size_, max_cache_size_);
  70. }
  71. used_slots_ = 0;
  72. ASSERT(cache_size_ <= max_cache_size_);
  73. }
  74. void CentralFreeList::ReleaseListToSpans(void* start) {
  75. while (start) {
  76. void *next = SLL_Next(start);
  77. ReleaseToSpans(start);
  78. start = next;
  79. }
  80. }
  81. // MapObjectToSpan should logically be part of ReleaseToSpans. But
  82. // this triggers an optimization bug in gcc 4.5.0. Moving to a
  83. // separate function, and making sure that function isn't inlined,
  84. // seems to fix the problem. It also should be fixed for gcc 4.5.1.
  85. static
  86. #if __GNUC__ == 4 && __GNUC_MINOR__ == 5 && __GNUC_PATCHLEVEL__ == 0
  87. __attribute__ ((noinline))
  88. #endif
  89. Span* MapObjectToSpan(void* object) {
  90. const PageID p = reinterpret_cast<uintptr_t>(object) >> kPageShift;
  91. Span* span = Static::pageheap()->GetDescriptor(p);
  92. return span;
  93. }
  94. void CentralFreeList::ReleaseToSpans(void* object) {
  95. Span* span = MapObjectToSpan(object);
  96. ASSERT(span != NULL);
  97. ASSERT(span->refcount > 0);
  98. // If span is empty, move it to non-empty list
  99. if (span->objects == NULL) {
  100. tcmalloc::DLL_Remove(span);
  101. tcmalloc::DLL_Prepend(&nonempty_, span);
  102. Event(span, 'N', 0);
  103. }
  104. // The following check is expensive, so it is disabled by default
  105. if (false) {
  106. // Check that object does not occur in list
  107. int got = 0;
  108. for (void* p = span->objects; p != NULL; p = *((void**) p)) {
  109. ASSERT(p != object);
  110. got++;
  111. }
  112. ASSERT(got + span->refcount ==
  113. (span->length<<kPageShift) /
  114. Static::sizemap()->ByteSizeForClass(span->sizeclass));
  115. }
  116. counter_++;
  117. span->refcount--;
  118. if (span->refcount == 0) {
  119. Event(span, '#', 0);
  120. counter_ -= ((span->length<<kPageShift) /
  121. Static::sizemap()->ByteSizeForClass(span->sizeclass));
  122. tcmalloc::DLL_Remove(span);
  123. --num_spans_;
  124. // Release central list lock while operating on pageheap
  125. lock_.Unlock();
  126. {
  127. SpinLockHolder h(Static::pageheap_lock());
  128. Static::pageheap()->Delete(span);
  129. }
  130. lock_.Lock();
  131. } else {
  132. *(reinterpret_cast<void**>(object)) = span->objects;
  133. span->objects = object;
  134. }
  135. }
  136. bool CentralFreeList::EvictRandomSizeClass(
  137. int locked_size_class, bool force) {
  138. static int race_counter = 0;
  139. int t = race_counter++; // Updated without a lock, but who cares.
  140. if (t >= kNumClasses) {
  141. while (t >= kNumClasses) {
  142. t -= kNumClasses;
  143. }
  144. race_counter = t;
  145. }
  146. ASSERT(t >= 0);
  147. ASSERT(t < kNumClasses);
  148. if (t == locked_size_class) return false;
  149. return Static::central_cache()[t].ShrinkCache(locked_size_class, force);
  150. }
  151. bool CentralFreeList::MakeCacheSpace() {
  152. // Is there room in the cache?
  153. if (used_slots_ < cache_size_) return true;
  154. // Check if we can expand this cache?
  155. if (cache_size_ == max_cache_size_) return false;
  156. // Ok, we'll try to grab an entry from some other size class.
  157. if (EvictRandomSizeClass(size_class_, false) ||
  158. EvictRandomSizeClass(size_class_, true)) {
  159. // Succeeded in evicting, we're going to make our cache larger.
  160. // However, we may have dropped and re-acquired the lock in
  161. // EvictRandomSizeClass (via ShrinkCache and the LockInverter), so the
  162. // cache_size may have changed. Therefore, check and verify that it is
  163. // still OK to increase the cache_size.
  164. if (cache_size_ < max_cache_size_) {
  165. cache_size_++;
  166. return true;
  167. }
  168. }
  169. return false;
  170. }
  171. namespace {
  172. class LockInverter {
  173. private:
  174. SpinLock *held_, *temp_;
  175. public:
  176. inline explicit LockInverter(SpinLock* held, SpinLock *temp)
  177. : held_(held), temp_(temp) { held_->Unlock(); temp_->Lock(); }
  178. inline ~LockInverter() { temp_->Unlock(); held_->Lock(); }
  179. };
  180. }
  181. // This function is marked as NO_THREAD_SAFETY_ANALYSIS because it uses
  182. // LockInverter to release one lock and acquire another in scoped-lock
  183. // style, which our current annotation/analysis does not support.
  184. bool CentralFreeList::ShrinkCache(int locked_size_class, bool force)
  185. NO_THREAD_SAFETY_ANALYSIS {
  186. // Start with a quick check without taking a lock.
  187. if (cache_size_ == 0) return false;
  188. // We don't evict from a full cache unless we are 'forcing'.
  189. if (force == false && used_slots_ == cache_size_) return false;
  190. // Grab lock, but first release the other lock held by this thread. We use
  191. // the lock inverter to ensure that we never hold two size class locks
  192. // concurrently. That can create a deadlock because there is no well
  193. // defined nesting order.
  194. LockInverter li(&Static::central_cache()[locked_size_class].lock_, &lock_);
  195. ASSERT(used_slots_ <= cache_size_);
  196. ASSERT(0 <= cache_size_);
  197. if (cache_size_ == 0) return false;
  198. if (used_slots_ == cache_size_) {
  199. if (force == false) return false;
  200. // ReleaseListToSpans releases the lock, so we have to make all the
  201. // updates to the central list before calling it.
  202. cache_size_--;
  203. used_slots_--;
  204. ReleaseListToSpans(tc_slots_[used_slots_].head);
  205. return true;
  206. }
  207. cache_size_--;
  208. return true;
  209. }
  210. void CentralFreeList::InsertRange(void *start, void *end, int N) {
  211. SpinLockHolder h(&lock_);
  212. if (N == Static::sizemap()->num_objects_to_move(size_class_) &&
  213. MakeCacheSpace()) {
  214. int slot = used_slots_++;
  215. ASSERT(slot >=0);
  216. ASSERT(slot < max_cache_size_);
  217. TCEntry *entry = &tc_slots_[slot];
  218. entry->head = start;
  219. entry->tail = end;
  220. return;
  221. }
  222. ReleaseListToSpans(start);
  223. }
  224. int CentralFreeList::RemoveRange(void **start, void **end, int N) {
  225. ASSERT(N > 0);
  226. lock_.Lock();
  227. if (N == Static::sizemap()->num_objects_to_move(size_class_) &&
  228. used_slots_ > 0) {
  229. int slot = --used_slots_;
  230. ASSERT(slot >= 0);
  231. TCEntry *entry = &tc_slots_[slot];
  232. *start = entry->head;
  233. *end = entry->tail;
  234. lock_.Unlock();
  235. return N;
  236. }
  237. int result = 0;
  238. *start = NULL;
  239. *end = NULL;
  240. // TODO: Prefetch multiple TCEntries?
  241. result = FetchFromOneSpansSafe(N, start, end);
  242. if (result != 0) {
  243. while (result < N) {
  244. int n;
  245. void* head = NULL;
  246. void* tail = NULL;
  247. n = FetchFromOneSpans(N - result, &head, &tail);
  248. if (!n) break;
  249. result += n;
  250. SLL_PushRange(start, head, tail);
  251. }
  252. }
  253. lock_.Unlock();
  254. return result;
  255. }
  256. int CentralFreeList::FetchFromOneSpansSafe(int N, void **start, void **end) {
  257. int result = FetchFromOneSpans(N, start, end);
  258. if (!result) {
  259. Populate();
  260. result = FetchFromOneSpans(N, start, end);
  261. }
  262. return result;
  263. }
  264. int CentralFreeList::FetchFromOneSpans(int N, void **start, void **end) {
  265. if (tcmalloc::DLL_IsEmpty(&nonempty_)) return 0;
  266. Span* span = nonempty_.next;
  267. ASSERT(span->objects != NULL);
  268. int result = 0;
  269. void *prev, *curr;
  270. curr = span->objects;
  271. do {
  272. prev = curr;
  273. curr = *(reinterpret_cast<void**>(curr));
  274. } while (++result < N && curr != NULL);
  275. if (curr == NULL) {
  276. // Move to empty list
  277. tcmalloc::DLL_Remove(span);
  278. tcmalloc::DLL_Prepend(&empty_, span);
  279. Event(span, 'E', 0);
  280. }
  281. *start = span->objects;
  282. *end = prev;
  283. span->objects = curr;
  284. SLL_SetNext(*end, NULL);
  285. span->refcount += result;
  286. counter_ -= result;
  287. return result;
  288. }
  289. // Fetch memory from the system and add to the central cache freelist.
  290. void CentralFreeList::Populate() {
  291. // Release central list lock while operating on pageheap
  292. lock_.Unlock();
  293. const size_t npages = Static::sizemap()->class_to_pages(size_class_);
  294. Span* span;
  295. {
  296. SpinLockHolder h(Static::pageheap_lock());
  297. span = Static::pageheap()->New(npages);
  298. if (span) Static::pageheap()->RegisterSizeClass(span, size_class_);
  299. }
  300. if (span == NULL) {
  301. Log(kLog, __FILE__, __LINE__,
  302. "tcmalloc: allocation failed", npages << kPageShift);
  303. lock_.Lock();
  304. return;
  305. }
  306. ASSERT(span->length == npages);
  307. // Cache sizeclass info eagerly. Locking is not necessary.
  308. // (Instead of being eager, we could just replace any stale info
  309. // about this span, but that seems to be no better in practice.)
  310. for (int i = 0; i < npages; i++) {
  311. Static::pageheap()->CacheSizeClass(span->start + i, size_class_);
  312. }
  313. // Split the block into pieces and add to the free-list
  314. // TODO: coloring of objects to avoid cache conflicts?
  315. void** tail = &span->objects;
  316. char* ptr = reinterpret_cast<char*>(span->start << kPageShift);
  317. char* limit = ptr + (npages << kPageShift);
  318. const size_t size = Static::sizemap()->ByteSizeForClass(size_class_);
  319. int num = 0;
  320. while (ptr + size <= limit) {
  321. *tail = ptr;
  322. tail = reinterpret_cast<void**>(ptr);
  323. ptr += size;
  324. num++;
  325. }
  326. ASSERT(ptr <= limit);
  327. *tail = NULL;
  328. span->refcount = 0; // No sub-object in use yet
  329. // Add span to list of non-empty spans
  330. lock_.Lock();
  331. tcmalloc::DLL_Prepend(&nonempty_, span);
  332. ++num_spans_;
  333. counter_ += num;
  334. }
  335. int CentralFreeList::tc_length() {
  336. SpinLockHolder h(&lock_);
  337. return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_);
  338. }
  339. size_t CentralFreeList::OverheadBytes() {
  340. SpinLockHolder h(&lock_);
  341. if (size_class_ == 0) { // 0 holds the 0-sized allocations
  342. return 0;
  343. }
  344. const size_t pages_per_span = Static::sizemap()->class_to_pages(size_class_);
  345. const size_t object_size = Static::sizemap()->class_to_size(size_class_);
  346. ASSERT(object_size > 0);
  347. const size_t overhead_per_span = (pages_per_span * kPageSize) % object_size;
  348. return num_spans_ * overhead_per_span;
  349. }
  350. } // namespace tcmalloc