Skip to content

Commit e4ce2e7

Browse files
committed
Support for approx free percentage in each allocation class based on upstream AC stats implementation
(fixes getACStats call to initialize extra members of the ACStats struct).
1 parent 2d80fb1 commit e4ce2e7

File tree

11 files changed

+108
-19
lines changed

11 files changed

+108
-19
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2679,6 +2679,11 @@ PoolStats CacheAllocator<CacheTrait>::getPoolStats(PoolId poolId) const {
26792679
return ret;
26802680
}
26812681

2682+
template <typename CacheTrait>
2683+
double CacheAllocator<CacheTrait>::slabsApproxFreePercentage(TierId tid) const {
2684+
return allocator_[tid]->approxFreeSlabsPercentage();
2685+
}
2686+
26822687
template <typename CacheTrait>
26832688
ACStats CacheAllocator<CacheTrait>::getACStats(TierId tid,
26842689
PoolId poolId,
@@ -2688,6 +2693,27 @@ ACStats CacheAllocator<CacheTrait>::getACStats(TierId tid,
26882693

26892694
auto stats = ac.getStats();
26902695
stats.allocLatencyNs = (*stats_.classAllocLatency)[tid][poolId][classId];
2696+
stats.memorySize = ac.getNumSlabs() * Slab::kSize;
2697+
2698+
if (slabsApproxFreePercentage(tid) > 0.0) {
2699+
auto totalMemory = MemoryAllocator::getMemorySize(memoryTierSize(tid));
2700+
auto freeMemory = static_cast<double>(totalMemory) * slabsApproxFreePercentage(tid) / 100.0;
2701+
2702+
// amount of free memory which has the same ratio to entire free memory as
2703+
// this allocation class memory size has to used memory
2704+
auto scaledFreeMemory = static_cast<size_t>(freeMemory * stats.memorySize / totalMemory);
2705+
2706+
auto acAllocatedMemory = (100.0 - ac.approxFreePercentage()) / 100.0 * ac.getNumSlabs() * Slab::kSize;
2707+
auto acMaxAvailableMemory = ac.getNumSlabs() * Slab::kSize + scaledFreeMemory;
2708+
2709+
if (acMaxAvailableMemory == 0) {
2710+
stats.approxFreePercent = 100.0;
2711+
} else {
2712+
stats.approxFreePercent = 100.0 - 100.0 * acAllocatedMemory / acMaxAvailableMemory;
2713+
}
2714+
} else {
2715+
stats.approxFreePercent = ac.approxFreePercentage();
2716+
}
26912717
return stats;
26922718
}
26932719

@@ -3719,6 +3745,10 @@ CacheMemoryStats CacheAllocator<CacheTrait>::getCacheMemoryStats() const {
37193745
size_t configuredCompactCacheSize = std::accumulate(
37203746
ccCachePoolIds.begin(), ccCachePoolIds.end(), 0ULL, addSize);
37213747

3748+
std::vector<double> slabsApproxFreePercentages;
3749+
for (TierId tid = 0; tid < getNumTiers(); ++tid)
3750+
slabsApproxFreePercentages.push_back(slabsApproxFreePercentage(tid));
3751+
37223752
return CacheMemoryStats{totalCacheSize,
37233753
totalCacheSize,
37243754
configuredTotalCacheSize,
@@ -3729,7 +3759,8 @@ CacheMemoryStats CacheAllocator<CacheTrait>::getCacheMemoryStats() const {
37293759
allocator_[currentTier()]->getUnreservedMemorySize(),
37303760
nvmCache_ ? nvmCache_->getSize() : 0,
37313761
util::getMemAvailable(),
3732-
util::getRSSBytes()};
3762+
util::getRSSBytes(),
3763+
slabsApproxFreePercentages};
37333764
}
37343765

37353766
template <typename CacheTrait>

cachelib/allocator/CacheAllocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,8 @@ class CacheAllocator : public CacheBase {
13201320
#pragma GCC diagnostic pop
13211321

13221322
private:
1323+
double slabsApproxFreePercentage(TierId tid) const;
1324+
13231325
// wrapper around Item's refcount and active handle tracking
13241326
FOLLY_ALWAYS_INLINE RefcountWithFlags::incResult incRef(Item& it, bool failIfMoving);
13251327
FOLLY_ALWAYS_INLINE RefcountWithFlags::Value decRef(Item& it);

cachelib/allocator/CacheStats.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ struct CacheMemoryStats {
559559

560560
// returne usable portion of the cache size
561561
size_t usableRamCacheSize() const { return ramCacheSize; }
562+
563+
// percentage of free slabs
564+
std::vector<double> slabsApproxFreePercentages{0.0};
562565
};
563566

564567
// Stats for compact cache

cachelib/allocator/memory/AllocationClass.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ AllocationClass::AllocationClass(ClassId classId,
5151
allocationSize_(allocSize),
5252
slabAlloc_(s),
5353
freedAllocations_{slabAlloc_.createSingleTierPtrCompressor<FreeAlloc>()} {
54+
curAllocatedSlabs_ = allocatedSlabs_.size();
5455
checkState();
5556
}
5657

@@ -87,6 +88,12 @@ void AllocationClass::checkState() const {
8788
"Current allocation slab {} is not in allocated slabs list",
8889
currSlab_));
8990
}
91+
92+
if (curAllocatedSlabs_ != allocatedSlabs_.size()) {
93+
throw std::invalid_argument(folly::sformat(
94+
"Mismatch in allocated slabs numbers"
95+
));
96+
}
9097
}
9198

