Line data Source code
1 : #pragma once 2 : 3 : #include "MemoryResource.h" 4 : #include <unordered_map> 5 : #include <list> 6 : #include <memory> 7 : #include <limits> 8 : 9 : template <> 10 : class std::hash<std::pair<size_t, size_t>> 11 : { 12 : public: 13 : size_t operator()(const std::pair<size_t, size_t>& pair) const 14 79798 : { 15 79798 : return std::hash<size_t>()(std::hash<size_t>()(pair.first) ^ pair.second); 16 79798 : } 17 : }; 18 : 19 : namespace elsa::mr 20 : { 21 : namespace cache_resource 22 : { 23 : struct CacheElement { 24 : void* ptr; 25 : 26 : size_t size; 27 : 28 : size_t alignment; 29 : }; 30 : } // namespace cache_resource 31 : 32 : class CacheResource; 33 : 34 : class CacheResourceConfig 35 : { 36 : private: 37 : friend class CacheResource; 38 : 39 : size_t maxCacheSize; 40 : 41 : size_t maxCachedCount; 42 : 43 : constexpr CacheResourceConfig(size_t maxCacheSize, size_t maxCachedCount) 44 : : maxCacheSize{maxCacheSize}, maxCachedCount{maxCachedCount} 45 10 : { 46 10 : } 47 : 48 : public: 49 : /// @brief Default configuration for a cache resource with (hopefully) sensible defaults. 50 : /// @return Default configuration for a cache resource. 51 : static constexpr CacheResourceConfig defaultConfig() 52 10 : { 53 10 : return CacheResourceConfig(std::numeric_limits<size_t>::max(), 16); 54 10 : } 55 : 56 : /// @brief Set the maximum cumulative size of cached chunks, before releasing chunks to the 57 : /// upstream allocator 58 : /// @param size Maximum cumulative size of cached chunks 59 : /// @return self 60 : constexpr CacheResourceConfig& setMaxCacheSize(size_t size) 61 3 : { 62 3 : maxCacheSize = size; 63 3 : return *this; 64 3 : } 65 : 66 : /// @brief Set the maximum number of cached chunks, before releasing chunks to the 67 : /// upstream allocator 68 : /// @param count Maximum number of cached chunks. For an unlimited number of chunks, 69 : /// set this value to std::numeric_limits<usize>::max(). Be aware that, for any other 70 : /// value, space for the cache entries may be pre-reserved. 71 : /// @return self 72 : constexpr CacheResourceConfig& setMaxCachedCount(size_t count) 73 3 : { 74 3 : maxCachedCount = count; 75 3 : return *this; 76 3 : } 77 : }; 78 : 79 : /// @brief Memory resource for the ContiguousStorage class. 80 : /// It caches freed blocks before returning them to the upstream allocator. Using this 81 : /// resource makes sense when the allocation pattern repeatedly allocates and frees blocks of 82 : /// exactly the same size, e.g. in a loop. 83 : /// IMPORTANT: THIS RESOURCE IS NOT SYNCHRONIZED! 84 : /// Advantage over a plain UniversalResource: allocations/deallocations are faster, memory is 85 : /// potentially already mapped from previous use. Only benefitial for repeating allocation 86 : /// patterns. Disadvantage: Move assignment between containers with different memory resources 87 : /// is more costly. 88 : class CacheResource : public MemResInterface 89 : { 90 : private: 91 : using Cache = std::list<cache_resource::CacheElement>; 92 : MemoryResource _upstream; 93 : 94 : CacheResourceConfig _config; 95 : 96 : std::unordered_multimap<std::pair<size_t, size_t>, Cache::iterator> _sizeToCacheElement; 97 : 98 : Cache _cache; 99 : 100 : size_t _cachedSize{0}; 101 : 102 : void releaseCache(); 103 : 104 : public: 105 : CacheResource(const CacheResource& other) = delete; 106 : 107 : CacheResource& operator=(const CacheResource& other) = delete; 108 : 109 : CacheResource(CacheResource&& other) noexcept = delete; 110 : 111 : CacheResource& operator=(CacheResource&& other) noexcept = delete; 112 : 113 : protected: 114 : CacheResource(MemoryResource upstream, 115 : const CacheResourceConfig& config = CacheResourceConfig::defaultConfig()); 116 : 117 : ~CacheResource(); 118 : 119 : public: 120 : static MemoryResource 121 : make(MemoryResource upstream = globalResource(), 122 : const CacheResourceConfig& config = CacheResourceConfig::defaultConfig()); 123 : 124 : void* allocate(size_t size, size_t alignment) override; 125 : 126 : void deallocate(void* ptr, size_t size, size_t alignment) noexcept override; 127 : 128 : bool tryResize(void* ptr, size_t size, size_t alignment, size_t newSize) noexcept override; 129 : }; 130 : } // namespace elsa::mr