| // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- |
| // Copyright (c) 2008, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // --- |
| // Author: Sanjay Ghemawat <opensource@google.com> |
| |
| #ifndef TCMALLOC_CENTRAL_FREELIST_H_ |
| #define TCMALLOC_CENTRAL_FREELIST_H_ |
| |
| #include "config.h" |
| #include <stddef.h> |
| #include <stdint.h> |
| #include "base/spinlock.h" |
| #include "base/thread_annotations.h" |
| #include "common.h" |
| #include "span.h" |
| |
| namespace tcmalloc { |
| |
| // Data kept per size-class in central cache. |
| class CACHELINE_ALIGNED CentralFreeList { |
| public: |
| constexpr CentralFreeList() {} |
| |
| void Init(size_t cl); |
| |
| // These methods all do internal locking. |
| |
| // Insert the specified range into the central freelist. N is the number of |
| // elements in the range. RemoveRange() is the opposite operation. |
| void InsertRange(void *start, void *end, int N); |
| |
| // Returns the actual number of fetched elements and sets *start and *end. |
| int RemoveRange(void **start, void **end, int N); |
| |
| // Returns the number of free objects in cache. |
| int length() { |
| SpinLockHolder h(&lock_); |
| return counter_; |
| } |
| |
| // Returns the number of free objects in the transfer cache. |
| int tc_length(); |
| |
| // Returns the memory overhead (internal fragmentation) attributable |
| // to the freelist. This is memory lost when the size of elements |
| // in a freelist doesn't exactly divide the page-size (an 8192-byte |
| // page full of 5-byte objects would have 2 bytes memory overhead). |
| size_t OverheadBytes(); |
| |
| // Lock/Unlock the internal SpinLock. Used on the pthread_atfork call |
| // to set the lock in a consistent state before the fork. |
| void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_) { |
| lock_.Lock(); |
| } |
| |
| void Unlock() UNLOCK_FUNCTION(lock_) { |
| lock_.Unlock(); |
| } |
| |
| private: |
| // TransferCache is used to cache transfers of |
| // sizemap.num_objects_to_move(size_class) back and forth between |
| // thread caches and the central cache for a given size class. |
| struct TCEntry { |
| constexpr TCEntry() {} |
| void *head{}; // Head of chain of objects. |
| void *tail{}; // Tail of chain of objects. |
| }; |
| |
| // A central cache freelist can have anywhere from 0 to kMaxNumTransferEntries |
| // slots to put link list chains into. |
| #ifdef TCMALLOC_SMALL_BUT_SLOW |
| // For the small memory model, the transfer cache is not used. |
| static const int kMaxNumTransferEntries = 0; |
| #else |
| // Starting point for the the maximum number of entries in the transfer cache. |
| // This actual maximum for a given size class may be lower than this |
| // maximum value. |
| static const int kMaxNumTransferEntries = 64; |
| #endif |
| |
| // REQUIRES: lock_ is held |
| // Remove object from cache and return. |
| // Return NULL if no free entries in cache. |
| int FetchFromOneSpans(int N, void **start, void **end) EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| // REQUIRES: lock_ is held |
| // Remove object from cache and return. Fetches |
| // from pageheap if cache is empty. Only returns |
| // NULL on allocation failure. |
| int FetchFromOneSpansSafe(int N, void **start, void **end) EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| // REQUIRES: lock_ is held |
| // Release a linked list of objects to spans. |
| // May temporarily release lock_. |
| void ReleaseListToSpans(void *start) EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| // REQUIRES: lock_ is held |
| // Release an object to spans. |
| // May temporarily release lock_. |
| void ReleaseToSpans(void* object) EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| // REQUIRES: lock_ is held |
| // Populate cache by fetching from the page heap. |
| // May temporarily release lock_. |
| void Populate() EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| // REQUIRES: lock is held. |
| // Tries to make room for a TCEntry. If the cache is full it will try to |
| // expand it at the cost of some other cache size. Return false if there is |
| // no space. |
| bool MakeCacheSpace() EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| |
| // REQUIRES: lock_ for locked_size_class is held. |
| // Picks a "random" size class to steal TCEntry slot from. In reality it |
| // just iterates over the sizeclasses but does so without taking a lock. |
| // Returns true on success. |
| // May temporarily lock a "random" size class. |
| static bool EvictRandomSizeClass(int locked_size_class, bool force); |
| |
| // REQUIRES: lock_ is *not* held. |
| // Tries to shrink the Cache. If force is true it will relase objects to |
| // spans if it allows it to shrink the cache. Return false if it failed to |
| // shrink the cache. Decrements cache_size_ on succeess. |
| // May temporarily take lock_. If it takes lock_, the locked_size_class |
| // lock is released to keep the thread from holding two size class locks |
| // concurrently which could lead to a deadlock. |
| bool ShrinkCache(int locked_size_class, bool force) LOCKS_EXCLUDED(lock_); |
| |
| // This lock protects all the data members. cached_entries and cache_size_ |
| // may be looked at without holding the lock. |
| SpinLock lock_; |
| |
| // We keep linked lists of empty and non-empty spans. |
| size_t size_class_{}; // My size class |
| Span empty_; // Dummy header for list of empty spans |
| Span nonempty_; // Dummy header for list of non-empty spans |
| size_t num_spans_{}; // Number of spans in empty_ plus nonempty_ |
| size_t counter_{}; // Number of free objects in cache entry |
| |
| // Here we reserve space for TCEntry cache slots. Space is preallocated |
| // for the largest possible number of entries than any one size class may |
| // accumulate. Not all size classes are allowed to accumulate |
| // kMaxNumTransferEntries, so there is some wasted space for those size |
| // classes. |
| TCEntry tc_slots_[kMaxNumTransferEntries]; |
| |
| // Number of currently used cached entries in tc_slots_. This variable is |
| // updated under a lock but can be read without one. |
| int32_t used_slots_{}; |
| // The current number of slots for this size class. This is an |
| // adaptive value that is increased if there is lots of traffic |
| // on a given size class. |
| int32_t cache_size_{}; |
| // Maximum size of the cache for a given size class. |
| int32_t max_cache_size_{}; |
| }; |
| |
| } // namespace tcmalloc |
| |
| #endif // TCMALLOC_CENTRAL_FREELIST_H_ |