tatami_chunked
Helpers to create custom chunked tatami matrices
Loading...
Searching...
No Matches
LruSlabCache.hpp
Go to the documentation of this file.
1#ifndef TATAMI_CHUNKED_LRU_SLAB_CACHE_HPP
2#define TATAMI_CHUNKED_LRU_SLAB_CACHE_HPP
3
4#include <unordered_map>
5#include <list>
6
12namespace tatami_chunked {
13
25template<typename Id_, class Slab_>
27private:
28 typedef std::pair<Slab_, Id_> Element;
29 std::list<Element> my_cache_data;
30 std::unordered_map<Id_, typename std::list<Element>::iterator> my_cache_exists;
31 size_t my_max_slabs;
32 Id_ my_last_id = 0;
33 Slab_* my_last_slab = NULL;
34
35public:
39 LruSlabCache(size_t max_slabs) : my_max_slabs(max_slabs) {}
40
44 LruSlabCache(const LruSlabCache&) = delete;
45
50
54 // Iterators are guaranteed to be valid after move, see Notes in
55 // https://en.cppreference.com/w/cpp/container/list/list
56 // https://en.cppreference.com/w/cpp/container/list/operator%3D
57 LruSlabCache& operator=(LruSlabCache&&) = default;
58 LruSlabCache(LruSlabCache&&) = default;
59
60 // Might as well define this.
61 ~LruSlabCache() = default;
66public:
85 template<class Cfunction_, class Pfunction_>
87 if (id == my_last_id && my_last_slab) {
88 return *my_last_slab;
89 }
90 my_last_id = id;
91
92 auto it = my_cache_exists.find(id);
93 if (it != my_cache_exists.end()) {
94 auto chosen = it->second;
95 my_cache_data.splice(my_cache_data.end(), my_cache_data, chosen); // move to end.
96 my_last_slab = &(chosen->first);
97 return chosen->first;
98 }
99
100 typename std::list<Element>::iterator location;
101 if (my_cache_data.size() < my_max_slabs) {
102 my_cache_data.emplace_back(create(), id);
103 location = std::prev(my_cache_data.end());
104 } else {
105 location = my_cache_data.begin();
106 my_cache_exists.erase(location->second);
107 location->second = id;
108 my_cache_data.splice(my_cache_data.end(), my_cache_data, location); // move to end.
109 }
110 my_cache_exists[id] = location;
111
112 auto& slab = location->first;
113 populate(id, slab);
114 my_last_slab = &slab;
115 return slab;
116 }
117
118public:
122 size_t get_max_slabs() const {
123 return my_max_slabs;
124 }
125
129 size_t get_num_slabs() const {
130 return my_cache_data.size();
131 }
132};
133
134// COMMENT:
135// As tempting as it is to implement an LruVariableSlabCache, this doesn't work out well in practice.
136// This is because the Slab_ objects are re-used, and in the worst case, each object would have to be large enough to fit the largest slab.
137// At this point, we have several options:
138//
139// - Pre-allocate each Slab_ instance to have enough memory to fit the largest slab, in which case the slabs are not variable.
140// - Allow Slab_ instances to grow/shrink their memory allocation according to the size of its assigned slab.
141// This reduces efficiency due to repeated reallocations, and memory usage might end up exceeding the nominal limit anyway due to fragmentation.
142// - Share a single memory pool across slabs, and manually handle defragmentation to free up enough contiguous memory for each new slab.
143// Unlike the oracular case, we don't have the luxury of defragmenting once for multiple slabs.
144// Instead, we might potentially need to defragment on every newly requested slab, which is computationally expensive.
145//
146// See also https://softwareengineering.stackexchange.com/questions/398503/is-lru-still-a-good-algorithm-for-a-cache-with-diferent-size-elements.
147// This lists a few methods for dealing with fragmentation, but none of them are particularly clean.
148// It's likely that just using the existing LruSlabCache with the maximum possible slab size is good enough for most applications.
149
150}
151
152#endif
Least-recently-used cache for slabs.
Definition LruSlabCache.hpp:26
const Slab_ & find(Id_ id, Cfunction_ create, Pfunction_ populate)
Definition LruSlabCache.hpp:86
LruSlabCache(const LruSlabCache &)=delete
LruSlabCache & operator=(const LruSlabCache &)=delete
size_t get_num_slabs() const
Definition LruSlabCache.hpp:129
LruSlabCache(size_t max_slabs)
Definition LruSlabCache.hpp:39
size_t get_max_slabs() const
Definition LruSlabCache.hpp:122
Methods to handle chunked tatami matrices.
Definition ChunkDimensionStats.hpp:4
Statistics for regular chunks along a dimension.
Definition ChunkDimensionStats.hpp:35