• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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