1818
1919#include  < folly/logging/xlog.h> 
2020
21+ #include  < deque> 
22+ #include  < forward_list> 
23+ #include  < list> 
24+ #include  < map> 
2125#include  < memory> 
26+ #include  < queue> 
27+ #include  < set> 
28+ #include  < stack> 
29+ #include  < string> 
30+ #include  < tuple> 
31+ #include  < type_traits> 
32+ #include  < unordered_map> 
33+ #include  < unordered_set> 
34+ #include  < utility> 
35+ #include  < vector> 
2236
2337#include  " cachelib/allocator/memory/Slab.h" 
2438
39+ //  specialize a type for all of the STL containers.
40+ namespace  IsContainerImpl  {
41+ template  <typename  T>
42+ struct  IsContainer  : std::false_type {};
43+ template  <typename  T, std::size_t  N>
44+ struct  IsContainer <std::array<T, N>> : std::true_type {};
45+ template  <typename ... Args>
46+ struct  IsContainer <std::vector<Args...>> : std::true_type {};
47+ template  <typename ... Args>
48+ struct  IsContainer <std::deque<Args...>> : std::true_type {};
49+ template  <typename ... Args>
50+ struct  IsContainer <std::list<Args...>> : std::true_type {};
51+ template  <typename ... Args>
52+ struct  IsContainer <std::forward_list<Args...>> : std::true_type {};
53+ template  <typename ... Args>
54+ struct  IsContainer <std::set<Args...>> : std::true_type {};
55+ template  <typename ... Args>
56+ struct  IsContainer <std::multiset<Args...>> : std::true_type {};
57+ template  <typename ... Args>
58+ struct  IsContainer <std::map<Args...>> : std::true_type {};
59+ template  <typename ... Args>
60+ struct  IsContainer <std::multimap<Args...>> : std::true_type {};
61+ template  <typename ... Args>
62+ struct  IsContainer <std::unordered_set<Args...>> : std::true_type {};
63+ template  <typename ... Args>
64+ struct  IsContainer <std::unordered_multiset<Args...>> : std::true_type {};
65+ template  <typename ... Args>
66+ struct  IsContainer <std::unordered_map<Args...>> : std::true_type {};
67+ template  <typename ... Args>
68+ struct  IsContainer <std::unordered_multimap<Args...>> : std::true_type {};
69+ template  <typename ... Args>
70+ struct  IsContainer <std::stack<Args...>> : std::true_type {};
71+ template  <typename ... Args>
72+ struct  IsContainer <std::queue<Args...>> : std::true_type {};
73+ template  <typename ... Args>
74+ struct  IsContainer <std::priority_queue<Args...>> : std::true_type {};
75+ } //  namespace IsContainerImpl
76+ 
77+ //  type trait to utilize the implementation type traits as well as decay the
78+ //  type
79+ template  <typename  T>
80+ struct  IsContainer  {
81+   static  constexpr  bool  const  value =
82+       IsContainerImpl::IsContainer<std::decay_t <T>>::value;
83+ };
84+ 
2585namespace  facebook  {
2686namespace  cachelib  {
2787
@@ -31,20 +91,22 @@ template <typename PtrType, typename AllocatorContainer>
3191class  PtrCompressor ;
3292
3393//  the following are for pointer compression for the memory allocator.  We
34- //  compress pointers by storing the slab index and the alloc index of the
35- //  allocation inside the slab. With slab worth kNumSlabBits of data, if we
36- //  have the min allocation size as 64 bytes, that requires kNumSlabBits - 6
37- //  bits for storing the alloc index. This leaves the remaining (32 -
38- //  (kNumSlabBits - 6)) bits for the slab index.  Hence we can index 256 GiB
39- //  of memory in slabs and index anything more than 64 byte allocations inside
40- //  the slab using a 32 bit representation.
94+ //  compress pointers by storing the tier index, slab index and alloc index
95+ //  of the allocation inside the slab. With slab worth kNumSlabBits (22 bits)
96+ //  of data, if we have the min allocation size as 64 bytes, that requires
97+ //  kNumSlabBits - 6 = 16 bits for storing the alloc index. The tier id
98+ //  occupies the 32nd bit only since its value cannot exceed kMaxTiers (2).
99+ //  This leaves the remaining (32 -(kNumSlabBits - 6) - 1 bit for tier id) =
100+ //  15 bits for the slab index. Hence we can index 128 GiB of memory in slabs
101+ //  per tier and index anything more than 64 byte allocations inside the slab
102+ //  using a 32 bit representation.
41103// 
42104//  This CompressedPtr makes decompression fast by staying away from division and
43105//  modulo arithmetic and doing those during the compression time. We most often
44106//  decompress a CompressedPtr than compress a pointer while creating one.
45107class  CACHELIB_PACKED_ATTR  CompressedPtr {
46108 public: 
47-   using  PtrType = uint64_t ;
109+   using  PtrType = uint32_t ;
48110  //  Thrift doesn't support unsigned type
49111  using  SerializedPtrType = int64_t ;
50112
@@ -103,26 +165,28 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
103165  static  constexpr  unsigned  int  kNumAllocIdxBits  =
104166      Slab::kNumSlabBits  - Slab::kMinAllocPower ;
105167
106-   //  Use topmost 32 bits for TierId
107-   //  XXX: optimize
108-   static  constexpr  unsigned  int  kNumTierIdxOffset  = 32 ;
168+   //  Use the top bit for tier id
169+   static  constexpr  unsigned  int  kNumTierIdxOffset  = 31 ;
109170
110171  static  constexpr  PtrType kAllocIdxMask  = ((PtrType)1  << kNumAllocIdxBits ) - 1 ;
111172
112173  //  kNumTierIdxBits most significant bits
113-   static  constexpr  PtrType kTierIdxMask  = ((( PtrType)1  << kNumTierIdxOffset ) -  1 ) << (NumBits<PtrType>::value -  kNumTierIdxOffset ) ;
174+   static  constexpr  PtrType kTierIdxMask  = (PtrType)1  << kNumTierIdxOffset ;
114175
115-   //  Number of bits for the slab index. This will be the top 16  bits of the
176+   //  Number of bits for the slab index. This will be the 16th - 31st  bits of the
116177  //  compressed ptr.
117178  static  constexpr  unsigned  int  kNumSlabIdxBits  =
118-       NumBits<PtrType>::value -  kNumTierIdxOffset  - kNumAllocIdxBits ;  
179+       kNumTierIdxOffset  - kNumAllocIdxBits ;
119180
120181  //  Compress the given slabIdx and allocIdx into a 64-bit compressed
121182  //  pointer.
122-   static  PtrType compress (uint32_t  slabIdx, uint32_t  allocIdx, TierId tid) noexcept  {
183+   static  PtrType compress (uint32_t  slabIdx,
184+                           uint32_t  allocIdx,
185+                           TierId tid) noexcept  {
123186    XDCHECK_LE (allocIdx, kAllocIdxMask );
124187    XDCHECK_LT (slabIdx, (1u  << kNumSlabIdxBits ) - 1 );
125-     return  (static_cast <uint64_t >(tid) << kNumTierIdxOffset ) + (slabIdx << kNumAllocIdxBits ) + allocIdx;
188+     return  (static_cast <uint64_t >(tid) << kNumTierIdxOffset ) +
189+            (slabIdx << kNumAllocIdxBits ) + allocIdx;
126190  }
127191
128192  //  Get the slab index of the compressed ptr
@@ -153,62 +217,44 @@ class CACHELIB_PACKED_ATTR CompressedPtr {
153217  friend  class  PtrCompressor ;
154218};
155219
156- template  <typename  PtrType, typename  AllocatorT>
157- class  SingleTierPtrCompressor  {
158-  public: 
159-   explicit  SingleTierPtrCompressor (const  AllocatorT& allocator) noexcept 
160-       : allocator_(allocator) {}
161- 
162-   const  CompressedPtr compress (const  PtrType* uncompressed) const  {
163-     return  allocator_.compress (uncompressed);
164-   }
165- 
166-   PtrType* unCompress (const  CompressedPtr compressed) const  {
167-     return  static_cast <PtrType*>(allocator_.unCompress (compressed));
168-   }
169- 
170-   bool  operator ==(const  SingleTierPtrCompressor& rhs) const  noexcept  {
171-     return  &allocator_ == &rhs.allocator_ ;
172-   }
173- 
174-   bool  operator !=(const  SingleTierPtrCompressor& rhs) const  noexcept  {
175-     return  !(*this  == rhs);
176-   }
177- 
178-  private: 
179-   //  memory allocator that does the pointer compression.
180-   const  AllocatorT& allocator_;
181- };
182- 
183220template  <typename  PtrType, typename  AllocatorContainer>
184221class  PtrCompressor  {
185222 public: 
186223  explicit  PtrCompressor (const  AllocatorContainer& allocators) noexcept 
187-       : allocators_(allocators) {}
224+       : allocators_(allocators),
225+         isContainer_(IsContainer<decltype (allocators)>::value) {}
188226
189227  const  CompressedPtr compress (const  PtrType* uncompressed) const  {
190-     if  (uncompressed == nullptr )
228+     if  (uncompressed == nullptr ) { 
191229      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 ;
197230    }
198- 
199-     auto  cptr = allocators_[tid]->compress (uncompressed);
200-     cptr.setTierId (tid);
201- 
202-     return  cptr;
231+     if  (isContainer_) {
232+       TierId tid;
233+       for  (tid = 0 ; tid < allocators_.size (); tid++) {
234+         if  (allocators_[tid]->isMemoryInAllocator (
235+                 static_cast <const  void *>(uncompressed)))
236+           break ;
237+       }
238+       auto  cptr = allocators_[tid]->compress (uncompressed);
239+       cptr.setTierId (tid);
240+       return  cptr;
241+ 
242+     } else  {
243+       return  allocators_.compress (uncompressed);
244+     }
203245  }
204246
205247  PtrType* unCompress (const  CompressedPtr compressed) const  {
206248    if  (compressed.isNull ()) {
207249      return  nullptr ;
208250    }
251+     if  (isContainer_) {
252+       auto & allocator = *allocators_[compressed.getTierId ()];
253+       return  static_cast <PtrType*>(allocator.unCompress (compressed));
209254
210-     auto  &allocator = *allocators_[compressed.getTierId ()];
211-     return  static_cast <PtrType*>(allocator.unCompress (compressed));
255+     } else  {
256+       return  static_cast <PtrType*>(allocators_.unCompress (compressed));
257+     }
212258  }
213259
214260  bool  operator ==(const  PtrCompressor& rhs) const  noexcept  {
@@ -222,6 +268,8 @@ class PtrCompressor {
222268 private: 
223269  //  memory allocator that does the pointer compression.
224270  const  AllocatorContainer& allocators_;
271+ 
272+   bool  isContainer_{false };
225273};
226274} //  namespace cachelib
227275} //  namespace facebook
0 commit comments