diff options
Diffstat (limited to 'boost/compute/detail/parameter_cache.hpp')
-rw-r--r-- | boost/compute/detail/parameter_cache.hpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/boost/compute/detail/parameter_cache.hpp b/boost/compute/detail/parameter_cache.hpp new file mode 100644 index 0000000000..2a856311e1 --- /dev/null +++ b/boost/compute/detail/parameter_cache.hpp @@ -0,0 +1,215 @@ +//---------------------------------------------------------------------------// +// 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 &e){ + // 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 |