9299
// TODO(stuclar): Add poolId to the metadata to be serialized when cache shuts
@@ -116,10 +123,12 @@ AllocationClass::AllocationClass(
116123
freeSlabs_.push_back(slabAlloc_.getSlabForIdx(freeSlabIdx));
117124
}
118125

126+
curAllocatedSlabs_ = allocatedSlabs_.size();
119127
checkState();
120128
}
121129

122130
void AllocationClass::addSlabLocked(Slab* slab) {
131+
curAllocatedSlabs_.fetch_add(1, std::memory_order_relaxed);
123132
canAllocate_ = true;
124133
auto header = slabAlloc_.getSlabHeader(slab);
125134
header->classId = classId_;
@@ -168,6 +177,7 @@ void* AllocationClass::allocateLocked() {
168177
}
169178

170179
XDCHECK(canAllocate_);
180+
curAllocatedSize_.fetch_add(getAllocSize(), std::memory_order_relaxed);
171181

172182
// grab from the free list if possible.
173183
if (!freedAllocations_.empty()) {
@@ -270,6 +280,7 @@ SlabReleaseContext AllocationClass::startSlabRelease(
270280
slab, getId()));
271281
}
272282
*allocIt = allocatedSlabs_.back();
283+
curAllocatedSlabs_.fetch_sub(1, std::memory_order_relaxed);
273284
allocatedSlabs_.pop_back();
274285

275286
// if slab is being carved currently, then update slabReleaseAllocMap
@@ -511,6 +522,7 @@ void AllocationClass::abortSlabRelease(const SlabReleaseContext& context) {
511522
}
512523
slabReleaseAllocMap_.erase(slabPtrVal);
513524
allocatedSlabs_.push_back(const_cast<Slab*>(slab));
525+
curAllocatedSlabs_.fetch_add(1, std::memory_order_relaxed);
514526
// restore the classId and allocSize
515527
header->classId = classId_;
516528
header->allocSize = allocationSize_;
@@ -661,6 +673,8 @@ void AllocationClass::free(void* memory) {
661673
freedAllocations_.insert(*reinterpret_cast<FreeAlloc*>(memory));
662674
canAllocate_ = true;
663675
});
676+
677+
curAllocatedSize_.fetch_sub(getAllocSize(), std::memory_order_relaxed);
664678
}
665679

666680
serialization::AllocationClassObject AllocationClass::saveState() const {
@@ -699,8 +713,8 @@ ACStats AllocationClass::getStats() const {
699713
const unsigned long long nFreedAllocs = freedAllocations_.size();
700714
const unsigned long long nActiveAllocs =
701715
nSlabsAllocated * perSlab - nFreedAllocs - freeAllocsInCurrSlab;
702-
return {allocationSize_, perSlab, nSlabsAllocated, freeSlabs_.size(),
703-
nFreedAllocs, nActiveAllocs, isFull()};
716+
return {allocationSize_, perSlab, 0, nSlabsAllocated, freeSlabs_.size(),
717+
nFreedAllocs, nActiveAllocs, isFull(), util::RollingStats{}, 0.0};
704718
});
705719
}
706720

@@ -723,3 +737,12 @@ std::vector<bool>& AllocationClass::getSlabReleaseAllocMapLocked(
723737
const auto slabPtrVal = getSlabPtrValue(slab);
724738
return slabReleaseAllocMap_.at(slabPtrVal);
725739
}
740+
741+
double AllocationClass::approxFreePercentage() const {
742+
if (getNumSlabs() == 0) {
743+
return 100.0;
744+
}
745+
746+
return 100.0 - 100.0 * static_cast<double>(curAllocatedSize_.load(std::memory_order_relaxed)) /
747+
static_cast<double>(getNumSlabs() * Slab::kSize);
748+
}

cachelib/allocator/memory/AllocationClass.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ class AllocationClass {
9494
return static_cast<unsigned int>(Slab::kSize / allocationSize_);
9595
}
9696

