1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
5 
6 #ifndef LIB_JXL_BASE_CACHE_ALIGNED_H_
7 #define LIB_JXL_BASE_CACHE_ALIGNED_H_
8 
9 // Memory allocator with support for alignment + misalignment.
10 
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include <memory>
15 
16 #include "lib/jxl/base/compiler_specific.h"
17 
18 namespace jxl {
19 
20 // Functions that depend on the cache line size.
21 class CacheAligned {
22  public:
23   static void PrintStats();
24 
25   static constexpr size_t kPointerSize = sizeof(void*);
26   static constexpr size_t kCacheLineSize = 64;
27   // To avoid RFOs, match L2 fill size (pairs of lines).
28   static constexpr size_t kAlignment = 2 * kCacheLineSize;
29   // Minimum multiple for which cache set conflicts and/or loads blocked by
30   // preceding stores can occur.
31   static constexpr size_t kAlias = 2048;
32 
33   // Returns a 'random' (cyclical) offset suitable for Allocate.
34   static size_t NextOffset();
35 
36   // Returns null or memory whose address is congruent to `offset` (mod kAlias).
37   // This reduces cache conflicts and load/store stalls, especially with large
38   // allocations that would otherwise have similar alignments. At least
39   // `payload_size` (which can be zero) bytes will be accessible.
40   static void* Allocate(size_t payload_size, size_t offset);
41 
Allocate(const size_t payload_size)42   static void* Allocate(const size_t payload_size) {
43     return Allocate(payload_size, NextOffset());
44   }
45 
46   static void Free(const void* aligned_pointer);
47 };
48 
49 // Avoids the need for a function pointer (deleter) in CacheAlignedUniquePtr.
50 struct CacheAlignedDeleter {
operatorCacheAlignedDeleter51   void operator()(uint8_t* aligned_pointer) const {
52     return CacheAligned::Free(aligned_pointer);
53   }
54 };
55 
56 using CacheAlignedUniquePtr = std::unique_ptr<uint8_t[], CacheAlignedDeleter>;
57 
58 // Does not invoke constructors.
AllocateArray(const size_t bytes)59 static inline CacheAlignedUniquePtr AllocateArray(const size_t bytes) {
60   return CacheAlignedUniquePtr(
61       static_cast<uint8_t*>(CacheAligned::Allocate(bytes)),
62       CacheAlignedDeleter());
63 }
64 
AllocateArray(const size_t bytes,const size_t offset)65 static inline CacheAlignedUniquePtr AllocateArray(const size_t bytes,
66                                                   const size_t offset) {
67   return CacheAlignedUniquePtr(
68       static_cast<uint8_t*>(CacheAligned::Allocate(bytes, offset)),
69       CacheAlignedDeleter());
70 }
71 
72 }  // namespace jxl
73 
74 #endif  // LIB_JXL_BASE_CACHE_ALIGNED_H_
75