1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com>
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
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
11 #ifndef BOOST_COMPUTE_DETAIL_PARAMETER_CACHE_HPP
12 #define BOOST_COMPUTE_DETAIL_PARAMETER_CACHE_HPP
17 #include <boost/shared_ptr.hpp>
18 #include <boost/make_shared.hpp>
19 #include <boost/noncopyable.hpp>
21 #include <boost/compute/config.hpp>
22 #include <boost/compute/device.hpp>
23 #include <boost/compute/detail/global_static.hpp>
24 #include <boost/compute/version.hpp>
26 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
28 #include <boost/algorithm/string/trim.hpp>
29 #include <boost/compute/detail/path.hpp>
30 #include <boost/property_tree/ptree.hpp>
31 #include <boost/property_tree/json_parser.hpp>
32 #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
38 class parameter_cache : boost::noncopyable
41 parameter_cache(const device &device)
43 m_device_name(device.name())
45 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
46 // get offline cache file name (e.g. /home/user/.boost_compute/tune/device.json)
47 m_file_name = make_file_name();
49 // load parameters from offline cache file (if it exists)
50 if(boost::filesystem::exists(m_file_name)){
53 #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
58 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
60 #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
63 void set(const std::string &object, const std::string ¶meter, uint_ value)
65 m_cache[std::make_pair(object, parameter)] = value;
67 // set the dirty flag to true. this will cause the updated parameters
68 // to be stored to disk.
72 uint_ get(const std::string &object, const std::string ¶meter, uint_ default_value)
74 std::map<std::pair<std::string, std::string>, uint_>::iterator
75 iter = m_cache.find(std::make_pair(object, parameter));
76 if(iter != m_cache.end()){
84 static boost::shared_ptr<parameter_cache> get_global_cache(const device &device)
86 // device name -> parameter cache
87 typedef std::map<std::string, boost::shared_ptr<parameter_cache> > cache_map;
89 BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(cache_map, caches, ((std::less<std::string>())));
91 cache_map::iterator iter = caches.find(device.name());
92 if(iter == caches.end()){
93 boost::shared_ptr<parameter_cache> cache =
94 boost::make_shared<parameter_cache>(device);
96 caches.insert(iter, std::make_pair(device.name(), cache));
106 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
107 // returns a string containing a cannoical device name
108 static std::string cannonical_device_name(std::string name)
110 boost::algorithm::trim(name);
111 std::replace(name.begin(), name.end(), ' ', '_');
112 std::replace(name.begin(), name.end(), '(', '_');
113 std::replace(name.begin(), name.end(), ')', '_');
117 // returns the boost.compute version string
118 static std::string version_string()
121 // snprintf is in Visual Studio since Visual Studio 2015 (_MSC_VER == 1900)
122 #if defined (_MSC_VER) && _MSC_VER < 1900
123 #define DETAIL_SNPRINTF sprintf_s
125 #define DETAIL_SNPRINTF std::snprintf
127 DETAIL_SNPRINTF(buf, sizeof(buf), "%d.%d.%d", BOOST_COMPUTE_VERSION_MAJOR,
128 BOOST_COMPUTE_VERSION_MINOR,
129 BOOST_COMPUTE_VERSION_PATCH);
130 #undef DETAIL_SNPRINTF
134 // returns the file path for the cached parameters
135 std::string make_file_name() const
137 return detail::parameter_cache_path(true) + cannonical_device_name(m_device_name) + ".json";
140 // store current parameters to disk
143 BOOST_ASSERT(!m_file_name.empty());
146 // save current parameters to disk
147 boost::property_tree::ptree pt;
148 pt.put("header.device", m_device_name);
149 pt.put("header.version", version_string());
150 typedef std::map<std::pair<std::string, std::string>, uint_> map_type;
151 for(map_type::const_iterator iter = m_cache.begin(); iter != m_cache.end(); ++iter){
152 const std::pair<std::string, std::string> &key = iter->first;
153 pt.add(key.first + "." + key.second, iter->second);
155 write_json(m_file_name, pt);
161 // load stored parameters from disk
162 void read_from_disk()
164 BOOST_ASSERT(!m_file_name.empty());
168 boost::property_tree::ptree pt;
170 read_json(m_file_name, pt);
172 catch(boost::property_tree::json_parser::json_parser_error&){
173 // no saved cache file, ignore
177 std::string stored_device;
179 stored_device = pt.get<std::string>("header.device");
181 catch(boost::property_tree::ptree_bad_path&){
185 std::string stored_version;
187 stored_version = pt.get<std::string>("header.version");
189 catch(boost::property_tree::ptree_bad_path&){
193 if(stored_device == m_device_name && stored_version == version_string()){
194 typedef boost::property_tree::ptree::const_iterator pt_iter;
195 for(pt_iter iter = pt.begin(); iter != pt.end(); ++iter){
196 if(iter->first == "header"){
201 boost::property_tree::ptree child_pt = pt.get_child(iter->first);
202 for(pt_iter child_iter = child_pt.begin(); child_iter != child_pt.end(); ++child_iter){
203 set(iter->first, child_iter->first, boost::lexical_cast<uint_>(child_iter->second.data()));
210 #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
214 std::string m_device_name;
215 std::string m_file_name;
216 std::map<std::pair<std::string, std::string>, uint_> m_cache;
219 } // end detail namespace
220 } // end compute namespace
221 } // end boost namespace
223 #endif // BOOST_COMPUTE_DETAIL_PARAMETER_CACHE_HPP