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
							 |