00001 #ifndef VIENNACL_OCL_CONTEXT_HPP_
00002 #define VIENNACL_OCL_CONTEXT_HPP_
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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;
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
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
00153
00154
00155
00156
00157
00158
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
00220 viennacl::ocl::command_queue & get_queue()
00221 {
00222 return queues_[devices_[current_device_id].id()][0];
00223 }
00224
00225
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
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];
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())
00339 {
00340
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
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
00397 h_ = c;
00398
00399 if (devices_.empty())
00400 {
00401
00402 cl_int err;
00403 cl_uint num_devices;
00404 size_t temp;
00405
00406
00407
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 };
00442
00443 }
00444 }
00445
00446 #endif