ViennaCL - The Vienna Computing Library  1.5.0
viennacl/generator/autotune.hpp
Go to the documentation of this file.
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