00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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;
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
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
00142
00143
00144
00145
00146
00147
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
00209 viennacl::ocl::command_queue & get_queue()
00210 {
00211 return queues_[devices_[current_device_id].id()][0];
00212 }
00213
00214
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];
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())
00327 {
00328
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
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
00381 h_ = c;
00382
00383 if (devices_.empty())
00384 {
00385
00386 cl_int err;
00387 cl_uint num_devices;
00388 size_t temp;
00389
00390
00391
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 };
00425
00426 }
00427 }
00428
00429 #endif