1 //---------------------------------------------------------------------------// 2 // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> 3 // 4 // Distributed under the Boost Software License, Version 1.0 5 // See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt 7 // 8 // See http://boostorg.github.com/compute for more information. 9 //---------------------------------------------------------------------------// 10 11 #ifndef BOOST_COMPUTE_UTILITY_PROGRAM_CACHE_HPP 12 #define BOOST_COMPUTE_UTILITY_PROGRAM_CACHE_HPP 13 14 #include <string> 15 #include <utility> 16 17 #include <boost/shared_ptr.hpp> 18 #include <boost/make_shared.hpp> 19 #include <boost/noncopyable.hpp> 20 21 #include <boost/compute/context.hpp> 22 #include <boost/compute/program.hpp> 23 #include <boost/compute/detail/lru_cache.hpp> 24 #include <boost/compute/detail/global_static.hpp> 25 26 namespace boost { 27 namespace compute { 28 29 /// The program_cache class stores \ref program objects in a LRU cache. 30 /// 31 /// This class can be used to help mitigate the overhead of OpenCL's run-time 32 /// kernel compilation model. Commonly used programs can be stored persistently 33 /// in the cache and only compiled once on their first use. 34 /// 35 /// Program objects are stored and retreived based on a user-defined cache key 36 /// along with the options used to build the program (if any). 37 /// 38 /// For example, to insert a program into the cache: 39 /// \code 40 /// cache.insert("foo", foo_program); 41 /// \endcode 42 /// 43 /// And to retreive the program later: 44 /// \code 45 /// boost::optional<program> p = cache.get("foo"); 46 /// if(p){ 47 /// // program found in cache 48 /// } 49 /// \endcode 50 /// 51 /// \see program 52 class program_cache : boost::noncopyable 53 { 54 public: 55 /// Creates a new program cache with space for \p capacity number of 56 /// program objects. program_cache(size_t capacity)57 program_cache(size_t capacity) 58 : m_cache(capacity) 59 { 60 } 61 62 /// Destroys the program cache. ~program_cache()63 ~program_cache() 64 { 65 } 66 67 /// Returns the number of program objects currently stored in the cache. size() const68 size_t size() const 69 { 70 return m_cache.size(); 71 } 72 73 /// Returns the total capacity of the cache. capacity() const74 size_t capacity() const 75 { 76 return m_cache.capacity(); 77 } 78 79 /// Clears the program cache. clear()80 void clear() 81 { 82 m_cache.clear(); 83 } 84 85 /// Returns the program object with \p key. Returns a null optional if no 86 /// program with \p key exists in the cache. get(const std::string & key)87 boost::optional<program> get(const std::string &key) 88 { 89 return m_cache.get(std::make_pair(key, std::string())); 90 } 91 92 /// Returns the program object with \p key and \p options. Returns a null 93 /// optional if no program with \p key and \p options exists in the cache. get(const std::string & key,const std::string & options)94 boost::optional<program> get(const std::string &key, const std::string &options) 95 { 96 return m_cache.get(std::make_pair(key, options)); 97 } 98 99 /// Inserts \p program into the cache with \p key. insert(const std::string & key,const program & program)100 void insert(const std::string &key, const program &program) 101 { 102 insert(key, std::string(), program); 103 } 104 105 /// Inserts \p program into the cache with \p key and \p options. insert(const std::string & key,const std::string & options,const program & program)106 void insert(const std::string &key, const std::string &options, const program &program) 107 { 108 m_cache.insert(std::make_pair(key, options), program); 109 } 110 111 /// Loads the program with \p key from the cache if it exists. Otherwise 112 /// builds a new program with \p source and \p options, stores it in the 113 /// cache, and returns it. 114 /// 115 /// This is a convenience function to simplify the common pattern of 116 /// attempting to load a program from the cache and, if not present, 117 /// building the program from source and storing it in the cache. 118 /// 119 /// Equivalent to: 120 /// \code 121 /// boost::optional<program> p = get(key, options); 122 /// if(!p){ 123 /// p = program::create_with_source(source, context); 124 /// p->build(options); 125 /// insert(key, options, *p); 126 /// } 127 /// return *p; 128 /// \endcode get_or_build(const std::string & key,const std::string & options,const std::string & source,const context & context)129 program get_or_build(const std::string &key, 130 const std::string &options, 131 const std::string &source, 132 const context &context) 133 { 134 boost::optional<program> p = get(key, options); 135 if(!p){ 136 p = program::build_with_source(source, context, options); 137 138 insert(key, options, *p); 139 } 140 return *p; 141 } 142 143 /// Returns the global program cache for \p context. 144 /// 145 /// This global cache is used internally by Boost.Compute to store compiled 146 /// program objects used by its algorithms. All Boost.Compute programs are 147 /// stored with a cache key beginning with \c "__boost". User programs 148 /// should avoid using the same prefix in order to prevent collisions. get_global_cache(const context & context)149 static boost::shared_ptr<program_cache> get_global_cache(const context &context) 150 { 151 typedef detail::lru_cache<cl_context, boost::shared_ptr<program_cache> > cache_map; 152 153 BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(cache_map, caches, (8)); 154 155 boost::optional<boost::shared_ptr<program_cache> > cache = caches.get(context.get()); 156 if(!cache){ 157 cache = boost::make_shared<program_cache>(64); 158 159 caches.insert(context.get(), *cache); 160 } 161 162 return *cache; 163 } 164 165 private: 166 detail::lru_cache<std::pair<std::string, std::string>, program> m_cache; 167 }; 168 169 } // end compute namespace 170 } // end boost namespace 171 172 #endif // BOOST_COMPUTE_UTILITY_PROGRAM_CACHE_HPP 173