Skip to content

Commit c8576f5

Browse files
igchorvinser52
authored andcommitted
Extend CompressedPtr to work with multiple tiers
Now it's size is 8 bytes intead of 4. Original CompressedPtr stored only some offset with a memory Allocator. For multi-tier implementation, this is not enough. We must also store tierId and when uncompressing, select a proper allocator. An alternative could be to just resign from CompressedPtr but they are leveraged to allow the cache to be mapped to different addresses on shared memory. Changing CompressedPtr impacted CacheItem size - it increased from 32 to 44 bytes.
1 parent e111395 commit c8576f5

File tree

9 files changed

+104
-30
lines changed

9 files changed

+104
-30
lines changed

cachelib/allocator/CacheAllocator.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,8 @@ class CacheAllocator : public CacheBase {
11791179
sizeof(typename RefcountWithFlags::Value) + sizeof(uint32_t) +
11801180
sizeof(uint32_t) + sizeof(KAllocation)) == sizeof(Item),
11811181
"vtable overhead");
1182-
static_assert(32 == sizeof(Item), "item overhead is 32 bytes");
1182+
// XXX: this will fail due to CompressedPtr change
1183+
// static_assert(32 == sizeof(Item), "item overhead is 32 bytes");
11831184

11841185
// make sure there is no overhead in ChainedItem on top of a regular Item
11851186
static_assert(sizeof(Item) == sizeof(ChainedItem),
@@ -1798,7 +1799,7 @@ class CacheAllocator : public CacheBase {
17981799
}
17991800

18001801
typename Item::PtrCompressor createPtrCompressor() const {
1801-
return allocator_[0 /* TODO */]->createPtrCompressor<Item>();
1802+
return typename Item::PtrCompressor(allocator_);
18021803
}
18031804

18041805
// helper utility to throttle and optionally log.

cachelib/allocator/CacheItem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class CACHELIB_PACKED_ATTR CacheItem {
141141
* to be mapped to different addresses on shared memory.
142142
*/
143143
using CompressedPtr = facebook::cachelib::CompressedPtr;
144+
using SingleTierPtrCompressor = MemoryAllocator::SingleTierPtrCompressor<Item>;
144145
using PtrCompressor = MemoryAllocator::PtrCompressor<Item>;
145146

146147
// Get the required size for a cache item given the size of memory

cachelib/allocator/memory/AllocationClass.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ AllocationClass::AllocationClass(ClassId classId,
5050
poolId_(poolId),
5151
allocationSize_(allocSize),
5252
slabAlloc_(s),
53-
freedAllocations_{slabAlloc_.createPtrCompressor<FreeAlloc>()} {
53+
freedAllocations_{slabAlloc_.createSingleTierPtrCompressor<FreeAlloc>()} {
5454
checkState();
5555
}
5656

@@ -102,7 +102,7 @@ AllocationClass::AllocationClass(
102102
currSlab_(s.getSlabForIdx(*object.currSlabIdx_ref())),
103103
slabAlloc_(s),
104104
freedAllocations_(*object.freedAllocationsObject_ref(),
105-
slabAlloc_.createPtrCompressor<FreeAlloc>()),
105+
slabAlloc_.createSingleTierPtrCompressor<FreeAlloc>()),
106106
canAllocate_(*object.canAllocate_ref()) {
107107
if (!slabAlloc_.isRestorable()) {
108108
throw std::logic_error("The allocation class cannot be restored.");
@@ -356,9 +356,9 @@ std::pair<bool, std::vector<void*>> AllocationClass::pruneFreeAllocs(
356356
// allocated slab, release any freed allocations belonging to this slab.
357357
// Set the bit to true if the corresponding allocation is freed, false
358358
// otherwise.
359-
FreeList freeAllocs{slabAlloc_.createPtrCompressor<FreeAlloc>()};
360-
FreeList notInSlab{slabAlloc_.createPtrCompressor<FreeAlloc>()};
361-
FreeList inSlab{slabAlloc_.createPtrCompressor<FreeAlloc>()};
359+
FreeList freeAllocs{slabAlloc_.createSingleTierPtrCompressor<FreeAlloc>()};
360+
FreeList notInSlab{slabAlloc_.createSingleTierPtrCompressor<FreeAlloc>()};
361+
FreeList inSlab{slabAlloc_.createSingleTierPtrCompressor<FreeAlloc>()};
362362

363363
lock_->lock_combine([&]() {
364364
// Take the allocation class free list offline

cachelib/allocator/memory/AllocationClass.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ class AllocationClass {
446446
struct CACHELIB_PACKED_ATTR FreeAlloc {
447447
using CompressedPtr = facebook::cachelib::CompressedPtr;
448448
using PtrCompressor =
449-
facebook::cachelib::PtrCompressor<FreeAlloc, SlabAllocator>;
449+
facebook::cachelib::SingleTierPtrCompressor<FreeAlloc, SlabAllocator>;
450450
SListHook<FreeAlloc> hook_{};
451451
};
452452

cachelib/allocator/memory/CompressedPtr.h

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ namespace cachelib {
2727

2828
class SlabAllocator;
2929

30+
template <typename PtrType, typename AllocatorContainer>
31+
class PtrCompressor;
32+
3033
// the following are for pointer compression for the memory allocator. We
3134
// compress pointers by storing the slab index and the alloc index of the
3235
// allocation inside the slab. With slab worth kNumSlabBits of data, if we
@@ -41,7 +44,7 @@ class SlabAllocator;
4144
// decompress a CompressedPtr than compress a pointer while creating one.
4245
class CACHELIB_PACKED_ATTR CompressedPtr {
4346
public:
44-
using PtrType = uint32_t;
47+
using PtrType = uint64_t;
4548
// Thrift doesn't support unsigned type
4649
using SerializedPtrType = int64_t;
4750

@@ -83,14 +86,14 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
8386
private:
8487
// null pointer representation. This is almost never guaranteed to be a
8588
// valid pointer that we can compress to.
86-
static constexpr PtrType kNull = 0xffffffff;
89+
static constexpr PtrType kNull = 0x00000000ffffffff;
8790

8891
// default construct to null.
8992
PtrType ptr_{kNull};
9093

9194
// create a compressed pointer for a valid memory allocation.
92-
CompressedPtr(uint32_t slabIdx, uint32_t allocIdx)
93-
: ptr_(compress(slabIdx, allocIdx)) {}
95+
CompressedPtr(uint32_t slabIdx, uint32_t allocIdx, TierId tid = 0)
96+
: ptr_(compress(slabIdx, allocIdx, tid)) {}
9497

9598
constexpr explicit CompressedPtr(PtrType ptr) noexcept : ptr_{ptr} {}
9699

@@ -100,40 +103,60 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
100103
static constexpr unsigned int kNumAllocIdxBits =
101104
Slab::kNumSlabBits - Slab::kMinAllocPower;
102105

106+
// Use topmost 32 bits for TierId
107+
// XXX: optimize
108+
static constexpr unsigned int kNumTierIdxOffset = 32;
109+
103110
static constexpr PtrType kAllocIdxMask = ((PtrType)1 << kNumAllocIdxBits) - 1;
104111

112+
// kNumTierIdxBits most significant bits
113+
static constexpr PtrType kTierIdxMask = (((PtrType)1 << kNumTierIdxOffset) - 1) << (NumBits<PtrType>::value - kNumTierIdxOffset);
114+
105115
// Number of bits for the slab index. This will be the top 16 bits of the
106116
// compressed ptr.
107117
static constexpr unsigned int kNumSlabIdxBits =
108-
NumBits<PtrType>::value - kNumAllocIdxBits;
118+
NumBits<PtrType>::value - kNumTierIdxOffset - kNumAllocIdxBits;
109119

110-
// Compress the given slabIdx and allocIdx into a 32-bit compressed
120+
// Compress the given slabIdx and allocIdx into a 64-bit compressed
111121
// pointer.
112-
static PtrType compress(uint32_t slabIdx, uint32_t allocIdx) noexcept {
122+
static PtrType compress(uint32_t slabIdx, uint32_t allocIdx, TierId tid) noexcept {
113123
XDCHECK_LE(allocIdx, kAllocIdxMask);
114124
XDCHECK_LT(slabIdx, (1u << kNumSlabIdxBits) - 1);
115-
return (slabIdx << kNumAllocIdxBits) + allocIdx;
125+
return (static_cast<uint64_t>(tid) << kNumTierIdxOffset) + (slabIdx << kNumAllocIdxBits) + allocIdx;
116126
}
117127

118128
// Get the slab index of the compressed ptr
119129
uint32_t getSlabIdx() const noexcept {
120130
XDCHECK(!isNull());
121-
return static_cast<uint32_t>(ptr_ >> kNumAllocIdxBits);
131+
auto noTierIdPtr = ptr_ & ~kTierIdxMask;
132+
return static_cast<uint32_t>(noTierIdPtr >> kNumAllocIdxBits);
122133
}
123134

124135
// Get the allocation index of the compressed ptr
125136
uint32_t getAllocIdx() const noexcept {
126137
XDCHECK(!isNull());
127-
return static_cast<uint32_t>(ptr_ & kAllocIdxMask);
138+
auto noTierIdPtr = ptr_ & ~kTierIdxMask;
139+
return static_cast<uint32_t>(noTierIdPtr & kAllocIdxMask);
140+
}
141+
142+
uint32_t getTierId() const noexcept {
143+
XDCHECK(!isNull());
144+
return static_cast<uint32_t>(ptr_ >> kNumTierIdxOffset);
145+
}
146+
147+
void setTierId(TierId tid) noexcept {
148+
ptr_ += static_cast<uint64_t>(tid) << kNumTierIdxOffset;
128149
}
129150

130151
friend SlabAllocator;
152+
template <typename CPtrType, typename AllocatorContainer>
153+
friend class PtrCompressor;
131154
};
132155

133156
template <typename PtrType, typename AllocatorT>
134-
class PtrCompressor {
157+
class SingleTierPtrCompressor {
135158
public:
136-
explicit PtrCompressor(const AllocatorT& allocator) noexcept
159+
explicit SingleTierPtrCompressor(const AllocatorT& allocator) noexcept
137160
: allocator_(allocator) {}
138161

139162
const CompressedPtr compress(const PtrType* uncompressed) const {
@@ -144,17 +167,61 @@ class PtrCompressor {
144167
return static_cast<PtrType*>(allocator_.unCompress(compressed));
145168
}
146169

147-
bool operator==(const PtrCompressor& rhs) const noexcept {
170+
bool operator==(const SingleTierPtrCompressor& rhs) const noexcept {
148171
return &allocator_ == &rhs.allocator_;
149172
}
150173

151-
bool operator!=(const PtrCompressor& rhs) const noexcept {
174+
bool operator!=(const SingleTierPtrCompressor& rhs) const noexcept {
152175
return !(*this == rhs);
153176
}
154177

155178
private:
156179
// memory allocator that does the pointer compression.
157180
const AllocatorT& allocator_;
158181
};
182+
183+
template <typename PtrType, typename AllocatorContainer>
184+
class PtrCompressor {
185+
public:
186+
explicit PtrCompressor(const AllocatorContainer& allocators) noexcept
187+
: allocators_(allocators) {}
188+
189+
const CompressedPtr compress(const PtrType* uncompressed) const {
190+
if (uncompressed == nullptr)
191+
return CompressedPtr{};
192+
193+
TierId tid;
194+
for (tid = 0; tid < allocators_.size(); tid++) {
195+
if (allocators_[tid]->isMemoryInAllocator(static_cast<const void*>(uncompressed)))
196+
break;
197+
}
198+
199+
auto cptr = allocators_[tid]->compress(uncompressed);
200+
cptr.setTierId(tid);
201+
202+
return cptr;
203+
}
204+
205+
PtrType* unCompress(const CompressedPtr compressed) const {
206+
if (compressed.isNull()) {
207+
return nullptr;
208+
}
209+
210+
auto &allocator = *allocators_[compressed.getTierId()];
211+
return static_cast<PtrType*>(allocator.unCompress(compressed));
212+
}
213+
214+
bool operator==(const PtrCompressor& rhs) const noexcept {
215+
return &allocators_ == &rhs.allocators_;
216+
}
217+
218+
bool operator!=(const PtrCompressor& rhs) const noexcept {
219+
return !(*this == rhs);
220+
}
221+
222+
private:
223+
// memory allocator that does the pointer compression.
224+
const AllocatorContainer& allocators_;
225+
};
159226
} // namespace cachelib
160227
} // namespace facebook

cachelib/allocator/memory/MemoryAllocator.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,13 @@ class MemoryAllocator {
516516
using CompressedPtr = facebook::cachelib::CompressedPtr;
517517
template <typename PtrType>
518518
using PtrCompressor =
519-
facebook::cachelib::PtrCompressor<PtrType, SlabAllocator>;
519+
facebook::cachelib::PtrCompressor<PtrType,
520+
std::vector<std::unique_ptr<MemoryAllocator>>>;
520521

521522
template <typename PtrType>
522-
PtrCompressor<PtrType> createPtrCompressor() {
523-
return slabAllocator_.createPtrCompressor<PtrType>();
524-
}
523+
using SingleTierPtrCompressor =
524+
facebook::cachelib::PtrCompressor<PtrType,
525+
SlabAllocator>;
525526

526527
// compress a given pointer to a valid allocation made out of this allocator
527528
// through an allocate() or nullptr. Calling this otherwise with invalid

cachelib/allocator/memory/SlabAllocator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ serialization::SlabAllocatorObject SlabAllocator::saveState() {
527527
// for benchmarking purposes.
528528
const unsigned int kMarkerBits = 6;
529529
CompressedPtr SlabAllocator::compressAlt(const void* ptr) const {
530+
// XXX: do we need to set tierId here?
531+
530532
if (ptr == nullptr) {
531533
return CompressedPtr{};
532534
}
@@ -538,6 +540,8 @@ CompressedPtr SlabAllocator::compressAlt(const void* ptr) const {
538540
}
539541

540542
void* SlabAllocator::unCompressAlt(const CompressedPtr cPtr) const {
543+
// XXX: do we need to set tierId here?
544+
541545
if (cPtr.isNull()) {
542546
return nullptr;
543547
}

cachelib/allocator/memory/SlabAllocator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,8 @@ class SlabAllocator {
308308
}
309309

310310
template <typename PtrType>
311-
PtrCompressor<PtrType, SlabAllocator> createPtrCompressor() const {
312-
return PtrCompressor<PtrType, SlabAllocator>(*this);
311+
SingleTierPtrCompressor<PtrType, SlabAllocator> createSingleTierPtrCompressor() const {
312+
return SingleTierPtrCompressor<PtrType, SlabAllocator>(*this);
313313
}
314314

315315
// returns starting address of memory we own.

cachelib/allocator/tests/AllocatorResizeTest.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ class AllocatorResizeTest : public AllocatorTest<AllocatorT> {
10981098
size_t allocBytes = 0;
10991099
for (size_t k = 0; k < expectedIters * Slab::kSize / sz; k++) {
11001100
const auto key = this->getRandomNewKey(alloc, keyLen);
1101-
auto handle = util::allocateAccessible(alloc, poolId, key, sz - 45);
1101+
auto handle = util::allocateAccessible(alloc, poolId, key, sz - 45 - 9 /* TODO: compressed ptr size */);
11021102
if (!handle.get()) {
11031103
break;
11041104
}
@@ -1110,7 +1110,7 @@ class AllocatorResizeTest : public AllocatorTest<AllocatorT> {
11101110
for (size_t k = 0; k < expectedIters * Slab::kSize / sz; k++) {
11111111
const auto key = this->getRandomNewKey(alloc, keyLen);
11121112
size_t allocBytes = 0;
1113-
auto handle = util::allocateAccessible(alloc, poolId, key, sz - 45);
1113+
auto handle = util::allocateAccessible(alloc, poolId, key, sz - 45 - 9 /* TODO: compressed ptr size */);
11141114
allocBytes += handle->getSize();
11151115
}
11161116
}

0 commit comments

Comments
 (0)