97+
// total number of slabs under this AllocationClass.
98+
unsigned int getNumSlabs() const {
99+
return curAllocatedSlabs_.load(std::memory_order_relaxed);
100+
}
101+
97102
// fetch stats about this allocation class.
98103
ACStats getStats() const;
99104

@@ -308,6 +313,9 @@ class AllocationClass {
308313
// @throw std::logic_error if the object state can not be serialized
309314
serialization::AllocationClassObject saveState() const;
310315

316+
// approximate percent of free memory inside this allocation class
317+
double approxFreePercentage() const;
318+
311319
private:
312320
// check if the state of the AllocationClass is valid and if not, throws an
313321
// std::invalid_argument exception. This is intended for use in
@@ -467,6 +475,12 @@ class AllocationClass {
467475

468476
std::atomic<int64_t> activeReleases_{0};
469477

478+
// amount of memory currently allocated by this AC
479+
std::atomic<size_t> curAllocatedSize_{0};
480+
481+
// total number of slabs under this AllocationClass.
482+
std::atomic<size_t> curAllocatedSlabs_{0};
483+
470484
// stores the list of outstanding allocations for a given slab. This is
471485
// created when we start a slab release process and if there are any active
472486
// allocaitons need to be marked as free.

cachelib/allocator/memory/MemoryAllocator.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,14 @@ class MemoryAllocator {
416416
return memoryPoolManager_.getPoolIds();
417417
}
418418

419+
double approxFreeSlabsPercentage() const {
420+
if (slabAllocator_.getNumUsableAndAdvisedSlabs() == 0)
421+
return 100.0;
422+
423+
return 100.0 - 100.0 * static_cast<double>(slabAllocator_.approxNumSlabsAllocated()) /
424+
slabAllocator_.getNumUsableAndAdvisedSlabs();
425+
}
426+
419427
// fetches the memory pool for the id if one exists. This is purely to get
420428
// information out of the pool.
421429
//

cachelib/allocator/memory/MemoryAllocatorStats.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ struct ACStats {
3333
// number of allocations per slab
3434
unsigned long long allocsPerSlab;
3535

36+
// size of memory assigned to this allocation class
37+
unsigned long long memorySize;
38+
3639
// number of slabs that are currently used for active allocations.
3740
unsigned long long usedSlabs;
3841

@@ -51,6 +54,9 @@ struct ACStats {
5154
// Rolling allocation latency (in ns)
5255
util::RollingStats allocLatencyNs;
5356

57+
// percent of free memory in this class
58+
double approxFreePercent{0.0};
59+
5460
constexpr unsigned long long totalSlabs() const noexcept {
5561
return freeSlabs + usedSlabs;
5662
}

cachelib/allocator/memory/SlabAllocator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ Slab* SlabAllocator::makeNewSlab(PoolId id) {
360360
return nullptr;
361361
}
362362

363+
numSlabsAllocated_.fetch_add(1, std::memory_order_relaxed);
364+
363365
memoryPoolSize_[id] += sizeof(Slab);
364366
// initialize the header for the slab.
365367
initializeHeader(slab, id);
@@ -375,6 +377,8 @@ void SlabAllocator::freeSlab(Slab* slab) {
375377
}
376378

377379
memoryPoolSize_[header->poolId] -= sizeof(Slab);
380+
numSlabsAllocated_.fetch_sub(1, std::memory_order_relaxed);
381+
378382
// grab the lock
379383
LockHolder l(lock_);
380384
freeSlabs_.push_back(slab);

cachelib/allocator/memory/SlabAllocator.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,13 @@ class SlabAllocator {
329329
memorySize_);
330330
}
331331

332-
private:
332+
size_t approxNumSlabsAllocated() const {
333+
return numSlabsAllocated_.load(std::memory_order_relaxed);
334+
}
335+
336+
private:
337+
std::atomic<size_t> numSlabsAllocated_{0};
338+
333339
// null Slab* presenttation. With 4M Slab size, a valid slab index would never
334340
// reach 2^16 - 1;
335341
static constexpr SlabIdx kNullSlabIdx = std::numeric_limits<SlabIdx>::max();

cachelib/cachebench/cache/Cache-inl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,7 @@ Stats Cache<Allocator>::getStats() const {
634634
const auto rebalanceStats = cache_->getSlabReleaseStats();
635635
const auto navyStats = cache_->getNvmCacheStatsMap().toMap();
636636

637+
ret.slabsApproxFreePercentages = cache_->getCacheMemoryStats().slabsApproxFreePercentages;
637638
ret.allocationClassStats = allocationClassStats;
638639
ret.numEvictions = aggregate.numEvictions();
639640
ret.numItems = aggregate.numItems();

0 commit comments

Comments
 (0)