1 
2 // =================================================================================================
3 // This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
4 // project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
5 // width of 100 characters per line.
6 //
7 // Author(s):
8 //   Cedric Nugteren <www.cedricnugteren.nl>
9 //
10 // This file implements the caching functionality of compiled binaries and programs.
11 //
12 // =================================================================================================
13 
14 #ifndef CLBLAST_CACHE_H_
15 #define CLBLAST_CACHE_H_
16 
17 #include <string>
18 #include <mutex>
19 #include <map>
20 
21 #include "utilities/utilities.hpp"
22 
23 namespace clblast {
24 // =================================================================================================
25 
26 // The generic thread-safe cache. We assume that the Key may be a heavyweight struct that is not
27 // normally used by the caller, while the Value is either lightweight or ref-counted.
28 // Hence, searching by non-Key is supported (if there is a corresponding operator<()), and
29 // on Store() the Key instance is moved from the caller (because it will likely be constructed
30 // as temporary at the time of Store()).
31 template <typename Key, typename Value>
32 class Cache {
33 public:
34   // Cached object is returned by-value to avoid racing with Invalidate().
35   // Due to lack of std::optional<>, in case of a cache miss we return a default-constructed
36   // Value and set the flag to false.
37   template <typename U>
38   Value Get(const U &key, bool *in_cache) const;
39 
40   // We do not return references to just stored object to avoid racing with Invalidate().
41   // Caller is expected to store a temporary.
42   void Store(Key &&key, Value &&value);
43   void Invalidate();
44 
45   // Removes all entries with a given key
46   void Remove(const Key &key);
47   template <int I1, int I2> void RemoveBySubset(const Key &key); // currently supports 2 indices
48 
49   static Cache<Key, Value> &Instance();
50 
51 private:
52 #if __cplusplus >= 201402L
53   // The std::less<void> allows to search in cache by an object comparable with Key, without
54   // constructing a temporary Key
55   // (see http://en.cppreference.com/w/cpp/utility/functional/less_void,
56   //      http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3657.htm,
57   //      http://stackoverflow.com/questions/10536788/avoiding-key-construction-for-stdmapfind)
58   std::map<Key, Value, std::less<void>> cache_;
59 #else
60   std::vector<std::pair<Key, Value>> cache_;
61 #endif
62   mutable std::mutex cache_mutex_;
63 
64   static Cache<Key, Value> instance_;
65 }; // class Cache
66 
67 // =================================================================================================
68 
69 // The key struct for the cache of compiled OpenCL binaries
70 // Order of fields: precision, routine_name, device_name (smaller fields first)
71 typedef std::tuple<Precision, std::string, std::string> BinaryKey;
72 typedef std::tuple<const Precision &, const std::string &, const std::string &> BinaryKeyRef;
73 
74 typedef Cache<BinaryKey, std::string> BinaryCache;
75 
76 extern template class Cache<BinaryKey, std::string>;
77 extern template std::string BinaryCache::Get(const BinaryKeyRef &, bool *) const;
78 
79 // =================================================================================================
80 
81 // The key struct for the cache of compiled OpenCL programs (context-dependent)
82 // Order of fields: context, device_id, precision, routine_name (smaller fields first)
83 typedef std::tuple<cl_context, cl_device_id, Precision, std::string> ProgramKey;
84 typedef std::tuple<const cl_context &, const cl_device_id &, const Precision &, const std::string &> ProgramKeyRef;
85 
86 typedef Cache<ProgramKey, Program> ProgramCache;
87 
88 extern template class Cache<ProgramKey, Program>;
89 extern template Program ProgramCache::Get(const ProgramKeyRef &, bool *) const;
90 
91 // =================================================================================================
92 
93 class Database;
94 
95 // The key struct for the cache of database maps.
96 // Order of fields: platform_id, device_id, precision, kernel_name (smaller fields first)
97 typedef std::tuple<cl_platform_id, cl_device_id, Precision, std::string> DatabaseKey;
98 typedef std::tuple<const cl_platform_id &, const cl_device_id &, const Precision &, const std::string &> DatabaseKeyRef;
99 
100 typedef Cache<DatabaseKey, Database> DatabaseCache;
101 
102 extern template class Cache<DatabaseKey, Database>;
103 extern template Database DatabaseCache::Get(const DatabaseKeyRef &, bool *) const;
104 
105 // =================================================================================================
106 } // namespace clblast
107 
108 // CLBLAST_CACHE_H_
109 #endif
110