151c0b2f7Stbbdev /* 22110128eSsarathnandu Copyright (c) 2005-2023 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev #ifndef __TBB_tbbmalloc_internal_H 1851c0b2f7Stbbdev #error tbbmalloc_internal.h must be included at this point 1951c0b2f7Stbbdev #endif 2051c0b2f7Stbbdev 2151c0b2f7Stbbdev #ifndef __TBB_large_objects_H 2251c0b2f7Stbbdev #define __TBB_large_objects_H 2351c0b2f7Stbbdev 2451c0b2f7Stbbdev //! The list of possible Cache Bin Aggregator operations. 2551c0b2f7Stbbdev /* Declared here to avoid Solaris Studio* 12.2 "multiple definitions" error */ 2651c0b2f7Stbbdev enum CacheBinOperationType { 2751c0b2f7Stbbdev CBOP_INVALID = 0, 2851c0b2f7Stbbdev CBOP_GET, 2951c0b2f7Stbbdev CBOP_PUT_LIST, 3051c0b2f7Stbbdev CBOP_CLEAN_TO_THRESHOLD, 3151c0b2f7Stbbdev CBOP_CLEAN_ALL, 3251c0b2f7Stbbdev CBOP_UPDATE_USED_SIZE 3351c0b2f7Stbbdev }; 3451c0b2f7Stbbdev 3551c0b2f7Stbbdev // The Cache Bin Aggregator operation status list. 3651c0b2f7Stbbdev // CBST_NOWAIT can be specified for non-blocking operations. 3751c0b2f7Stbbdev enum CacheBinOperationStatus { 3851c0b2f7Stbbdev CBST_WAIT = 0, 3951c0b2f7Stbbdev CBST_NOWAIT, 4051c0b2f7Stbbdev CBST_DONE 4151c0b2f7Stbbdev }; 4251c0b2f7Stbbdev 4351c0b2f7Stbbdev /* 4451c0b2f7Stbbdev * Bins that grow with arithmetic step 4551c0b2f7Stbbdev */ 4651c0b2f7Stbbdev template<size_t MIN_SIZE, size_t MAX_SIZE> 4751c0b2f7Stbbdev struct LargeBinStructureProps { 4851c0b2f7Stbbdev public: 4951c0b2f7Stbbdev static const size_t MinSize = MIN_SIZE, MaxSize = MAX_SIZE; 5051c0b2f7Stbbdev static const size_t CacheStep = 8 * 1024; 5151c0b2f7Stbbdev static const unsigned NumBins = (MaxSize - MinSize) / CacheStep; 5251c0b2f7Stbbdev alignToBinLargeBinStructureProps5351c0b2f7Stbbdev static size_t alignToBin(size_t size) { 5451c0b2f7Stbbdev return alignUp(size, CacheStep); 5551c0b2f7Stbbdev } 5651c0b2f7Stbbdev sizeToIdxLargeBinStructureProps5751c0b2f7Stbbdev static int sizeToIdx(size_t size) { 5851c0b2f7Stbbdev MALLOC_ASSERT(MinSize <= size && size < MaxSize, ASSERT_TEXT); 5951c0b2f7Stbbdev MALLOC_ASSERT(size % CacheStep == 0, ASSERT_TEXT); 6051c0b2f7Stbbdev return (size - MinSize) / CacheStep; 6151c0b2f7Stbbdev } 6251c0b2f7Stbbdev }; 6351c0b2f7Stbbdev 6451c0b2f7Stbbdev /* 6551c0b2f7Stbbdev * Bins that grow with special geometric progression. 6651c0b2f7Stbbdev */ 6751c0b2f7Stbbdev template<size_t MIN_SIZE, size_t MAX_SIZE> 6851c0b2f7Stbbdev struct HugeBinStructureProps { 6951c0b2f7Stbbdev 7051c0b2f7Stbbdev private: 7151c0b2f7Stbbdev // Sizes grow with the following formula: Size = MinSize * (2 ^ (Index / StepFactor)) 7251c0b2f7Stbbdev // There are StepFactor bins (8 be default) between each power of 2 bin 7351c0b2f7Stbbdev static const int MaxSizeExp = Log2<MAX_SIZE>::value; 7451c0b2f7Stbbdev static const int MinSizeExp = Log2<MIN_SIZE>::value; 7551c0b2f7Stbbdev static const int StepFactor = 8; 7651c0b2f7Stbbdev static const int StepFactorExp = Log2<StepFactor>::value; 7751c0b2f7Stbbdev 7851c0b2f7Stbbdev public: 7951c0b2f7Stbbdev static const size_t MinSize = MIN_SIZE, MaxSize = MAX_SIZE; 8051c0b2f7Stbbdev static const unsigned NumBins = (MaxSizeExp - MinSizeExp) * StepFactor; 8151c0b2f7Stbbdev alignToBinHugeBinStructureProps8251c0b2f7Stbbdev static size_t alignToBin(size_t size) { 834992457dSLukasz Dorau MALLOC_ASSERT(size >= StepFactor, "Size must not be less than the StepFactor"); 8451c0b2f7Stbbdev size_t minorStepExp = BitScanRev(size) - StepFactorExp; 8551c0b2f7Stbbdev return alignUp(size, 1ULL << minorStepExp); 8651c0b2f7Stbbdev } 8751c0b2f7Stbbdev 88*c4a799dfSJhaShweta1 // Sizes between the power of 2 values are approximated to StepFactor. sizeToIdxHugeBinStructureProps8951c0b2f7Stbbdev static int sizeToIdx(size_t size) { 9051c0b2f7Stbbdev MALLOC_ASSERT(MinSize <= size && size <= MaxSize, ASSERT_TEXT); 9151c0b2f7Stbbdev int sizeExp = (int)BitScanRev(size); // same as __TBB_Log2 92926c3783SLukasz Dorau MALLOC_ASSERT(sizeExp >= 0, "A shift amount (sizeExp) must not be negative"); 9351c0b2f7Stbbdev size_t majorStepSize = 1ULL << sizeExp; 9451c0b2f7Stbbdev int minorStepExp = sizeExp - StepFactorExp; 95926c3783SLukasz Dorau MALLOC_ASSERT(minorStepExp >= 0, "A shift amount (minorStepExp) must not be negative"); 9651c0b2f7Stbbdev int minorIdx = (size - majorStepSize) >> minorStepExp; 9751c0b2f7Stbbdev MALLOC_ASSERT(size == majorStepSize + ((size_t)minorIdx << minorStepExp), 9851c0b2f7Stbbdev "Size is not aligned on the bin"); 9951c0b2f7Stbbdev return StepFactor * (sizeExp - MinSizeExp) + minorIdx; 10051c0b2f7Stbbdev } 10151c0b2f7Stbbdev }; 10251c0b2f7Stbbdev 10351c0b2f7Stbbdev /* 10451c0b2f7Stbbdev * Cache properties accessor 10551c0b2f7Stbbdev * 10651c0b2f7Stbbdev * TooLargeFactor -- when cache size treated "too large" in comparison to user data size 10751c0b2f7Stbbdev * OnMissFactor -- If cache miss occurred and cache was cleaned, 10851c0b2f7Stbbdev * set ageThreshold to OnMissFactor * the difference 10951c0b2f7Stbbdev * between current time and last time cache was cleaned. 11051c0b2f7Stbbdev * LongWaitFactor -- to detect rarely-used bins and forget about their usage history 11151c0b2f7Stbbdev */ 11251c0b2f7Stbbdev template<typename StructureProps, int TOO_LARGE, int ON_MISS, int LONG_WAIT> 11351c0b2f7Stbbdev struct LargeObjectCacheProps : public StructureProps { 11451c0b2f7Stbbdev static const int TooLargeFactor = TOO_LARGE, OnMissFactor = ON_MISS, LongWaitFactor = LONG_WAIT; 11551c0b2f7Stbbdev }; 11651c0b2f7Stbbdev 11751c0b2f7Stbbdev template<typename Props> 11851c0b2f7Stbbdev class LargeObjectCacheImpl { 11951c0b2f7Stbbdev private: 12051c0b2f7Stbbdev 12151c0b2f7Stbbdev // Current sizes of used and cached objects. It's calculated while we are 12251c0b2f7Stbbdev // traversing bins, and used for isLOCTooLarge() check at the same time. 12351c0b2f7Stbbdev class BinsSummary { 12451c0b2f7Stbbdev size_t usedSz; 12551c0b2f7Stbbdev size_t cachedSz; 12651c0b2f7Stbbdev public: BinsSummary()12751c0b2f7Stbbdev BinsSummary() : usedSz(0), cachedSz(0) {} 12851c0b2f7Stbbdev // "too large" criteria isLOCTooLarge()12951c0b2f7Stbbdev bool isLOCTooLarge() const { return cachedSz > Props::TooLargeFactor * usedSz; } update(size_t usedSize,size_t cachedSize)13051c0b2f7Stbbdev void update(size_t usedSize, size_t cachedSize) { 13151c0b2f7Stbbdev usedSz += usedSize; 13251c0b2f7Stbbdev cachedSz += cachedSize; 13351c0b2f7Stbbdev } reset()13451c0b2f7Stbbdev void reset() { usedSz = cachedSz = 0; } 13551c0b2f7Stbbdev }; 13651c0b2f7Stbbdev 13751c0b2f7Stbbdev public: 13851c0b2f7Stbbdev // The number of bins to cache large/huge objects. 13951c0b2f7Stbbdev static const uint32_t numBins = Props::NumBins; 14051c0b2f7Stbbdev 14151c0b2f7Stbbdev typedef BitMaskMax<numBins> BinBitMask; 14251c0b2f7Stbbdev 14351c0b2f7Stbbdev // 2-linked list of same-size cached blocks ordered by age (oldest on top) 14451c0b2f7Stbbdev // TODO: are we really want the list to be 2-linked? This allows us 14551c0b2f7Stbbdev // reduce memory consumption and do less operations under lock. 14651c0b2f7Stbbdev // TODO: try to switch to 32-bit logical time to save space in CacheBin 14751c0b2f7Stbbdev // and move bins to different cache lines. 14851c0b2f7Stbbdev class CacheBin { 14951c0b2f7Stbbdev private: 150478de5b1Stbbdev LargeMemoryBlock* first; 151478de5b1Stbbdev std::atomic<LargeMemoryBlock*> last; 15251c0b2f7Stbbdev /* age of an oldest block in the list; equal to last->age, if last defined, 15351c0b2f7Stbbdev used for quick checking it without acquiring the lock. */ 154478de5b1Stbbdev std::atomic<uintptr_t> oldest; 15551c0b2f7Stbbdev /* currAge when something was excluded out of list because of the age, 15651c0b2f7Stbbdev not because of cache hit */ 15751c0b2f7Stbbdev uintptr_t lastCleanedAge; 15851c0b2f7Stbbdev /* Current threshold value for the blocks of a particular size. 15951c0b2f7Stbbdev Set on cache miss. */ 160478de5b1Stbbdev std::atomic<intptr_t> ageThreshold; 16151c0b2f7Stbbdev 16251c0b2f7Stbbdev /* total size of all objects corresponding to the bin and allocated by user */ 163478de5b1Stbbdev std::atomic<size_t> usedSize; 16451c0b2f7Stbbdev /* total size of all objects cached in the bin */ 165478de5b1Stbbdev std::atomic<size_t> cachedSize; 16651c0b2f7Stbbdev /* mean time of presence of block in the bin before successful reuse */ 167478de5b1Stbbdev std::atomic<intptr_t> meanHitRange; 16851c0b2f7Stbbdev /* time of last get called for the bin */ 16951c0b2f7Stbbdev uintptr_t lastGet; 17051c0b2f7Stbbdev 17151c0b2f7Stbbdev typename MallocAggregator<CacheBinOperation>::type aggregator; 17251c0b2f7Stbbdev 17351c0b2f7Stbbdev void ExecuteOperation(CacheBinOperation *op, ExtMemoryPool *extMemPool, BinBitMask *bitMask, int idx, bool longLifeTime = true); 17451c0b2f7Stbbdev 17551c0b2f7Stbbdev /* should be placed in zero-initialized memory, ctor not needed. */ 17651c0b2f7Stbbdev CacheBin(); 17751c0b2f7Stbbdev 17851c0b2f7Stbbdev public: init()17951c0b2f7Stbbdev void init() { 1802110128eSsarathnandu memset(static_cast<void*>(this), 0, sizeof(CacheBin)); 18151c0b2f7Stbbdev } 18251c0b2f7Stbbdev 18351c0b2f7Stbbdev /* ---------- Cache accessors ---------- */ 18451c0b2f7Stbbdev void putList(ExtMemoryPool *extMemPool, LargeMemoryBlock *head, BinBitMask *bitMask, int idx); 18551c0b2f7Stbbdev LargeMemoryBlock *get(ExtMemoryPool *extMemPool, size_t size, BinBitMask *bitMask, int idx); 18651c0b2f7Stbbdev 18751c0b2f7Stbbdev /* ---------- Cleanup functions -------- */ 18851c0b2f7Stbbdev bool cleanToThreshold(ExtMemoryPool *extMemPool, BinBitMask *bitMask, uintptr_t currTime, int idx); 18951c0b2f7Stbbdev bool releaseAllToBackend(ExtMemoryPool *extMemPool, BinBitMask *bitMask, int idx); 19051c0b2f7Stbbdev /* ------------------------------------- */ 19151c0b2f7Stbbdev 19251c0b2f7Stbbdev void updateUsedSize(ExtMemoryPool *extMemPool, size_t size, BinBitMask *bitMask, int idx); decreaseThreshold()19351c0b2f7Stbbdev void decreaseThreshold() { 194478de5b1Stbbdev intptr_t threshold = ageThreshold.load(std::memory_order_relaxed); 195478de5b1Stbbdev if (threshold) 196478de5b1Stbbdev ageThreshold.store((threshold + meanHitRange.load(std::memory_order_relaxed)) / 2, std::memory_order_relaxed); 19751c0b2f7Stbbdev } updateBinsSummary(BinsSummary * binsSummary)19851c0b2f7Stbbdev void updateBinsSummary(BinsSummary *binsSummary) const { 199478de5b1Stbbdev binsSummary->update(usedSize.load(std::memory_order_relaxed), cachedSize.load(std::memory_order_relaxed)); 20051c0b2f7Stbbdev } getSize()201478de5b1Stbbdev size_t getSize() const { return cachedSize.load(std::memory_order_relaxed); } getUsedSize()202478de5b1Stbbdev size_t getUsedSize() const { return usedSize.load(std::memory_order_relaxed); } 20351c0b2f7Stbbdev size_t reportStat(int num, FILE *f); 20451c0b2f7Stbbdev 20551c0b2f7Stbbdev /* --------- Unsafe methods used with the aggregator ------- */ 20651c0b2f7Stbbdev void forgetOutdatedState(uintptr_t currTime); 20751c0b2f7Stbbdev LargeMemoryBlock *putList(LargeMemoryBlock *head, LargeMemoryBlock *tail, BinBitMask *bitMask, 20851c0b2f7Stbbdev int idx, int num, size_t hugeObjectThreshold); 20951c0b2f7Stbbdev LargeMemoryBlock *get(); 21051c0b2f7Stbbdev LargeMemoryBlock *cleanToThreshold(uintptr_t currTime, BinBitMask *bitMask, int idx); 21151c0b2f7Stbbdev LargeMemoryBlock *cleanAll(BinBitMask *bitMask, int idx); updateUsedSize(size_t size,BinBitMask * bitMask,int idx)21251c0b2f7Stbbdev void updateUsedSize(size_t size, BinBitMask *bitMask, int idx) { 213478de5b1Stbbdev if (!usedSize.load(std::memory_order_relaxed)) bitMask->set(idx, true); 214478de5b1Stbbdev usedSize.store(usedSize.load(std::memory_order_relaxed) + size, std::memory_order_relaxed); 215478de5b1Stbbdev if (!usedSize.load(std::memory_order_relaxed) && !first) bitMask->set(idx, false); 21651c0b2f7Stbbdev } updateMeanHitRange(intptr_t hitRange)21751c0b2f7Stbbdev void updateMeanHitRange( intptr_t hitRange ) { 21851c0b2f7Stbbdev hitRange = hitRange >= 0 ? hitRange : 0; 219478de5b1Stbbdev intptr_t mean = meanHitRange.load(std::memory_order_relaxed); 220478de5b1Stbbdev mean = mean ? (mean + hitRange) / 2 : hitRange; 221478de5b1Stbbdev meanHitRange.store(mean, std::memory_order_relaxed); 22251c0b2f7Stbbdev } updateAgeThreshold(uintptr_t currTime)22351c0b2f7Stbbdev void updateAgeThreshold( uintptr_t currTime ) { 22451c0b2f7Stbbdev if (lastCleanedAge) 225478de5b1Stbbdev ageThreshold.store(Props::OnMissFactor * (currTime - lastCleanedAge), std::memory_order_relaxed); 22651c0b2f7Stbbdev } updateCachedSize(size_t size)22751c0b2f7Stbbdev void updateCachedSize(size_t size) { 228478de5b1Stbbdev cachedSize.store(cachedSize.load(std::memory_order_relaxed) + size, std::memory_order_relaxed); 22951c0b2f7Stbbdev } setLastGet(uintptr_t newLastGet)23051c0b2f7Stbbdev void setLastGet( uintptr_t newLastGet ) { 23151c0b2f7Stbbdev lastGet = newLastGet; 23251c0b2f7Stbbdev } 23351c0b2f7Stbbdev /* -------------------------------------------------------- */ 23451c0b2f7Stbbdev }; 23551c0b2f7Stbbdev 23651c0b2f7Stbbdev // Huge bins index for fast regular cleanup searching in case of 23751c0b2f7Stbbdev // the "huge size threshold" setting defined 23851c0b2f7Stbbdev intptr_t hugeSizeThresholdIdx; 23951c0b2f7Stbbdev 24051c0b2f7Stbbdev private: 24151c0b2f7Stbbdev // How many times LOC was "too large" 24251c0b2f7Stbbdev std::atomic<intptr_t> tooLargeLOC; 24351c0b2f7Stbbdev // for fast finding of used bins and bins with non-zero usedSize; 24451c0b2f7Stbbdev // indexed from the end, as we need largest 1st 24551c0b2f7Stbbdev BinBitMask bitMask; 246*c4a799dfSJhaShweta1 // bins with lists of recently freed large blocks cached for reuse 24751c0b2f7Stbbdev CacheBin bin[numBins]; 24851c0b2f7Stbbdev 24951c0b2f7Stbbdev public: 25051c0b2f7Stbbdev /* ------------ CacheBin structure dependent stuff ------------ */ alignToBin(size_t size)25151c0b2f7Stbbdev static size_t alignToBin(size_t size) { 25251c0b2f7Stbbdev return Props::alignToBin(size); 25351c0b2f7Stbbdev } sizeToIdx(size_t size)25451c0b2f7Stbbdev static int sizeToIdx(size_t size) { 25551c0b2f7Stbbdev return Props::sizeToIdx(size); 25651c0b2f7Stbbdev } 25751c0b2f7Stbbdev 25851c0b2f7Stbbdev /* --------- Main cache functions (put, get object) ------------ */ 25951c0b2f7Stbbdev void putList(ExtMemoryPool *extMemPool, LargeMemoryBlock *largeBlock); 26051c0b2f7Stbbdev LargeMemoryBlock *get(ExtMemoryPool *extMemPool, size_t size); 26151c0b2f7Stbbdev 26251c0b2f7Stbbdev /* ------------------------ Cleanup ---------------------------- */ 26351c0b2f7Stbbdev bool regularCleanup(ExtMemoryPool *extMemPool, uintptr_t currAge, bool doThreshDecr); 26451c0b2f7Stbbdev bool cleanAll(ExtMemoryPool *extMemPool); 26551c0b2f7Stbbdev 26651c0b2f7Stbbdev /* -------------------------- Other ---------------------------- */ 26751c0b2f7Stbbdev void updateCacheState(ExtMemoryPool *extMemPool, DecreaseOrIncrease op, size_t size); 26851c0b2f7Stbbdev 26951c0b2f7Stbbdev void reset(); 27051c0b2f7Stbbdev void reportStat(FILE *f); 27151c0b2f7Stbbdev #if __TBB_MALLOC_WHITEBOX_TEST 27251c0b2f7Stbbdev size_t getLOCSize() const; 27351c0b2f7Stbbdev size_t getUsedSize() const; 27451c0b2f7Stbbdev #endif 27551c0b2f7Stbbdev }; 27651c0b2f7Stbbdev 27751c0b2f7Stbbdev class LargeObjectCache { 27851c0b2f7Stbbdev private: 27951c0b2f7Stbbdev // Large bins [minLargeSize, maxLargeSize) 28051c0b2f7Stbbdev // Huge bins [maxLargeSize, maxHugeSize) 28151c0b2f7Stbbdev static const size_t minLargeSize = 8 * 1024, 28251c0b2f7Stbbdev maxLargeSize = 8 * 1024 * 1024, 28351c0b2f7Stbbdev // Cache memory up to 1TB (or 2GB for 32-bit arch), but sieve objects from the special threshold 28451c0b2f7Stbbdev maxHugeSize = tbb::detail::select_size_t_constant<2147483648U, 1099511627776ULL>::value; 28551c0b2f7Stbbdev 28651c0b2f7Stbbdev public: 28751c0b2f7Stbbdev // Upper bound threshold for caching size. After that size all objects sieve through cache 28851c0b2f7Stbbdev // By default - 64MB, previous value was 129MB (needed by some Intel(R) Math Kernel Library (Intel(R) MKL) benchmarks) 28951c0b2f7Stbbdev static const size_t defaultMaxHugeSize = 64UL * 1024UL * 1024UL; 29051c0b2f7Stbbdev // After that size large object interpreted as huge and does not participate in regular cleanup. 29151c0b2f7Stbbdev // Can be changed during the program execution. 29251c0b2f7Stbbdev size_t hugeSizeThreshold; 29351c0b2f7Stbbdev 29451c0b2f7Stbbdev private: 29551c0b2f7Stbbdev // Large objects cache properties 29651c0b2f7Stbbdev typedef LargeBinStructureProps<minLargeSize, maxLargeSize> LargeBSProps; 29751c0b2f7Stbbdev typedef LargeObjectCacheProps<LargeBSProps, 2, 2, 16> LargeCacheTypeProps; 29851c0b2f7Stbbdev 29951c0b2f7Stbbdev // Huge objects cache properties 30051c0b2f7Stbbdev typedef HugeBinStructureProps<maxLargeSize, maxHugeSize> HugeBSProps; 30151c0b2f7Stbbdev typedef LargeObjectCacheProps<HugeBSProps, 1, 1, 4> HugeCacheTypeProps; 30251c0b2f7Stbbdev 30351c0b2f7Stbbdev // Cache implementation type with properties 30451c0b2f7Stbbdev typedef LargeObjectCacheImpl< LargeCacheTypeProps > LargeCacheType; 30551c0b2f7Stbbdev typedef LargeObjectCacheImpl< HugeCacheTypeProps > HugeCacheType; 30651c0b2f7Stbbdev 30751c0b2f7Stbbdev // Beginning of largeCache is more actively used and smaller than hugeCache, 30851c0b2f7Stbbdev // so put hugeCache first to prevent false sharing 30951c0b2f7Stbbdev // with LargeObjectCache's predecessor 31051c0b2f7Stbbdev HugeCacheType hugeCache; 31151c0b2f7Stbbdev LargeCacheType largeCache; 31251c0b2f7Stbbdev 31351c0b2f7Stbbdev /* logical time, incremented on each put/get operation 31451c0b2f7Stbbdev To prevent starvation between pools, keep separately for each pool. 31551c0b2f7Stbbdev Overflow is OK, as we only want difference between 31651c0b2f7Stbbdev its current value and some recent. 31751c0b2f7Stbbdev 31851c0b2f7Stbbdev Both malloc and free should increment logical time, as in 31951c0b2f7Stbbdev a different case multiple cached blocks would have same age, 32051c0b2f7Stbbdev and accuracy of predictors suffers. 32151c0b2f7Stbbdev */ 32251c0b2f7Stbbdev std::atomic<uintptr_t> cacheCurrTime; 32351c0b2f7Stbbdev 32451c0b2f7Stbbdev // Memory pool that owns this LargeObjectCache. 32551c0b2f7Stbbdev // strict 1:1 relation, never changed 32651c0b2f7Stbbdev ExtMemoryPool *extMemPool; 32751c0b2f7Stbbdev 32851c0b2f7Stbbdev // Returns artificial bin index, 32951c0b2f7Stbbdev // it's used only during sorting and never saved 33051c0b2f7Stbbdev static int sizeToIdx(size_t size); 33151c0b2f7Stbbdev 33251c0b2f7Stbbdev // Our friends 33351c0b2f7Stbbdev friend class Backend; 33451c0b2f7Stbbdev 33551c0b2f7Stbbdev public: 33651c0b2f7Stbbdev void init(ExtMemoryPool *memPool); 33751c0b2f7Stbbdev 33851c0b2f7Stbbdev // Item accessors 33951c0b2f7Stbbdev void put(LargeMemoryBlock *largeBlock); 34051c0b2f7Stbbdev void putList(LargeMemoryBlock *head); 34151c0b2f7Stbbdev LargeMemoryBlock *get(size_t size); 34251c0b2f7Stbbdev 34351c0b2f7Stbbdev void updateCacheState(DecreaseOrIncrease op, size_t size); 34451c0b2f7Stbbdev bool isCleanupNeededOnRange(uintptr_t range, uintptr_t currTime); 34551c0b2f7Stbbdev 34651c0b2f7Stbbdev // Cleanup operations 34751c0b2f7Stbbdev bool doCleanup(uintptr_t currTime, bool doThreshDecr); 34851c0b2f7Stbbdev bool decreasingCleanup(); 34951c0b2f7Stbbdev bool regularCleanup(); 35051c0b2f7Stbbdev bool cleanAll(); 35151c0b2f7Stbbdev void reset(); 35251c0b2f7Stbbdev 35351c0b2f7Stbbdev void reportStat(FILE *f); 35451c0b2f7Stbbdev #if __TBB_MALLOC_WHITEBOX_TEST 35551c0b2f7Stbbdev size_t getLOCSize() const; 35651c0b2f7Stbbdev size_t getUsedSize() const; 35751c0b2f7Stbbdev #endif 35851c0b2f7Stbbdev 35951c0b2f7Stbbdev // Cache deals with exact-fit sizes, so need to align each size 36051c0b2f7Stbbdev // to the specific bin when put object to cache 36151c0b2f7Stbbdev static size_t alignToBin(size_t size); 36251c0b2f7Stbbdev 36351c0b2f7Stbbdev void setHugeSizeThreshold(size_t value); 36451c0b2f7Stbbdev 36551c0b2f7Stbbdev // Check if we should cache or sieve this size 36651c0b2f7Stbbdev bool sizeInCacheRange(size_t size); 36751c0b2f7Stbbdev 36851c0b2f7Stbbdev uintptr_t getCurrTimeRange(uintptr_t range); 36951c0b2f7Stbbdev void registerRealloc(size_t oldSize, size_t newSize); 37051c0b2f7Stbbdev }; 37151c0b2f7Stbbdev 37251c0b2f7Stbbdev #endif // __TBB_large_objects_H 37351c0b2f7Stbbdev 374