ViennaCL - The Vienna Computing Library
1.5.0
|
00001 #ifndef VIENNACL_GENERATOR_AUTOTUNE_HPP 00002 #define VIENNACL_GENERATOR_AUTOTUNE_HPP 00003 00004 00005 /* ========================================================================= 00006 Copyright (c) 2010-2013, Institute for Microelectronics, 00007 Institute for Analysis and Scientific Computing, 00008 TU Wien. 00009 Portions of this software are copyright by UChicago Argonne, LLC. 00010 00011 ----------------- 00012 ViennaCL - The Vienna Computing Library 00013 ----------------- 00014 00015 Project Head: Karl Rupp rupp@iue.tuwien.ac.at 00016 00017 (A list of authors and contributors can be found in the PDF manual) 00018 00019 License: MIT (X11), see file LICENSE in the base directory 00020 ============================================================================= */ 00021 00022 00028 #include <ctime> 00029 #include <iomanip> 00030 #include <cmath> 00031 #include <iterator> 00032 00033 #include "viennacl/ocl/kernel.hpp" 00034 #include "viennacl/ocl/infos.hpp" 00035 00036 #include "viennacl/scheduler/forwards.h" 00037 #include "viennacl/generator/generate.hpp" 00038 00039 #include "viennacl/tools/timer.hpp" 00040 00041 namespace viennacl{ 00042 00043 namespace generator{ 00044 00045 namespace autotune{ 00046 00048 class tuning_param{ 00049 public: 00050 00055 tuning_param(std::vector<int> const & values) : values_(values){ reset(); } 00056 00058 bool is_max() const { return current_ == (values_.size()-1); } 00059 00061 bool inc(){ 00062 ++current_ ; 00063 if(current_ < values_.size() ) 00064 return false; 00065 reset(); 00066 return true; 00067 } 00068 00070 int current() const{ return values_[current_]; } 00071 00073 void reset() { current_ = 0; } 00074 00075 private: 00076 std::vector<int> values_; 00077 unsigned int current_; 00078 }; 00079 00088 template<class ConfigType> 00089 class tuning_config{ 00090 private: 00092 typedef std::map<std::string, viennacl::generator::autotune::tuning_param> params_t; 00093 00094 public: 00095 typedef ConfigType config_type; 00096 00098 typedef typename config_type::profile_type profile_type; 00099 00101 void add_tuning_param(std::string const & name, std::vector<int> const & values){ 00102 params_.insert(std::make_pair(name,values)); 00103 } 00104 00106 bool has_next() const{ 00107 bool res = false; 00108 for(typename params_t::const_iterator it = params_.begin() ; it != params_.end() ; ++it) 00109 res = res || !it->second.is_max(); 00110 return res; 00111 } 00112 00114 void update(){ 00115 for(typename params_t::iterator it = params_.begin() ; it != params_.end() ; ++it) 00116 if(it->second.inc()==false) 00117 break; 00118 } 00119 00121 bool is_invalid(viennacl::ocl::device const & dev) const{ 00122 return config_type::is_invalid(dev,params_); 00123 } 00124 00126 typename config_type::profile_type get_current(){ 00127 return config_type::create_profile(params_); 00128 } 00129 00131 void reset(){ 00132 for(params_t::iterator it = params_.begin() ; it != params_.end() ; ++it){ 00133 it->second.reset(); 00134 } 00135 } 00136 00137 private: 00138 params_t params_; 00139 }; 00140 00142 template<class ProfileT> 00143 double benchmark_impl(viennacl::scheduler::statement const & statement, code_generator::forced_profile_key_type key, ProfileT const & prof, unsigned int n_runs){ 00144 00145 tools::timer t; 00146 std::list<viennacl::ocl::kernel *> kernels; 00147 viennacl::generator::code_generator gen; 00148 gen.force_profile(key, prof); 00149 gen.add(statement, statement.array()[0]); 00150 viennacl::generator::get_configured_program(gen, kernels, true); 00151 viennacl::generator::enqueue(gen); 00152 viennacl::backend::finish(); 00153 t.start(); 00154 00155 for(unsigned int i = 0 ; i < n_runs ; ++i) 00156 viennacl::generator::enqueue(gen); 00157 viennacl::backend::finish(); 00158 return (double)t.get()/n_runs; 00159 } 00160 00161 00173 template<class ConfigType> 00174 void benchmark(std::map<double, typename ConfigType::profile_type> * timings, scheduler::statement const & op, code_generator::forced_profile_key_type const & key, tuning_config<ConfigType> & config, unsigned int n_runs, std::ofstream * out){ 00175 viennacl::ocl::device const & dev = viennacl::ocl::current_device(); 00176 unsigned int n_conf = 0; 00177 while(config.has_next()){ 00178 config.update(); 00179 typename ConfigType::profile_type const & profile = config.get_current(); 00180 if(config.is_invalid(dev) || profile.is_slow(dev)) 00181 continue; 00182 ++n_conf; 00183 } 00184 config.reset(); 00185 00186 unsigned int n = 0; 00187 while(config.has_next()){ 00188 config.update(); 00189 typename ConfigType::profile_type const & profile = config.get_current(); 00190 if(config.is_invalid(dev) || profile.is_slow(dev)) 00191 continue; 00192 double percent = (double)n++*100/n_conf; 00193 double exec_time = benchmark_impl(op,key,profile,n_runs); 00194 timings->insert(std::make_pair(exec_time, profile)); 00195 std::cout << '\r' << "Autotuning..." << "[" << std::setprecision(2) << std::setfill (' ') << std::setw(6) << std::fixed << percent << "%" << "]" 00196 << " | Best : " << timings->begin()->second << " => " << std::scientific << std::right << std::setprecision(2) << timings->begin()->first << std::flush; 00197 if(out) 00198 *out << std::setprecision(3) << std::scientific << exec_time << "," << profile.csv_representation() << std::endl ; 00199 } 00200 std::cout << '\r' << "Autotuning..." << "[100.00%]" << std::endl; 00201 } 00202 00203 } 00204 00205 } 00206 00207 } 00208 #endif // AUTOTUNE_HPP