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