@@ -27,18 +27,22 @@ 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- //
30+ template <typename PtrType, typename AllocatorContainer>
31+ class PtrCompressor ;
32+
3933// This CompressedPtr makes decompression fast by staying away from division and
40- // modulo arithmetic and doing those during the compression time. We most often
41- // decompress a CompressedPtr than compress a pointer while creating one.
34+ // modulo arithmetic and doing those during the compression time. We most often
35+ // decompress a CompressedPtr than compress a pointer while creating one. This
36+ // is used for pointer compression by the memory allocator.
37+
38+ // We compress pointers by storing the tier index, slab index and alloc index of
39+ // the allocation inside the slab. With slab worth kNumSlabBits (22 bits) of data,
40+ // if we have the min allocation size as 64 bytes, that requires kNumSlabBits - 6
41+ // = 16 bits for storing the alloc index. The tier id occupies the 32nd bit only
42+ // since its value cannot exceed kMaxTiers (2). This leaves the remaining
43+ // (32 - (kNumSlabBits - 6) - 1 bit for tier id) = 15 bits for the slab index.
44+ // Hence we can index 128 GiB of memory in slabs per tier and index anything more
45+ // than 64 byte allocations inside the slab using a 32 bit representation.
4246class CACHELIB_PACKED_ATTR CompressedPtr {
4347 public:
4448 using PtrType = uint32_t ;
@@ -62,9 +66,9 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
6266 return static_cast <uint32_t >(1 ) << (Slab::kMinAllocPower );
6367 }
6468
65- // maximum adressable memory for pointer compression to work.
69+ // maximum addressable memory for pointer compression to work.
6670 static constexpr size_t getMaxAddressableSize () noexcept {
67- return static_cast <size_t >(1 ) << (kNumSlabIdxBits + Slab::kNumSlabBits );
71+ return static_cast <size_t >(1 ) << (kNumSlabIdxBits + Slab::kNumSlabBits + 1 );
6872 }
6973
7074 // default construct to nullptr.
@@ -89,8 +93,8 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
8993 PtrType ptr_{kNull };
9094
9195 // create a compressed pointer for a valid memory allocation.
92- CompressedPtr (uint32_t slabIdx, uint32_t allocIdx)
93- : ptr_(compress(slabIdx, allocIdx)) {}
96+ CompressedPtr (uint32_t slabIdx, uint32_t allocIdx, bool isMultiTiered, TierId tid = 0 )
97+ : ptr_(compress(slabIdx, allocIdx, isMultiTiered, tid )) {}
9498
9599 constexpr explicit CompressedPtr (PtrType ptr) noexcept : ptr_{ptr} {}
96100
@@ -100,31 +104,52 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
100104 static constexpr unsigned int kNumAllocIdxBits =
101105 Slab::kNumSlabBits - Slab::kMinAllocPower ;
102106
107+ // Use 32nd bit position for TierId
108+ static constexpr unsigned int kNumTierIdxOffset = 31 ;
109+
103110 static constexpr PtrType kAllocIdxMask = ((PtrType)1 << kNumAllocIdxBits ) - 1 ;
104111
112+ // kNumTierIdxBits most significant bits
113+ static constexpr PtrType kTierIdxMask = (PtrType)1 << 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+ kNumTierIdxOffset - kNumAllocIdxBits ;
109119
110120 // Compress the given slabIdx and allocIdx into a 32-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, bool isMultiTiered, TierId tid ) noexcept {
113123 XDCHECK_LE (allocIdx, kAllocIdxMask );
124+ if (!isMultiTiered) {
125+ XDCHECK_LT (slabIdx, (1u << (kNumSlabIdxBits +1 )) - 1 );
126+ return (slabIdx << kNumAllocIdxBits ) + allocIdx;
127+ }
114128 XDCHECK_LT (slabIdx, (1u << kNumSlabIdxBits ) - 1 );
115129 return (slabIdx << kNumAllocIdxBits ) + allocIdx;
116130 }
117131
118132 // Get the slab index of the compressed ptr
119- uint32_t getSlabIdx () const noexcept {
133+ uint32_t getSlabIdx (bool isMultiTiered ) const noexcept {
120134 XDCHECK (!isNull ());
121- return static_cast <uint32_t >(ptr_ >> kNumAllocIdxBits );
135+ auto noTierIdPtr = isMultiTiered ? ptr_ & ~kTierIdxMask : ptr_;
136+ return static_cast <uint32_t >(noTierIdPtr >> kNumAllocIdxBits );
122137 }
123138
124139 // Get the allocation index of the compressed ptr
125- uint32_t getAllocIdx () const noexcept {
140+ uint32_t getAllocIdx (bool isMultiTiered ) const noexcept {
126141 XDCHECK (!isNull ());
127- return static_cast <uint32_t >(ptr_ & kAllocIdxMask );
142+ auto noTierIdPtr = isMultiTiered ? ptr_ & ~kTierIdxMask : ptr_;
143+ return static_cast <uint32_t >(noTierIdPtr & kAllocIdxMask );
144+ }
145+
146+ uint32_t getTierId (bool isMultiTiered) const noexcept {
147+ XDCHECK (!isNull ());
148+ return isMultiTiered ? static_cast <uint32_t >(ptr_ >> kNumTierIdxOffset ) : 0 ;
149+ }
150+
151+ void setTierId (TierId tid) noexcept {
152+ ptr_ += static_cast <uint64_t >(tid) << kNumTierIdxOffset ;
128153 }
129154
130155 friend SlabAllocator;
@@ -137,11 +162,57 @@ class PtrCompressor {
137162 : allocator_(allocator) {}
138163
139164 const CompressedPtr compress (const PtrType* uncompressed) const {
140- return allocator_.compress (uncompressed);
165+ return allocator_.compress (uncompressed, false );
166+ }
167+
168+ PtrType* unCompress (const CompressedPtr compressed) const {
169+ return static_cast <PtrType*>(allocator_.unCompress (compressed, false ));
170+ }
171+
172+ bool operator ==(const SingleTierPtrCompressor& rhs) const noexcept {
173+ return &allocator_ == &rhs.allocator_ ;
174+ }
175+
176+ bool operator !=(const SingleTierPtrCompressor& rhs) const noexcept {
177+ return !(*this == rhs);
178+ }
179+
180+ private:
181+ // memory allocator that does the pointer compression.
182+ const AllocatorT& allocator_;
183+ };
184+
185+ template <typename PtrType, typename AllocatorContainer>
186+ class PtrCompressor {
187+ public:
188+ explicit PtrCompressor (const AllocatorContainer& allocators) noexcept
189+ : allocators_(allocators) {}
190+
191+ const CompressedPtr compress (const PtrType* uncompressed) const {
192+ if (uncompressed == nullptr )
193+ return CompressedPtr{};
194+
195+ TierId tid;
196+ for (tid = 0 ; tid < allocators_.size (); tid++) {
197+ if (allocators_[tid]->isMemoryInAllocator (static_cast <const void *>(uncompressed)))
198+ break ;
199+ }
200+
201+ bool isMultiTiered = allocators_.size () > 1 ;
202+ auto cptr = allocators_[tid]->compress (uncompressed, isMultiTiered);
203+ if (isMultiTiered) { // config has multiple tiers
204+ cptr.setTierId (tid);
205+ }
206+ return cptr;
141207 }
142208
143209 PtrType* unCompress (const CompressedPtr compressed) const {
144- return static_cast <PtrType*>(allocator_.unCompress (compressed));
210+ if (compressed.isNull ()) {
211+ return nullptr ;
212+ }
213+ bool isMultiTiered = allocators_.size () > 1 ;
214+ auto &allocator = *allocators_[compressed.getTierId (isMultiTiered)];
215+ return static_cast <PtrType*>(allocator.unCompress (compressed, isMultiTiered));
145216 }
146217
147218 bool operator ==(const PtrCompressor& rhs) const noexcept {
0 commit comments