ViennaCL - The Vienna Computing Library  1.4.2
viennacl/io/kernel_parameters.hpp
Go to the documentation of this file.
00001 #ifndef VIENNACL_IO_KERNEL_PARAMETERS_HPP
00002 #define VIENNACL_IO_KERNEL_PARAMETERS_HPP
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2013, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008    Portions of this software are copyright by UChicago Argonne, LLC.
00009 
00010                             -----------------
00011                   ViennaCL - The Vienna Computing Library
00012                             -----------------
00013 
00014    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00015                
00016    (A list of authors and contributors can be found in the PDF manual)
00017 
00018    License:         MIT (X11), see file LICENSE in the base directory
00019 ============================================================================= */
00020 
00021 
00026 #include "viennacl/ocl/backend.hpp"
00027 #include "pugixml/src/pugixml.hpp"
00028 
00029 namespace viennacl
00030 {
00031   namespace io 
00032   {
00033     namespace tag 
00034     {
00035       static std::string root     = "parameters";
00036       static std::string devices  = "devices";   
00037       static std::string device   = "device";   
00038       static std::string name     = "name";
00039       static std::string driver   = "driver";
00040       static std::string compun   = "computeunits";      
00041       static std::string workgrp  = "workgroupsize";            
00042       static std::string tests    = "tests";
00043       static std::string test     = "test";                     
00044       static std::string numeric  = "numeric";
00045       static std::string kernels  = "kernels";
00046       static std::string kernel   = "kernel";
00047       static std::string params   = "params";
00048       static std::string param    = "param";
00049       static std::string value    = "value";   
00050       static std::string alignment = "alignment";   
00051     } // end namespace tag
00052 
00053     namespace val {
00054       static std::string globsize = "globalsize";
00055       static std::string locsize  = "localsize";   
00056       static std::string vec      = "vector";   
00057       static std::string matrix   = "matrix";   
00058       static std::string compmat  = "compressed_matrix";
00059       static std::string fl       = "float";   
00060       static std::string dbl      = "double";      
00061     }
00062 
00064     struct parameter_database 
00065     {
00066       parameter_database ()
00067       {
00068           root = doc.append_child();
00069           root.set_name(tag::root.c_str());
00070           last = root;
00071           
00072           devices_open = false;
00073           tests_open = false;      
00074           kernels_open = false;
00075           parameters_open = false;      
00076       }   
00077       
00078       void add_device()
00079       {
00080           pugi::xml_node dev;
00081           if(devices_open)
00082           {
00083             dev = devices.append_child();
00084             dev.set_name(tag::device.c_str());      
00085           }
00086           else
00087           {
00088             devices = last.append_child();
00089             devices.set_name(tag::devices.c_str());
00090             
00091             dev = devices.append_child();
00092             dev.set_name(tag::device.c_str());
00093             
00094             devices_open = true;
00095           }
00096           last = dev;
00097       }
00098       
00099       void add_test()
00100       {
00101           pugi::xml_node test;
00102           if(tests_open)
00103           {
00104             test = tests.append_child();
00105             test.set_name(tag::test.c_str());      
00106           }
00107           else
00108           {
00109             tests = last.append_child();
00110             tests.set_name(tag::tests.c_str());
00111             
00112             test = tests.append_child();
00113             test.set_name(tag::test.c_str());
00114             
00115             tests_open = true;
00116           }
00117           last = test;
00118           // close the current kernels section
00119           // so a new one is created for this new test
00120           kernels_open = false;      
00121       }   
00122 
00123       void add_kernel()
00124       {
00125           pugi::xml_node kern;
00126           if(kernels_open)
00127           {
00128             kern = kernels.append_child();
00129             kern.set_name(tag::kernel.c_str());      
00130           }
00131           else
00132           {
00133             kernels = last.append_child();
00134             kernels.set_name(tag::kernels.c_str());
00135             
00136             kern = kernels.append_child();
00137             kern.set_name(tag::kernel.c_str());
00138             
00139             kernels_open = true;
00140           }
00141           last = kern;
00142           
00143           // close the current parameters section
00144           // so a new one is created for this new kernel
00145           parameters_open = false;
00146       }      
00147       
00148       void add_parameter()
00149       {
00150           pugi::xml_node para;
00151           
00152           if(parameters_open)
00153           {
00154             para = parameters.append_child();
00155             para.set_name(tag::param.c_str());      
00156           }
00157           else
00158           {
00159             parameters = last.append_child();
00160             parameters.set_name(tag::params.c_str());
00161             
00162             para = parameters.append_child();
00163             para.set_name(tag::param.c_str());
00164             
00165             parameters_open = true;
00166           }
00167           last = para;
00168       }         
00169       
00170       template<typename ValueT>
00171       void add_data_node(std::string tagstr, ValueT data)
00172       {
00173           std::stringstream ss;
00174           ss << data;
00175           add_data_node(tagstr, ss.str());
00176       }   
00177       
00178       void add_data_node(std::string tagstr, std::string data)
00179       {
00180           pugi::xml_node node = last.append_child();
00181           
00182           if(tagstr == tag::name)
00183             node.set_name(tag::name.c_str());
00184           else if(tagstr == tag::driver)
00185             node.set_name(tag::driver.c_str());      
00186           else if(tagstr == tag::numeric)
00187             node.set_name(tag::numeric.c_str());      
00188           else if(tagstr == tag::alignment)
00189             node.set_name(tag::alignment.c_str());      
00190           else if(tagstr == tag::value)
00191             node.set_name(tag::value.c_str());      
00192           else if(tagstr == tag::compun)
00193             node.set_name(tag::compun.c_str());      
00194           else if(tagstr == tag::workgrp)
00195             node.set_name(tag::workgrp.c_str());                        
00196           else
00197             std::cout << "# Error adding data node: node tag not recognized .." << std::endl;
00198           node.append_child(pugi::node_pcdata).set_value(data.c_str());
00199       }
00200 
00201       void load(std::string filename)
00202       {
00203           doc.load_file(filename.c_str());
00204       }
00205 
00206       void dump(std::string filename)
00207       {
00208           std::ofstream outstream(filename.c_str());
00209           this->dump(outstream);
00210           outstream.close();
00211       }
00212       
00213       void dump(std::ostream& stream = std::cout)
00214       {
00215           doc.save(stream, "  ");
00216       }
00217 
00218       pugi::xml_document   doc;
00219       pugi::xml_node       root;
00220       pugi::xml_node       devices;
00221       pugi::xml_node       tests;   
00222       pugi::xml_node       kernels;      
00223       pugi::xml_node       parameters;         
00224       pugi::xml_node       last;   
00225       
00226       bool devices_open;
00227       bool tests_open;   
00228       bool kernels_open;      
00229       bool parameters_open;         
00230 
00231     };
00232     
00234     template <typename T>
00235     struct first_letter_of_type
00236     {
00237       static char get(); //intentionally not implemented, class must be specialized
00238     };
00239     
00240     template <>
00241     struct first_letter_of_type <float>
00242     {
00243       static char get() { return 'f'; } 
00244     };
00245     
00246     template <>
00247     struct first_letter_of_type <double>
00248     {
00249       static char get() { return 'd'; } 
00250     };
00251     
00252     template <typename T>
00253     struct program_for_vcltype
00254     {
00255       static std::string get();  //intentionally not implemented, class must be specialized
00256     };
00257     
00258     template <typename T, unsigned int ALIGNMENT>
00259     struct program_for_vcltype < viennacl::vector<T, ALIGNMENT> >
00260     {
00261       static std::string get()
00262       {
00263         std::stringstream ss;
00264         ss << first_letter_of_type<T>::get() << "_vector_" << ALIGNMENT;
00265         return ss.str();
00266       } 
00267     };
00268     
00269     template <typename T, unsigned int ALIGNMENT>
00270     struct program_for_vcltype < viennacl::matrix<T, row_major, ALIGNMENT> >
00271     {
00272       static std::string get()
00273       {
00274         std::stringstream ss;
00275         ss << first_letter_of_type<T>::get() << "_matrix_row_" << ALIGNMENT;
00276         return ss.str();
00277       } 
00278     };
00279 
00280     template <typename T, unsigned int ALIGNMENT>
00281     struct program_for_vcltype < viennacl::matrix<T, column_major, ALIGNMENT> >
00282     {
00283       static std::string get()
00284       {
00285         std::stringstream ss;
00286         ss << first_letter_of_type<T>::get() << "_matrix_col_" << ALIGNMENT;
00287         return ss.str();
00288       } 
00289     };
00290     
00291     template <typename T, unsigned int ALIGNMENT>
00292     struct program_for_vcltype < viennacl::compressed_matrix<T,  ALIGNMENT> >
00293     {
00294       static std::string get()
00295       {
00296         std::stringstream ss;
00297         ss << first_letter_of_type<T>::get() << "_compressed_matrix_" << ALIGNMENT;
00298         return ss.str();
00299       } 
00300     };
00301 
00302     template<typename SCALARTYPE, unsigned int ALIGNMENT>
00303     void set_kernel_params(std::string program_name,
00304                           std::string kernel_name,
00305                           unsigned int glob, //total no. of threads
00306                           unsigned int loc)  //threads per work group
00307     {
00308       //get kernel from pool and set work sizes:
00309       viennacl::ocl::kernel & k = viennacl::ocl::get_kernel(program_name, kernel_name);
00310       k.global_work_size(0, glob);
00311       k.local_work_size(0, loc);
00312       
00313       //std::cout << "Setting [" << glob << ", " << loc << "] for kernel " << kernel_name << std::endl;
00314     }
00315 
00316     template<typename VclBasicType>
00317     void tune_impl(parameter_database& paras, std::string parent)
00318     {
00319       typedef typename VclBasicType::value_type::value_type   SCALARTYPE;
00320       
00321       // create dummy vectors; the kernels have to be created ..
00322       VclBasicType    dummy;
00323 
00324       // extract the kernels for which parameters are present
00325       std::string          kernel_str = parent+"/kernels/kernel/name/text()";
00326       pugi::xpath_node_set kernel_res = paras.doc.select_nodes(kernel_str.c_str());      
00327 
00328       typedef std::vector<std::string>   kernels_type;
00329       kernels_type kernels;
00330       std::cout << "Retrieving kernels..." << std::endl;
00331       for (pugi::xpath_node_set::const_iterator it = kernel_res.begin(); it != kernel_res.end(); ++it)
00332       {
00333           std::stringstream ss;
00334           it->node().print(ss, "  ");
00335           std::string kern(ss.str());
00336           kern.erase(std::remove(kern.begin(), kern.end(), '\n'), kern.end()); //trim trailing linebreak
00337           kernels.push_back(kern);
00338       }
00339       
00340       // retrieve the actual parameters
00341       std::cout << "Retrieving actual parameters..." << std::endl;
00342       for(typename kernels_type::iterator iter = kernels.begin();
00343           iter != kernels.end(); iter++)
00344       {
00345           // retrieving the work group ..
00346           std::string          wg_str = parent+"/kernels/kernel[name='"+*iter+"']/params/param[name='"+val::globsize+"']/value/text()";
00347           pugi::xpath_node_set wg_res = paras.doc.select_nodes(wg_str.c_str());  
00348 
00349           unsigned int global_size(0);
00350           
00351           std::stringstream ss;
00352           ss << wg_res[0].node().value();
00353           ss >> global_size;
00354           
00355           // retrieving the local_workers ..
00356           std::string          lw_str = parent+"/kernels/kernel[name='"+*iter+"']/params/param[name='"+val::locsize+"']/value/text()";
00357           pugi::xpath_node_set lw_res = paras.doc.select_nodes(lw_str.c_str());  
00358 
00359           unsigned int local_workers(0);
00360           
00361           ss.clear();
00362           ss << lw_res[0].node().value();
00363           ss >> local_workers;         
00364           
00365           //std::cout << "kernel: " << *iter << " wg: " << work_group << " lw: " << local_workers << std::endl;
00366 
00367           // set the parameters
00368           set_kernel_params<SCALARTYPE,1> (program_for_vcltype<VclBasicType>::get(), *iter, global_size, local_workers);
00369           //set_kernel_params<SCALARTYPE,4> (*iter, work_group * local_workers, local_workers);         
00370           //set_kernel_params<SCALARTYPE,16>(*iter, work_group * local_workers, local_workers);                 
00371       }
00372     }
00373 
00375     template <typename T>
00376     struct to_string {};
00377 
00378     template <>
00379     struct to_string<float>
00380     {
00381       static std::string get() { return "float"; }
00382     };
00383 
00384     template <>
00385     struct to_string<double>
00386     {
00387       static std::string get() { return "double"; }
00388     };
00389 
00395     template<typename VclBasicType>
00396     void read_kernel_parameters(std::string filename)
00397     {
00398       typedef typename VclBasicType::value_type::value_type   SCALARTYPE;
00399       
00400       parameter_database  paras;
00401       paras.load(filename);
00402       
00403       std::string devname   = viennacl::ocl::current_device().name();
00404       
00405       // check if tune parameters for the current device are present
00406       std::string          device_str = "/parameters/devices/device[name='"+devname+"']";
00407       pugi::xpath_node_set device_res = paras.doc.select_nodes(device_str.c_str());
00408       
00409       if(device_res.size() == 0)
00410       {
00411           std::cout << "Tuner: There are no parameters for this device present!" << std::endl;
00412           // evaluate the parameters for this device?
00413       }
00414       
00415       // check if tune parameters for float exist
00416       std::string          numeric_str = device_str+"/tests/test[numeric='"+to_string<SCALARTYPE>::get()+"']";
00417       pugi::xpath_node_set numeric_res = paras.doc.select_nodes(numeric_str.c_str());
00418 
00419       if(numeric_res.size() > 0)
00420       {
00421           tune_impl<VclBasicType>(paras, numeric_str);
00422       }
00423       else
00424       {
00425           std::cout << "Tuner: There are no parameters for numeric type float present!" << std::endl;   
00426       }
00427 
00428   //    // check if tune parameters for double exist
00429   //    std::string          double_str = device_str+"/tests/test[numeric='"+val::dbl+"']";
00430   //    pugi::xpath_node_set double_res = paras.doc.select_nodes(double_str.c_str());
00431   // 
00432   //    if(double_res.size() > 0)
00433   //    {
00434   //       tune_impl<double>(paras, double_str);
00435   //    }
00436   //    else
00437   //    {
00438   //       std::cout << "Tuner: There are no parameters for numeric type double present!" << std::endl;   
00439   //    }
00440 
00441     }
00442 
00443   } // end namespace io
00444 
00445 } // end namespace viennacl
00446 
00447 #endif