216 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //---------------------------------------------------------------------------//
 | |
| // Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com>
 | |
| //
 | |
| // Distributed under the Boost Software License, Version 1.0
 | |
| // See accompanying file LICENSE_1_0.txt or copy at
 | |
| // http://www.boost.org/LICENSE_1_0.txt
 | |
| //
 | |
| // See http://boostorg.github.com/compute for more information.
 | |
| //---------------------------------------------------------------------------//
 | |
| 
 | |
| #ifndef BOOST_COMPUTE_DETAIL_PARAMETER_CACHE_HPP
 | |
| #define BOOST_COMPUTE_DETAIL_PARAMETER_CACHE_HPP
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <string>
 | |
| 
 | |
| #include <boost/shared_ptr.hpp>
 | |
| #include <boost/make_shared.hpp>
 | |
| #include <boost/noncopyable.hpp>
 | |
| 
 | |
| #include <boost/compute/config.hpp>
 | |
| #include <boost/compute/device.hpp>
 | |
| #include <boost/compute/detail/global_static.hpp>
 | |
| #include <boost/compute/version.hpp>
 | |
| 
 | |
| #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
| #include <boost/algorithm/string/trim.hpp>
 | |
| #include <boost/compute/detail/path.hpp>
 | |
| #include <boost/property_tree/ptree.hpp>
 | |
| #include <boost/property_tree/json_parser.hpp>
 | |
| #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
| 
 | |
