• Main Page
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

/data/development/ViennaCL/dev/viennacl/ocl/context.hpp

Go to the documentation of this file.
00001 #ifndef VIENNACL_OCL_CONTEXT_HPP_
00002 #define VIENNACL_OCL_CONTEXT_HPP_
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2011, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008 
00009                             -----------------
00010                   ViennaCL - The Vienna Computing Library
00011                             -----------------
00012 
00013    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00014                
00015    (A list of authors and contributors can be found in the PDF manual)
00016 
00017    License:         MIT (X11), see file LICENSE in the base directory
00018 ============================================================================= */
00019 
00024 #ifdef __APPLE__
00025 #include <OpenCL/cl.h>
00026 #else
00027 #include <CL/cl.h>
00028 #endif
00029 
00030 #include <algorithm>
00031 #include <vector>
00032 #include <map>
00033 #include "viennacl/ocl/forwards.h"
00034 #include "viennacl/ocl/handle.hpp"
00035 #include "viennacl/ocl/program.hpp"
00036 #include "viennacl/ocl/device.hpp"
00037 #include "viennacl/ocl/platform.hpp"
00038 #include "viennacl/ocl/command_queue.hpp"
00039 
00040 namespace viennacl
00041 {
00042   namespace ocl
00043   {
00044     class context
00045     {
00046       typedef std::vector< viennacl::ocl::program >   ProgramContainer;
00047       
00048       public:
00049         context() : initialized_(false),
00050                     device_type_(CL_DEVICE_TYPE_DEFAULT),
00051                     current_device_id(0),
00052                     default_device_num_(1) {}
00053         
00055 
00056         std::size_t default_device_num() const { return default_device_num_; }
00057         
00059         void default_device_num(std::size_t new_num) { default_device_num_ = new_num; }
00060         
00062 
00063         cl_device_type default_device_type()
00064         {
00065           return device_type_;
00066         }
00067         
00069         void default_device_type(cl_device_type dtype) 
00070         { 
00071           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00072           std::cout << "ViennaCL: Setting new device type for context " << h_ << std::endl;
00073           #endif
00074           if (!initialized_)
00075             device_type_ = dtype; //assume that the user provided a correct value
00076         }
00077         
00079 
00080         std::vector<viennacl::ocl::device> const & devices() const
00081         {
00082           return devices_;
00083         }
00084         
00086         viennacl::ocl::device const & current_device() const
00087         {
00088           //std::cout << "Current device id in context: " << current_device_id << std::endl;
00089           return devices_[current_device_id];
00090         }
00091         
00093         void switch_device(size_t i)
00094         {
00095           assert(i >= 0 && i < devices_.size());
00096           current_device_id = i;
00097         }
00098 
00100         void switch_device(viennacl::ocl::device const & d)
00101         {
00102           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00103           std::cout << "ViennaCL: Setting new current device for context " << h_ << std::endl;
00104           #endif
00105           bool found = false;
00106           for (size_t i=0; i<devices_.size(); ++i)
00107           {
00108             if (devices_[i] == d)
00109             {
00110               found = true;
00111               current_device_id = i;
00112               break;
00113             }
00114           }
00115           if (found == false)
00116             std::cerr << "ViennaCL: Warning: Could not set device " << d.name() << " for context." << std::endl;
00117         }
00118         
00120         void add_device(viennacl::ocl::device const & d)
00121         {
00122           assert(!initialized_ && "Device must be added to context before it is initialized!");
00123           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00124           std::cout << "ViennaCL: Adding new device to context " << h_ << std::endl;
00125           #endif
00126           if (std::find(devices_.begin(), devices_.end(), d) != devices_.end())
00127             devices_.push_back(d);
00128         }
00129 
00131         void add_device(cl_device_id d)
00132         {
00133           assert(!initialized_ && "Device must be added to context before it is initialized!");
00134           add_device(viennacl::ocl::device(d));
00135         }
00136 
00137 
00139         
00141         void init()
00142         {
00143           init_new();
00144         }
00145 
00147         void init(cl_context c)
00148         {
00149           init_existing(c);
00150         }
00151 
00152 /*        void existing_context(cl_context context_id)
00153         {
00154           assert(!initialized_ && "ViennaCL: FATAL error: Provided a new context for an already initialized context.");
00155           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00156           std::cout << "ViennaCL: Reusing existing context " << h_ << std::endl;
00157           #endif
00158           h_ = context_id;
00159         }*/
00160         
00162 
00168         viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, unsigned int size, void * ptr = NULL)
00169         {
00170           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00171           std::cout << "ViennaCL: Creating memory of size " << size << " for context " << h_ << std::endl;
00172           #endif
00173           if (ptr)
00174             flags |= CL_MEM_COPY_HOST_PTR;
00175           cl_int err;
00176           viennacl::ocl::handle<cl_mem> mem = clCreateBuffer(handle(), flags, size, ptr, &err);
00177           VIENNACL_ERR_CHECK(err);
00178           return mem;
00179         }
00180 
00186         template < typename SCALARTYPE, typename A, template <typename, typename> class VectorType >
00187         viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, const VectorType<SCALARTYPE, A> & _buffer)
00188         {
00189           return create_memory(flags, static_cast<cl_uint>(sizeof(SCALARTYPE) * _buffer.size()), (void*)&_buffer[0]);
00190         }
00191         
00193         
00195         void add_queue(cl_device_id dev, cl_command_queue q)
00196         {
00197           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00198           std::cout << "ViennaCL: Adding existing queue " << q << " for device " << dev << " to context " << h_ << std::endl;
00199           #endif
00200           queues_[dev].push_back(viennacl::ocl::command_queue(q, dev));
00201         }
00202         
00204         void add_queue(cl_device_id dev)
00205         {
00206           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00207           std::cout << "ViennaCL: Adding new queue for device " << dev << " to context " << h_ << std::endl;
00208           #endif
00209           cl_int err;
00210           viennacl::ocl::handle<cl_command_queue> temp = clCreateCommandQueue(handle(), dev, 0, &err);
00211           VIENNACL_ERR_CHECK(err);
00212           
00213           queues_[dev].push_back(viennacl::ocl::command_queue(temp, dev));
00214         }
00215 
00217         void add_queue(viennacl::ocl::device d) { add_queue(d.id()); }
00218 
00219         //get queue for default device:
00220         viennacl::ocl::command_queue & get_queue()
00221         {
00222           return queues_[devices_[current_device_id].id()][0];
00223         }
00224         
00225         //get a particular queue:
00227         viennacl::ocl::command_queue & get_queue(cl_device_id dev, size_t i = 0)
00228         {
00229           assert(i >= 0 && i < queues_.size() && "In class 'context': id invalid in get_queue()");
00230           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00231           std::cout << "ViennaCL: Getting queue " << i << " for device " << dev << " in context " << h_ << std::endl;
00232           #endif
00233           unsigned int device_index;
00234           for (device_index = 0; device_index < devices_.size(); ++device_index)
00235           {
00236             if (devices_[device_index] == dev)
00237               break;
00238           }
00239           
00240           assert(device_index < devices_.size() && "Device not within context");
00241           
00242           return queues_[devices_[device_index].id()][i];
00243         }
00244         
00246 
00248         viennacl::ocl::program & add_program(cl_program p, std::string const & prog_name)
00249         {
00250           programs_.push_back(viennacl::ocl::program(p, prog_name));
00251           return programs_.back();
00252         }
00253         
00256         viennacl::ocl::program & add_program(std::string const & source, std::string const & prog_name)
00257         {
00258           const char * source_text = source.c_str();
00259           size_t source_size = source.size();
00260           cl_int err;
00261           
00262           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00263           std::cout << "ViennaCL: Adding program '" << prog_name << "' to context " << h_ << std::endl;
00264           #endif
00265           
00266           viennacl::ocl::handle<cl_program> temp = clCreateProgramWithSource(h_, 1, (const char **)&source_text, &source_size, &err);
00267           VIENNACL_ERR_CHECK(err);
00268           
00269           err = clBuildProgram(temp, 0, NULL, NULL, NULL, NULL);
00270           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_BUILD)
00271             char buffer[1024];
00272             cl_build_status status;
00273             clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL);
00274             clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, sizeof(char)*1024, &buffer, NULL);
00275             std::cout << "Build Scalar: Err = " << err << " Status = " << status << std::endl;
00276             std::cout << "Log: " << buffer << std::endl;
00277             //std::cout << "Sources: " << source << std::endl;
00278           #endif
00279           VIENNACL_ERR_CHECK(err);
00280 
00281           programs_.push_back(viennacl::ocl::program(temp, prog_name));
00282           
00283           return programs_.back();
00284         }
00285         
00287         viennacl::ocl::program & get_program(std::string const & name)
00288         {
00289           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00290           std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
00291           #endif
00292           for (ProgramContainer::iterator it = programs_.begin();
00293                 it != programs_.end();
00294                 ++it)
00295           {
00296             if (it->name() == name)
00297               return *it;
00298           }
00299           std::cerr << "Could not find program '" << name << "'" << std::endl;
00300           assert(!"In class 'context': name invalid in get_program()");
00301           return programs_[0];  //return a defined object
00302         }
00303         
00305         viennacl::ocl::program & get_program(size_t id)
00306         {
00307           assert(id >= 0 && id < programs_.size() && "In class 'context': id invalid in get_program()");
00308           return programs_[id];
00309         }
00310         
00312         size_t program_num() { return programs_.size(); }
00313 
00315         size_t device_num() { return devices_.size(); }
00316         
00318         const viennacl::ocl::handle<cl_context> & handle() const { return h_; }
00319         
00321         bool operator<(context const & other) const
00322         {
00323           return h_ < other.h_;
00324         }
00325         
00326       private:
00328         void init_new()
00329         {
00330           assert(!initialized_ && "ViennaCL FATAL error: Context already created!");
00331 
00332           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00333           std::cout << "ViennaCL: Initializing new ViennaCL context." << std::endl;
00334           #endif
00335           
00336           cl_int err;
00337           std::vector<cl_device_id> device_id_array;
00338           if (devices_.empty()) //get the default device if user has not yet specified a list of devices
00339           {
00340             //create an OpenCL context for the provided devices:
00341             #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00342             std::cout << "ViennaCL: Setting all devices for context..." << std::endl;
00343             #endif
00344             
00345             platform pf;
00346             std::vector<device> devices = pf.devices(device_type_);
00347             #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00348             std::cout << "ViennaCL: Number of devices for context: " << devices.size() << std::endl;
00349             #endif
00350             for (size_t i=0; i<devices.size(); ++i)
00351               devices_.push_back(devices[i]);
00352             
00353             if (devices.size() == 0)
00354             {
00355               std::cerr << "ViennaCL: FATAL ERROR: No devices of type '";
00356               switch (device_type_)
00357               {
00358                 case CL_DEVICE_TYPE_CPU:          std::cout << "CPU"; break;
00359                 case CL_DEVICE_TYPE_GPU:          std::cout << "CPU"; break;
00360                 case CL_DEVICE_TYPE_ACCELERATOR:  std::cout << "ACCELERATOR"; break;
00361                 case CL_DEVICE_TYPE_DEFAULT:      std::cout << "DEFAULT"; break;
00362                 default:
00363                   std::cout << "UNKNOWN" << std::endl;
00364               }
00365               std::cout << "' found!" << std::endl;
00366             }
00367           }
00368           
00369           //extract list of device ids:
00370           for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
00371                                                                     iter != devices_.end();
00372                                                                   ++iter)
00373             device_id_array.push_back(iter->id());
00374             
00375           cl_uint device_num = std::max(default_device_num_, device_id_array.size());
00376           h_ = clCreateContext(0, 
00377                                device_num,
00378                                &(device_id_array[0]),
00379                                NULL, NULL, &err);
00380           VIENNACL_ERR_CHECK(err);
00381           
00382           initialized_ = true;
00383           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00384           std::cout << "ViennaCL: Initialization of new ViennaCL context done." << std::endl;
00385           #endif
00386         }
00387         
00389         void init_existing(cl_context c)
00390         {
00391           assert(!initialized_ && "ViennaCL FATAL error: Context already created!");
00392           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00393           std::cout << "ViennaCL: Initialization of ViennaCL context from existing context." << std::endl;
00394           #endif
00395           
00396           //set context handle:
00397           h_ = c;
00398           
00399           if (devices_.empty())
00400           {
00401             //get devices for context:
00402             cl_int err;
00403             cl_uint num_devices;
00404             size_t temp;
00405             //Note: The obvious
00406             //  err = clGetContextInfo(h_, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL);
00407             //does not work with NVIDIA OpenCL stack!
00408             err = clGetContextInfo(h_, CL_CONTEXT_DEVICES, VIENNACL_OCL_MAX_DEVICE_NUM * sizeof(cl_device_id), NULL, &temp);
00409             VIENNACL_ERR_CHECK(err);
00410             assert(temp > 0 && "ViennaCL: FATAL error: Provided context does not contain any devices!");
00411             num_devices = temp / sizeof(cl_device_id);
00412             
00413             #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00414             std::cout << "ViennaCL: Reusing context with " << num_devices << " devices." << std::endl;
00415             #endif
00416             
00417             std::vector<cl_device_id> device_ids(num_devices);
00418             err = clGetContextInfo(h_, CL_CONTEXT_DEVICES, num_devices * sizeof(cl_device_id), &(device_ids[0]), NULL);
00419             VIENNACL_ERR_CHECK(err);
00420             
00421             for (size_t i=0; i<num_devices; ++i)
00422               devices_.push_back(viennacl::ocl::device(device_ids[i]));
00423           }
00424           current_device_id = 0;
00425           
00426           initialized_ = true;
00427           #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
00428           std::cout << "ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
00429           #endif
00430         }       
00431         
00432         
00433         bool initialized_;
00434         cl_device_type device_type_;
00435         viennacl::ocl::handle<cl_context> h_;
00436         std::vector< viennacl::ocl::device > devices_;
00437         unsigned int current_device_id;
00438         std::size_t default_device_num_;
00439         ProgramContainer programs_;
00440         std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
00441     }; //context
00442     
00443   }
00444 }
00445 
00446 #endif

Generated on Fri Dec 30 2011 23:20:43 for ViennaCL - The Vienna Computing Library by  doxygen 1.7.1