@@ -27,18 +27,29 @@ namespace cachelib {
2727
2828class SlabAllocator ;
2929
30- // the following are for pointer compression for the memory allocator. We
31- // compress pointers by storing the slab index and the alloc index of the
32- // allocation inside the slab. With slab worth kNumSlabBits of data, if we
33- // have the min allocation size as 64 bytes, that requires kNumSlabBits - 6
34- // bits for storing the alloc index. This leaves the remaining (32 -
35- // (kNumSlabBits - 6)) bits for the slab index. Hence we can index 256 GiB
36- // of memory in slabs and index anything more than 64 byte allocations inside
37- // the slab using a 32 bit representation.
38- //
3930// This CompressedPtr makes decompression fast by staying away from division and
4031// modulo arithmetic and doing those during the compression time. We most often
41- // decompress a CompressedPtr than compress a pointer while creating one.
32+ // decompress a CompressedPtr than compress a pointer while creating one. This
33+ // is used for pointer compression by the memory allocator.
34+
35+ // We compress pointers by storing the tier index, slab index and alloc index of
36+ // the allocation inside the slab.
37+
38+ // In original design (without memory tiers):
39+ // Each slab addresses 22 bits of allocations (kNumSlabBits). This is split into
40+ // allocation index and allocation size. If we have the min allocation size of
41+ // 64 bytes (kMinAllocPower = 6 bits), remaining kNumSlabBits(22) -
42+ // kMinAllocPower(6) = 16 bits for storing the alloc index. This leaves the
43+ // remaining 32 - (kNumSlabBits - kMinAllocPower) = 16 bits for the slab
44+ // index. Hence we can index 256 GiB of memory.
45+
46+ // In multi-tier design:
47+ // kNumSlabIds and kMinAllocPower remains unchanged. The tier id occupies the
48+ // 32nd bit only since its value cannot exceed kMaxTiers(2). This leaves the
49+ // remaining 32 - (kNumSlabBits - kMinAllocPower) - 1 bit for tier id = 15 bits
50+ // for the slab index. Hence we can index 128 GiB of memory per tier in
51+ // multi-tier configuration.
52+
4253class CACHELIB_PACKED_ATTR CompressedPtr {
4354 public:
4455 using PtrType = uint32_t ;
@@ -62,9 +73,10 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
6273 return static_cast <uint32_t >(1 ) << (Slab::kMinAllocPower );
6374 }
6475
65- // maximum adressable memory for pointer compression to work.
76+ // maximum addressable memory for pointer compression to work.
6677 static constexpr size_t getMaxAddressableSize () noexcept {
67- return static_cast <size_t >(1 ) << (kNumSlabIdxBits + Slab::kNumSlabBits );
78+ return static_cast <size_t >(1 )
79+ << (numSlabIdxBits (false ) + Slab::kNumSlabBits );
6880 }
6981
7082 // default construct to nullptr.
@@ -89,8 +101,11 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
89101 PtrType ptr_{kNull };
90102
91103 // create a compressed pointer for a valid memory allocation.
92- CompressedPtr (uint32_t slabIdx, uint32_t allocIdx)
93- : ptr_(compress(slabIdx, allocIdx)) {}
104+ CompressedPtr (uint32_t slabIdx,
105+ uint32_t allocIdx,
106+ bool isMultiTiered,
107+ TierId tid = 0 )
108+ : ptr_(compress(slabIdx, allocIdx, isMultiTiered, tid)) {}
94109
95110 constexpr explicit CompressedPtr (PtrType ptr) noexcept : ptr_{ptr} {}
96111
@@ -100,33 +115,63 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
100115 static constexpr unsigned int kNumAllocIdxBits =
101116 Slab::kNumSlabBits - Slab::kMinAllocPower ;
102117
118+ // Use 32nd bit position for TierId
119+ static constexpr unsigned int kNumTierIdxOffset = 31 ;
120+
103121 static constexpr PtrType kAllocIdxMask = ((PtrType)1 << kNumAllocIdxBits ) - 1 ;
104122
105- // Number of bits for the slab index. This will be the top 16 bits of the
106- // compressed ptr.
107- static constexpr unsigned int kNumSlabIdxBits =
108- NumBits<PtrType>::value - kNumAllocIdxBits ;
123+ // kNumTierIdxBits most significant bits
124+ static constexpr PtrType kTierIdxMask = (PtrType)1 << kNumTierIdxOffset ;
125+
126+ // Number of bits for the slab index.
127+ // If CacheLib is single tiered, slab index will be the top 16 bits
128+ // of the compressed ptr.
129+ // Else if CacheLib is multi-tiered, the topmost 32nd bit will be
130+ // reserved for tier id. The following 15 bits will be reserved for
131+ // the slab index.
132+ static constexpr unsigned int numSlabIdxBits (bool isMultiTiered) {
133+ return kNumTierIdxOffset - kNumAllocIdxBits + (!isMultiTiered);
134+ }
109135
110136 // Compress the given slabIdx and allocIdx into a 32-bit compressed
111137 // pointer.
112- static PtrType compress (uint32_t slabIdx, uint32_t allocIdx) noexcept {
138+ static PtrType compress (uint32_t slabIdx,
139+ uint32_t allocIdx,
140+ bool isMultiTiered,
141+ TierId tid) noexcept {
113142 XDCHECK_LE (allocIdx, kAllocIdxMask );
114- XDCHECK_LT (slabIdx, (1u << kNumSlabIdxBits ) - 1 );
115- return (slabIdx << kNumAllocIdxBits ) + allocIdx;
143+ XDCHECK_LT (slabIdx, (1u << numSlabIdxBits (isMultiTiered)) - 1 );
144+ if (!isMultiTiered) {
145+ return (slabIdx << kNumAllocIdxBits ) + allocIdx;
146+ }
147+ return (static_cast <uint32_t >(tid) << kNumTierIdxOffset ) +
148+ (slabIdx << kNumAllocIdxBits ) + allocIdx;
116149 }
117150
118151 // Get the slab index of the compressed ptr
119- uint32_t getSlabIdx () const noexcept {
152+ uint32_t getSlabIdx (bool isMultiTiered ) const noexcept {
120153 XDCHECK (!isNull ());
121- return static_cast <uint32_t >(ptr_ >> kNumAllocIdxBits );
154+ auto noTierIdPtr = isMultiTiered ? ptr_ & ~kTierIdxMask : ptr_;
155+ return static_cast <uint32_t >(noTierIdPtr >> kNumAllocIdxBits );
122156 }
123157
124158 // Get the allocation index of the compressed ptr
125159 uint32_t getAllocIdx () const noexcept {
126160 XDCHECK (!isNull ());
161+ // Note: tid check not required in ptr_ since only
162+ // the lower 16 bits are being read here.
127163 return static_cast <uint32_t >(ptr_ & kAllocIdxMask );
128164 }
129165
166+ uint32_t getTierId (bool isMultiTiered) const noexcept {
167+ XDCHECK (!isNull ());
168+ return isMultiTiered ? static_cast <uint32_t >(ptr_ >> kNumTierIdxOffset ) : 0 ;
169+ }
170+
171+ void setTierId (TierId tid) noexcept {
172+ ptr_ += static_cast <uint32_t >(tid) << kNumTierIdxOffset ;
173+ }
174+
130175 friend SlabAllocator;
131176};
132177
@@ -137,11 +182,12 @@ class PtrCompressor {
137182 : allocator_(allocator) {}
138183
139184 const CompressedPtr compress (const PtrType* uncompressed) const {
140- return allocator_.compress (uncompressed);
185+ return allocator_.compress (uncompressed, false /* isMultiTiered */ );
141186 }
142187
143188 PtrType* unCompress (const CompressedPtr compressed) const {
144- return static_cast <PtrType*>(allocator_.unCompress (compressed));
189+ return static_cast <PtrType*>(
190+ allocator_.unCompress (compressed, false /* isMultiTiered */ ));
145191 }
146192
147193 bool operator ==(const PtrCompressor& rhs) const noexcept {
0 commit comments