ViennaCL - The Vienna Computing Library  1.2.0
context.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_OCL_CONTEXT_HPP_
2 #define VIENNACL_OCL_CONTEXT_HPP_
3 
4 /* =========================================================================
5  Copyright (c) 2010-2011, Institute for Microelectronics,
6  Institute for Analysis and Scientific Computing,
7  TU Wien.
8 
9  -----------------
10  ViennaCL - The Vienna Computing Library
11  -----------------
12 
13  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
14 
15  (A list of authors and contributors can be found in the PDF manual)
16 
17  License: MIT (X11), see file LICENSE in the base directory
18 ============================================================================= */
19 
24 #ifdef __APPLE__
25 #include <OpenCL/cl.h>
26 #else
27 #include <CL/cl.h>
28 #endif
29 
30 #include <algorithm>
31 #include <vector>
32 #include <map>
33 #include "viennacl/ocl/forwards.h"
34 #include "viennacl/ocl/handle.hpp"
35 #include "viennacl/ocl/program.hpp"
36 #include "viennacl/ocl/device.hpp"
39 
40 namespace viennacl
41 {
42  namespace ocl
43  {
44  class context
45  {
46  typedef std::vector< viennacl::ocl::program > ProgramContainer;
47 
48  public:
49  context() : initialized_(false),
50  device_type_(CL_DEVICE_TYPE_DEFAULT),
51  current_device_id(0),
52  default_device_num_(1) {}
53 
55 
56  std::size_t default_device_num() const { return default_device_num_; }
57 
59  void default_device_num(std::size_t new_num) { default_device_num_ = new_num; }
60 
62 
63  cl_device_type default_device_type()
64  {
65  return device_type_;
66  }
67 
69  void default_device_type(cl_device_type dtype)
70  {
71  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
72  std::cout << "ViennaCL: Setting new device type for context " << h_ << std::endl;
73  #endif
74  if (!initialized_)
75  device_type_ = dtype; //assume that the user provided a correct value
76  }
77 
79 
80  std::vector<viennacl::ocl::device> const & devices() const
81  {
82  return devices_;
83  }
84 
87  {
88  //std::cout << "Current device id in context: " << current_device_id << std::endl;
89  return devices_[current_device_id];
90  }
91 
93  void switch_device(size_t i)
94  {
95  assert(i >= 0 && i < devices_.size());
96  current_device_id = i;
97  }
98 
101  {
102  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
103  std::cout << "ViennaCL: Setting new current device for context " << h_ << std::endl;
104  #endif
105  bool found = false;
106  for (size_t i=0; i<devices_.size(); ++i)
107  {
108  if (devices_[i] == d)
109  {
110  found = true;
111  current_device_id = i;
112  break;
113  }
114  }
115  if (found == false)
116  std::cerr << "ViennaCL: Warning: Could not set device " << d.name() << " for context." << std::endl;
117  }
118 
121  {
122  assert(!initialized_ && "Device must be added to context before it is initialized!");
123  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
124  std::cout << "ViennaCL: Adding new device to context " << h_ << std::endl;
125  #endif
126  if (std::find(devices_.begin(), devices_.end(), d) == devices_.end())
127  devices_.push_back(d);
128  }
129 
131  void add_device(cl_device_id d)
132  {
133  assert(!initialized_ && "Device must be added to context before it is initialized!");
135  }
136 
137 
139 
141  void init()
142  {
143  init_new();
144  }
145 
147  void init(cl_context c)
148  {
149  init_existing(c);
150  }
151 
152 /* void existing_context(cl_context context_id)
153  {
154  assert(!initialized_ && "ViennaCL: FATAL error: Provided a new context for an already initialized context.");
155  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
156  std::cout << "ViennaCL: Reusing existing context " << h_ << std::endl;
157  #endif
158  h_ = context_id;
159  }*/
160 
162 
168  viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, unsigned int size, void * ptr = NULL)
169  {
170  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
171  std::cout << "ViennaCL: Creating memory of size " << size << " for context " << h_ << std::endl;
172  #endif
173  if (ptr)
174  flags |= CL_MEM_COPY_HOST_PTR;
175  cl_int err;
176  viennacl::ocl::handle<cl_mem> mem = clCreateBuffer(handle(), flags, size, ptr, &err);
177  VIENNACL_ERR_CHECK(err);
178  return mem;
179  }
180 
186  template < typename SCALARTYPE, typename A, template <typename, typename> class VectorType >
187  viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, const VectorType<SCALARTYPE, A> & _buffer)
188  {
189  return create_memory(flags, static_cast<cl_uint>(sizeof(SCALARTYPE) * _buffer.size()), (void*)&_buffer[0]);
190  }
191 
193 
195  void add_queue(cl_device_id dev, cl_command_queue q)
196  {
197  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
198  std::cout << "ViennaCL: Adding existing queue " << q << " for device " << dev << " to context " << h_ << std::endl;
199  #endif
200  queues_[dev].push_back(viennacl::ocl::command_queue(q, dev));
201  }
202 
204  void add_queue(cl_device_id dev)
205  {
206  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
207  std::cout << "ViennaCL: Adding new queue for device " << dev << " to context " << h_ << std::endl;
208  #endif
209  cl_int err;
210  viennacl::ocl::handle<cl_command_queue> temp = clCreateCommandQueue(handle(), dev, 0, &err);
211  VIENNACL_ERR_CHECK(err);
212 
213  queues_[dev].push_back(viennacl::ocl::command_queue(temp, dev));
214  }
215 
218 
219  //get queue for default device:
221  {
222  return queues_[devices_[current_device_id].id()][0];
223  }
224 
225  //get a particular queue:
227  viennacl::ocl::command_queue & get_queue(cl_device_id dev, size_t i = 0)
228  {
229  assert(i >= 0 && i < queues_.size() && "In class 'context': id invalid in get_queue()");
230  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
231  std::cout << "ViennaCL: Getting queue " << i << " for device " << dev << " in context " << h_ << std::endl;
232  #endif
233  unsigned int device_index;
234  for (device_index = 0; device_index < devices_.size(); ++device_index)
235  {
236  if (devices_[device_index] == dev)
237  break;
238  }
239 
240  assert(device_index < devices_.size() && "Device not within context");
241 
242  return queues_[devices_[device_index].id()][i];
243  }
244 
246 
248  viennacl::ocl::program & add_program(cl_program p, std::string const & prog_name)
249  {
250  programs_.push_back(viennacl::ocl::program(p, prog_name));
251  return programs_.back();
252  }
253 
256  viennacl::ocl::program & add_program(std::string const & source, std::string const & prog_name)
257  {
258  const char * source_text = source.c_str();
259  size_t source_size = source.size();
260  cl_int err;
261 
262  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
263  std::cout << "ViennaCL: Adding program '" << prog_name << "' to context " << h_ << std::endl;
264  #endif
265 
266  viennacl::ocl::handle<cl_program> temp = clCreateProgramWithSource(h_, 1, (const char **)&source_text, &source_size, &err);
267  VIENNACL_ERR_CHECK(err);
268 
269  err = clBuildProgram(temp, 0, NULL, NULL, NULL, NULL);
270  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_BUILD)
271  char buffer[1024];
272  cl_build_status status;
273  clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL);
274  clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, sizeof(char)*1024, &buffer, NULL);
275  std::cout << "Build Scalar: Err = " << err << " Status = " << status << std::endl;
276  std::cout << "Log: " << buffer << std::endl;
277  //std::cout << "Sources: " << source << std::endl;
278  #endif
279  VIENNACL_ERR_CHECK(err);
280 
281  programs_.push_back(viennacl::ocl::program(temp, prog_name));
282 
283  return programs_.back();
284  }
285 
287  viennacl::ocl::program & get_program(std::string const & name)
288  {
289  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
290  std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
291  #endif
292  for (ProgramContainer::iterator it = programs_.begin();
293  it != programs_.end();
294  ++it)
295  {
296  if (it->name() == name)
297  return *it;
298  }
299  std::cerr << "Could not find program '" << name << "'" << std::endl;
300  assert(!"In class 'context': name invalid in get_program()");
301  return programs_[0]; //return a defined object
302  }
303 
306  {
307  assert(id >= 0 && id < programs_.size() && "In class 'context': id invalid in get_program()");
308  return programs_[id];
309  }
310 
312  size_t program_num() { return programs_.size(); }
313 
315  size_t device_num() { return devices_.size(); }
316 
318  const viennacl::ocl::handle<cl_context> & handle() const { return h_; }
319 
321  bool operator<(context const & other) const
322  {
323  return h_ < other.h_;
324  }
325 
326  private:
328  void init_new()
329  {
330  assert(!initialized_ && "ViennaCL FATAL error: Context already created!");
331 
332  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
333  std::cout << "ViennaCL: Initializing new ViennaCL context." << std::endl;
334  #endif
335 
336  cl_int err;
337  std::vector<cl_device_id> device_id_array;
338  if (devices_.empty()) //get the default device if user has not yet specified a list of devices
339  {
340  //create an OpenCL context for the provided devices:
341  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
342  std::cout << "ViennaCL: Setting all devices for context..." << std::endl;
343  #endif
344 
345  platform pf;
346  std::vector<device> devices = pf.devices(device_type_);
347  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
348  std::cout << "ViennaCL: Number of devices for context: " << devices.size() << std::endl;
349  #endif
350  for (size_t i=0; i<devices.size(); ++i)
351  devices_.push_back(devices[i]);
352 
353  if (devices.size() == 0)
354  {
355  std::cerr << "ViennaCL: FATAL ERROR: No devices of type '";
356  switch (device_type_)
357  {
358  case CL_DEVICE_TYPE_CPU: std::cout << "CPU"; break;
359  case CL_DEVICE_TYPE_GPU: std::cout << "CPU"; break;
360  case CL_DEVICE_TYPE_ACCELERATOR: std::cout << "ACCELERATOR"; break;
361  case CL_DEVICE_TYPE_DEFAULT: std::cout << "DEFAULT"; break;
362  default:
363  std::cout << "UNKNOWN" << std::endl;
364  }
365  std::cout << "' found!" << std::endl;
366  }
367  }
368 
369  //extract list of device ids:
370  for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
371  iter != devices_.end();
372  ++iter)
373  device_id_array.push_back(iter->id());
374 
375  cl_uint device_num = std::max(default_device_num_, device_id_array.size());
376  h_ = clCreateContext(0,
377  device_num,
378  &(device_id_array[0]),
379  NULL, NULL, &err);
380  VIENNACL_ERR_CHECK(err);
381 
382  initialized_ = true;
383  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
384  std::cout << "ViennaCL: Initialization of new ViennaCL context done." << std::endl;
385  #endif
386  }
387 
389  void init_existing(cl_context c)
390  {
391  assert(!initialized_ && "ViennaCL FATAL error: Context already created!");
392  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
393  std::cout << "ViennaCL: Initialization of ViennaCL context from existing context." << std::endl;
394  #endif
395 
396  //set context handle:
397  h_ = c;
398 
399  if (devices_.empty())
400  {
401  //get devices for context:
402  cl_int err;
403  cl_uint num_devices;
404  size_t temp;
405  //Note: The obvious
406  // err = clGetContextInfo(h_, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL);
407  //does not work with NVIDIA OpenCL stack!
408  err = clGetContextInfo(h_, CL_CONTEXT_DEVICES, VIENNACL_OCL_MAX_DEVICE_NUM * sizeof(cl_device_id), NULL, &temp);
409  VIENNACL_ERR_CHECK(err);
410  assert(temp > 0 && "ViennaCL: FATAL error: Provided context does not contain any devices!");
411  num_devices = temp / sizeof(cl_device_id);
412 
413  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
414  std::cout << "ViennaCL: Reusing context with " << num_devices << " devices." << std::endl;
415  #endif
416 
417  std::vector<cl_device_id> device_ids(num_devices);
418  err = clGetContextInfo(h_, CL_CONTEXT_DEVICES, num_devices * sizeof(cl_device_id), &(device_ids[0]), NULL);
419  VIENNACL_ERR_CHECK(err);
420 
421  for (size_t i=0; i<num_devices; ++i)
422  devices_.push_back(viennacl::ocl::device(device_ids[i]));
423  }
424  current_device_id = 0;
425 
426  initialized_ = true;
427  #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
428  std::cout << "ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
429  #endif
430  }
431 
432 
433  bool initialized_;
434  cl_device_type device_type_;
436  std::vector< viennacl::ocl::device > devices_;
437  unsigned int current_device_id;
438  std::size_t default_device_num_;
439  ProgramContainer programs_;
440  std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
441  }; //context
442 
443  }
444 }
445 
446 #endif