| namespace boost {
 | |
| namespace compute {
 | |
| namespace detail {
 | |
| 
 | |
| class parameter_cache : boost::noncopyable
 | |
| {
 | |
| public:
 | |
|     parameter_cache(const device &device)
 | |
|         : m_dirty(false),
 | |
|           m_device_name(device.name())
 | |
|     {
 | |
|     #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
|         // get offline cache file name (e.g. /home/user/.boost_compute/tune/device.json)
 | |
|         m_file_name = make_file_name();
 | |
| 
 | |
|         // load parameters from offline cache file (if it exists)
 | |
|         if(boost::filesystem::exists(m_file_name)){
 | |
|             read_from_disk();
 | |
|         }
 | |
|     #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
|     }
 | |
| 
 | |
|     ~parameter_cache()
 | |
|     {
 | |
|     #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
|         write_to_disk();
 | |
|     #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
|     }
 | |
| 
 | |
|     void set(const std::string &object, const std::string ¶meter, uint_ value)
 | |
|     {
 | |
|         m_cache[std::make_pair(object, parameter)] = value;
 | |
| 
 | |
|         // set the dirty flag to true. this will cause the updated parameters
 | |
|         // to be stored to disk.
 | |
|         m_dirty = true;
 | |
|     }
 | |
| 
 | |
|     uint_ get(const std::string &object, const std::string ¶meter, uint_ default_value)
 | |
|     {
 | |
|         std::map<std::pair<std::string, std::string>, uint_>::iterator
 | |
|             iter = m_cache.find(std::make_pair(object, parameter));
 | |
|         if(iter != m_cache.end()){
 | |
|             return iter->second;
 | |
|         }
 | |
|         else {
 | |
|             return default_value;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static boost::shared_ptr<parameter_cache> get_global_cache(const device &device)
 | |
|     {
 | |
|         // device name -> parameter cache
 | |
|         typedef std::map<std::string, boost::shared_ptr<parameter_cache> > cache_map;
 | |
| 
 | |
|         BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(cache_map, caches, ((std::less<std::string>())));
 | |
| 
 | |
|         cache_map::iterator iter = caches.find(device.name());
 | |
|         if(iter == caches.end()){
 | |
|             boost::shared_ptr<parameter_cache> cache =
 | |
|                 boost::make_shared<parameter_cache>(device);
 | |
| 
 | |
|             caches.insert(iter, std::make_pair(device.name(), cache));
 | |
| 
 | |
|             return cache;
 | |
|         }
 | |
|         else {
 | |
|             return iter->second;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| private:
 | |
| #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
|     // returns a string containing a cannoical device name
 | |
|     static std::string cannonical_device_name(std::string name)
 | |
|     {
 | |
|         boost::algorithm::trim(name);
 | |
|         std::replace(name.begin(), name.end(), ' ', '_');
 | |
|         std::replace(name.begin(), name.end(), '(', '_');
 | |
|         std::replace(name.begin(), name.end(), ')', '_');
 | |
|         return name;
 | |
|     }
 | |
| 
 | |
|     // returns the boost.compute version string
 | |
|     static std::string version_string()
 | |
|     {
 | |
|         char buf[32];
 | |
|         std::snprintf(buf, sizeof(buf), "%d.%d.%d", BOOST_COMPUTE_VERSION_MAJOR,
 | |
|                                                     BOOST_COMPUTE_VERSION_MINOR,
 | |
|                                                     BOOST_COMPUTE_VERSION_PATCH);
 | |
|         return buf;
 | |
|     }
 | |
| 
 | |
|     // returns the file path for the cached parameters
 | |
|     std::string make_file_name() const
 | |
|     {
 | |
|         return detail::parameter_cache_path(true) + cannonical_device_name(m_device_name) + ".json";
 | |
|     }
 | |
| 
 | |
|     // store current parameters to disk
 | |
|     void write_to_disk()
 | |
|     {
 | |
|         BOOST_ASSERT(!m_file_name.empty());
 | |
| 
 | |
|         if(m_dirty){
 | |
|             // save current parameters to disk
 | |
|             boost::property_tree::ptree pt;
 | |
|             pt.put("header.device", m_device_name);
 | |
|             pt.put("header.version", version_string());
 | |
|             typedef std::map<std::pair<std::string, std::string>, uint_> map_type;
 | |
|             for(map_type::const_iterator iter = m_cache.begin(); iter != m_cache.end(); ++iter){
 | |
|                 const std::pair<std::string, std::string> &key = iter->first;
 | |
|                 pt.add(key.first + "." + key.second, iter->second);
 | |
|             }
 | |
|             write_json(m_file_name, pt);
 | |
| 
 | |
|             m_dirty = false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // load stored parameters from disk
 | |
|     void read_from_disk()
 | |
|     {
 | |
|         BOOST_ASSERT(!m_file_name.empty());
 | |
| 
 | |
|         m_cache.clear();
 | |
| 
 | |
|         boost::property_tree::ptree pt;
 | |
|         try {
 | |
|             read_json(m_file_name, pt);
 | |
|         }
 | |
|         catch(boost::property_tree::json_parser::json_parser_error&){
 | |
|             // no saved cache file, ignore
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         std::string stored_device;
 | |
|         try {
 | |
|             stored_device = pt.get<std::string>("header.device");
 | |
|         }
 | |
|         catch(boost::property_tree::ptree_bad_path&){
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         std::string stored_version;
 | |
|         try {
 | |
|             stored_version = pt.get<std::string>("header.version");
 | |
|         }
 | |
|         catch(boost::property_tree::ptree_bad_path&){
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if(stored_device == m_device_name && stored_version == version_string()){
 | |
|             typedef boost::property_tree::ptree::const_iterator pt_iter;
 | |
|             for(pt_iter iter = pt.begin(); iter != pt.end(); ++iter){
 | |
|                 if(iter->first == "header"){
 | |
|                     // skip header
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 boost::property_tree::ptree child_pt = pt.get_child(iter->first);
 | |
|                 for(pt_iter child_iter = child_pt.begin(); child_iter != child_pt.end(); ++child_iter){
 | |
|                     set(iter->first, child_iter->first, boost::lexical_cast<uint_>(child_iter->second.data()));
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         m_dirty = false;
 | |
|     }
 | |
| #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
 | |
| 
 | |
| private:
 | |
|     bool m_dirty;
 | |
|     std::string m_device_name;
 | |
|     std::string m_file_name;
 | |
|     std::map<std::pair<std::string, std::string>, uint_> m_cache;
 | |
| };
 | |
| 
 | |
| } // end detail namespace
 | |
| } // end compute namespace
 | |
| } // end boost namespace
 | |
| 
 | |
| #endif // BOOST_COMPUTE_DETAIL_PARAMETER_CACHE_HPP
 | 
