1515#include < stdexcept>
1616#include < vector>
1717
18- #include " persistent_cache.h"
18+ #include " core/utils.h"
19+ #include " core/persistent_cache.h"
1920
2021namespace VPUNN {
2122
2223/* *
2324 * @brief a workload cache using LRU (least recent used) replacement policy
24- * @tparam T workload datatype
25+ * @tparam K is the Key type
26+ * @tparam V is the Value type
2527 */
26- template <class T >
28+ template <typename K, typename V >
2729class LRUCache {
2830private:
29- typedef std::list<std::pair<std::vector<T>, T>> List;
30- typedef typename List::iterator List_Iter;
31- typedef std::map<std::vector<T>, List_Iter> Map;
32- typedef typename Map::iterator Map_Iter;
33- List workloads;
34- Map m_table;
35- size_t max_size, size;
31+ typedef std::list<std::pair<K, V>> List;
32+ typedef typename List::const_iterator List_Iter_cnst;
3633
37- // / loaded from file, must be loaded from a file with the same descriptor signature
38- const FixedCache<T> deserialized_table;
34+ typedef std::map<K, List_Iter_cnst> Map;
35+ typedef typename Map::const_iterator Map_Iter_cnst;
36+
37+ List workloads; // /< list with first being the most recently used key
38+ Map m_table; // /< table for fast searching of keys (contains pointers to list objects)
39+ const size_t max_size;
40+ size_t size{0 };
3941
42+ // / loaded from file, must be loaded from a file with the same descriptor signature
43+ // / @note this is a draft implementation
44+ // / This datatype knows it is a float Value and uint32 key. this beats the K, V template
45+ const FixedCache deserialized_table; // maybe send it as template, OR reuse V and hashable K?
46+
47+ // / @brief Decide which cache file to load (DRAFT
48+ // / @param filenamePrio1 the first filename to try to load. must be a valid name and extension.Must be empty to go
49+ // / and try to select the second option
50+ // / @param loadThisCSVIfPairedCacheExists the second filename to try to load if the first does not exist. Takes only
51+ // / the name, and replaces the extension with the default extension for cache. Is selected only if exists on disk!
4052 static std::string decideCacheFilename (const std::string& filenamePrio1,
4153 const std::string& loadThisCSVIfPairedCacheExists) {
4254 auto selected_filename{filenamePrio1}; // can be empty or nonexistent
43- if (filenamePrio1.empty ()) { // prio 1 dropped
55+ if (filenamePrio1.empty ()) { // prio 1 dropped, does not exist
4456 std::filesystem::path pairC{loadThisCSVIfPairedCacheExists};
4557 pairC.replace_extension (" .cache_bin" );
4658 if (!loadThisCSVIfPairedCacheExists.empty () && std::filesystem::exists (pairC)) {
@@ -56,17 +68,14 @@ class LRUCache {
5668 *
5769 * @param max_size the maximum size of the LRUCache
5870 */
59- explicit LRUCache (size_t max_size, size_t interface_size = 0 , const std::string& filename = " " ,
60- const std::string& loadIfPairedCacheExists = " " )
61- : max_size(max_size),
62- size(0 ),
63- deserialized_table{interface_size, decideCacheFilename (filename, loadIfPairedCacheExists)} {
71+ explicit LRUCache (size_t max_size, const std::string& filename = " " ,
72+ const std::string& prio2_loadIfPairedCacheExists = " " )
73+ : max_size(max_size), deserialized_table{decideCacheFilename (filename, prio2_loadIfPairedCacheExists)} {
6474 }
6575
6676 // const char* model_data, size_t model_data_length, bool copy_model_data
67- explicit LRUCache (size_t max_size, size_t interface_size = 0 , const char * file_data = nullptr ,
68- size_t file_data_length = 0 )
69- : max_size(max_size), size(0 ), deserialized_table{interface_size, file_data, file_data_length} {
77+ explicit LRUCache (size_t max_size, const char * file_data = nullptr , size_t file_data_length = 0 )
78+ : max_size(max_size), deserialized_table{file_data, file_data_length} {
7079 }
7180
7281 /* *
@@ -75,28 +84,31 @@ class LRUCache {
7584 * @param wl the workload descriptor (key)
7685 * @param value the workload value
7786 */
78- void add (const std::vector<T> & wl, const T & value) {
79- // If max_size == 0 we effectively disable the cache
87+ void add (const K & wl, const V & value) {
88+ // If max_size == 0 we effectively disable the cache!
8089 if (max_size == 0 )
8190 return ;
8291
8392 // Check if the workload is already in the deserialized table
84- if (deserialized_table.contains (wl))
85- return ;
93+ {
94+ if constexpr (has_hash_v<K>) {
95+ if (deserialized_table.contains (wl.hash ()))
96+ return ;
97+ } else {
98+ if (deserialized_table.contains (NNDescriptor<float >(wl).hash ()))
99+ return ;
100+ }
101+ }
86102
87103 // Insert items in the list and map
88104 workloads.push_front ({wl, value});
89- auto it = workloads.begin ();
90- m_table.insert ({wl, it});
105+ m_table.insert ({wl, workloads.cbegin ()});
91106 size++;
92107
108+ // delete the oldest ones that occupy more space than allowed
93109 while (size > max_size) {
94- // Get the last element.
95- auto last_item = workloads.end ();
96- --last_item;
97-
98- // Remove the last element
99- remove (last_item->first );
110+ const auto & last_item{workloads.back ()};
111+ remove (last_item.first ); // key is first in pair
100112 }
101113 }
102114
@@ -106,22 +118,17 @@ class LRUCache {
106118 *
107119 * @param wl the workload descriptor
108120 */
109- void remove (std::vector<T>& wl) {
110- // Remove the workload from the cache
111- auto it = m_table.find (wl);
121+ void remove (const K& wl) {
122+ Map_Iter_cnst it = m_table.find (wl);
112123
113- if (it != m_table.end ()) {
114- // Erase the element from the map
115- m_table.erase (it->first );
124+ if (it != m_table.cend ()) {
125+ m_table.erase (it->first ); // key is first
116126 } else {
117127 throw std::out_of_range (" VPUNN Cache out of range" );
118128 }
119129
120- // Remove the last element from the list
121- workloads.pop_back ();
122-
123- // Update the size
124- size--;
130+ workloads.pop_back (); // Remove the last element from the list
131+ size--; // Update the size
125132 }
126133
127134public:
@@ -131,20 +138,28 @@ class LRUCache {
131138 * @param wl the workload descriptor
132139 * @return T* a pointer to the workload value stored in the cache, or nullptr if not available
133140 */
134- const T * get (const std::vector<T> & wl) {
141+ const V * get (const K & wl) {
135142 // Check if the workload is in the deserialized table
136- const T* elementInPreloadedCache{deserialized_table.get_pointer (wl)};
137- if (elementInPreloadedCache) {
138- return elementInPreloadedCache; // ret the pointer to the element in the preloaded cache
143+ {
144+ uint32_t wlhash{0 };
145+ if constexpr (has_hash_v<K>) {
146+ wlhash = wl.hash ();
147+ } else {
148+ wlhash = NNDescriptor<float >(wl).hash ();
149+ }
150+
151+ const V* elementInPreloadedCache{deserialized_table.get_pointer (wlhash)};
152+ if (elementInPreloadedCache) {
153+ return elementInPreloadedCache; // ret the pointer to the element in the preloaded cache
154+ }
139155 }
140156
141157 // Check if the workload is in the main table
142- Map_Iter it = m_table.find (wl);
143- if (it != m_table.end ()) {
158+ Map_Iter_cnst it = m_table.find (wl);
159+ if (it != m_table.cend ()) {
144160 // Move the workload to the beginning of the list
145- workloads.splice (workloads.begin (), workloads, it->second );
146- // Return the value
147- return &(it->second ->second );
161+ workloads.splice (workloads.cbegin (), workloads, it->second );
162+ return &(it->second ->second ); // second is the list iterator
148163 } else {
149164 return nullptr ;
150165 }
0 commit comments