ViennaCL - The Vienna Computing Library  1.6.1
Free open-source GPU-accelerated linear algebra and solver library.
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-2014, Institute for Microelectronics,
6  Institute for Analysis and Scientific Computing,
7  TU Wien.
8  Portions of this software are copyright by UChicago Argonne, LLC.
9 
10  -----------------
11  ViennaCL - The Vienna Computing Library
12  -----------------
13 
14  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
15 
16  (A list of authors and contributors can be found in the PDF manual)
17 
18  License: MIT (X11), see file LICENSE in the base directory
19 ============================================================================= */
20 
25 #ifdef __APPLE__
26 #include <OpenCL/cl.h>
27 #else
28 #include <CL/cl.h>
29 #endif
30 
31 #include <algorithm>
32 #include <fstream>
33 #include <vector>
34 #include <map>
35 #include <cstdlib>
36 #include "viennacl/ocl/forwards.h"
37 #include "viennacl/ocl/handle.hpp"
38 #include "viennacl/ocl/kernel.hpp"
39 #include "viennacl/ocl/program.hpp"
40 #include "viennacl/ocl/device.hpp"
43 #include "viennacl/tools/sha1.hpp"
45 namespace viennacl
46 {
47 namespace ocl
48 {
54 class context
55 {
56  typedef std::vector< tools::shared_ptr<viennacl::ocl::program> > program_container_type;
57 
58 public:
59  context() : initialized_(false),
60  device_type_(CL_DEVICE_TYPE_DEFAULT),
61  current_device_id_(0),
62  default_device_num_(1),
63  pf_index_(0),
64  current_queue_id_(0)
65  {
66  if (std::getenv("VIENNACL_CACHE_PATH"))
67  cache_path_ = std::getenv("VIENNACL_CACHE_PATH");
68  else
69  cache_path_ = "";
70  }
71 
73 
74  std::string cache_path() const { return cache_path_; }
75 
77  void cache_path(std::string new_path) { cache_path_ = new_path; }
78 
80 
81  vcl_size_t default_device_num() const { return default_device_num_; }
82 
84  void default_device_num(vcl_size_t new_num) { default_device_num_ = new_num; }
85 
87 
88  cl_device_type default_device_type()
89  {
90  return device_type_;
91  }
92 
94  void default_device_type(cl_device_type dtype)
95  {
96 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
97  std::cout << "ViennaCL: Setting new device type for context " << h_ << std::endl;
98 #endif
99  if (!initialized_)
100  device_type_ = dtype; //assume that the user provided a correct value
101  }
102 
104 
105  std::vector<viennacl::ocl::device> const & devices() const
106  {
107  return devices_;
108  }
109 
112  {
113  //std::cout << "Current device id in context: " << current_device_id_ << std::endl;
114  return devices_[current_device_id_];
115  }
116 
119  {
120  assert(i < devices_.size() && bool("Provided device index out of range!"));
121  current_device_id_ = i;
122  }
123 
126  {
127 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
128  std::cout << "ViennaCL: Setting new current device for context " << h_ << std::endl;
129 #endif
130  bool found = false;
131  for (vcl_size_t i=0; i<devices_.size(); ++i)
132  {
133  if (devices_[i] == d)
134  {
135  found = true;
136  current_device_id_ = i;
137  break;
138  }
139  }
140  if (found == false)
141  std::cerr << "ViennaCL: Warning: Could not set device " << d.name() << " for context." << std::endl;
142  }
143 
146  {
147  assert(!initialized_ && bool("Device must be added to context before it is initialized!"));
148 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
149  std::cout << "ViennaCL: Adding new device to context " << h_ << std::endl;
150 #endif
151  if (std::find(devices_.begin(), devices_.end(), d) == devices_.end())
152  devices_.push_back(d);
153  }
154 
156  void add_device(cl_device_id d)
157  {
158  assert(!initialized_ && bool("Device must be added to context before it is initialized!"));
160  }
161 
162 
164 
166  void init()
167  {
168  init_new();
169  }
170 
172  void init(cl_context c)
173  {
174  init_existing(c);
175  }
176 
177  /* void existing_context(cl_context context_id)
178  {
179  assert(!initialized_ && bool("ViennaCL: FATAL error: Provided a new context for an already initialized context."));
180  #i#if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
181  std::cout << "ViennaCL: Reusing existing context " << h_ << std::endl;
182  #e#endif
183  h_ = context_id;
184  }*/
185 
187 
195  cl_mem create_memory_without_smart_handle(cl_mem_flags flags, unsigned int size, void * ptr = NULL) const
196  {
197 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
198  std::cout << "ViennaCL: Creating memory of size " << size << " for context " << h_ << " (unsafe, returning cl_mem directly)" << std::endl;
199 #endif
200  if (ptr)
201  flags |= CL_MEM_COPY_HOST_PTR;
202  cl_int err;
203  cl_mem mem = clCreateBuffer(h_.get(), flags, size, ptr, &err);
204  VIENNACL_ERR_CHECK(err);
205  return mem;
206  }
207 
208 
215  viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, unsigned int size, void * ptr = NULL) const
216  {
217  return viennacl::ocl::handle<cl_mem>(create_memory_without_smart_handle(flags, size, ptr), *this);
218  }
219 
225  template< typename NumericT, typename A, template<typename, typename> class VectorType >
226  viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, const VectorType<NumericT, A> & buffer) const
227  {
228  return viennacl::ocl::handle<cl_mem>(create_memory_without_smart_handle(flags, static_cast<cl_uint>(sizeof(NumericT) * buffer.size()), (void*)&buffer[0]), *this);
229  }
230 
232 
234  void add_queue(cl_device_id dev, cl_command_queue q)
235  {
236 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
237  std::cout << "ViennaCL: Adding existing queue " << q << " for device " << dev << " to context " << h_ << std::endl;
238 #endif
239  viennacl::ocl::handle<cl_command_queue> queue_handle(q, *this);
240  queues_[dev].push_back(viennacl::ocl::command_queue(queue_handle));
241  queues_[dev].back().handle().inc();
242  }
243 
245  void add_queue(cl_device_id dev)
246  {
247 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
248  std::cout << "ViennaCL: Adding new queue for device " << dev << " to context " << h_ << std::endl;
249 #endif
250  cl_int err;
251 #ifdef VIENNACL_PROFILING_ENABLED
252  viennacl::ocl::handle<cl_command_queue> temp(clCreateCommandQueue(h_.get(), dev, CL_QUEUE_PROFILING_ENABLE, &err), *this);
253 #else
254  viennacl::ocl::handle<cl_command_queue> temp(clCreateCommandQueue(h_.get(), dev, 0, &err), *this);
255 #endif
256  VIENNACL_ERR_CHECK(err);
257 
258  queues_[dev].push_back(viennacl::ocl::command_queue(temp));
259  }
260 
263 
264  //get queue for default device:
266  {
267 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
268  std::cout << "ViennaCL: Getting queue for device " << devices_[current_device_id_].name() << " in context " << h_ << std::endl;
269  std::cout << "ViennaCL: Current queue id " << current_queue_id_ << std::endl;
270 #endif
271 
272  return queues_[devices_[current_device_id_].id()][current_queue_id_];
273  }
274 
276  {
277  typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
278 
279 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
280  std::cout << "ViennaCL: Getting const queue for device " << devices_[current_device_id_].name() << " in context " << h_ << std::endl;
281  std::cout << "ViennaCL: Current queue id " << current_queue_id_ << std::endl;
282 #endif
283 
284  // find queue:
285  QueueContainer::const_iterator it = queues_.find(devices_[current_device_id_].id());
286  if (it != queues_.end()) {
287 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
288  std::cout << "ViennaCL: Queue handle " << (it->second)[current_queue_id_].handle() << std::endl;
289 #endif
290  return (it->second)[current_queue_id_];
291  }
292 
293  std::cerr << "ViennaCL: FATAL ERROR: Could not obtain current command queue!" << std::endl;
294  std::cout << "Number of queues in context: " << queues_.size() << std::endl;
295  std::cout << "Number of devices in context: " << devices_.size() << std::endl;
296  throw "queue not found!";
297 
298  //return ((*it)->second)[current_queue_id_];
299  }
300 
301  //get a particular queue:
304  {
305  if (i >= queues_[dev].size())
306  throw invalid_command_queue();
307 
308 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
309  std::cout << "ViennaCL: Getting queue " << i << " for device " << dev << " in context " << h_ << std::endl;
310 #endif
311  unsigned int device_index;
312  for (device_index = 0; device_index < devices_.size(); ++device_index)
313  {
314  if (devices_[device_index] == dev)
315  break;
316  }
317 
318  assert(device_index < devices_.size() && bool("Device not within context"));
319 
320  return queues_[devices_[device_index].id()][i];
321  }
322 
324  // TODO: work out the const issues
326  {
327  return queues_[devices_[current_device_id_].id()][current_queue_id_];
328  }
329 
332  {
333  assert(i < queues_[devices_[current_device_id_].id()].size() && bool("In class 'context': Provided queue index out of range for device!"));
334  current_queue_id_ = i;
335  }
336 
339  {
340 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
341  std::cout << "ViennaCL: Setting new current queue for context " << h_ << std::endl;
342 #endif
343  bool found = false;
344  typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
345 
346  // For each device:
347  vcl_size_t j = 0;
348  for (QueueContainer::const_iterator it=queues_.begin(); it != queues_.end(); it++,j++)
349  {
350  const std::vector<viennacl::ocl::command_queue> & qv = (it->second);
351  // For each queue candidate
352  for (vcl_size_t i=0; i<qv.size(); ++i)
353  {
354  if (qv[i] == q)
355  {
356  found = true;
357  current_device_id_ = j;
358  current_queue_id_ = i;
359  break;
360  }
361  }
362  }
363  if (found == false)
364  std::cerr << "ViennaCL: Warning: Could not set queue " << q.handle().get() << " for context." << std::endl;
365  }
366 
368 
370  viennacl::ocl::program & add_program(cl_program p, std::string const & prog_name)
371  {
372  programs_.push_back(tools::shared_ptr<ocl::program>(new viennacl::ocl::program(p, *this, prog_name)));
373 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
374  std::cout << "ViennaCL: Adding program '" << prog_name << "' with cl_program to context " << h_ << std::endl;
375 #endif
376  return *programs_.back();
377  }
378 
381  viennacl::ocl::program & add_program(std::string const & source, std::string const & prog_name)
382  {
383  const char * source_text = source.c_str();
384  vcl_size_t source_size = source.size();
385  cl_int err;
386 
387 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
388  std::cout << "ViennaCL: Adding program '" << prog_name << "' with source to context " << h_ << std::endl;
389 #endif
390 
391  cl_program temp = 0;
392 
393  //
394  // Retrieves the program in the cache
395  //
396  if (cache_path_.size())
397  {
398 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
399  std::cout << "ViennaCL: Cache at " << cache_path_ << std::endl;
400 #endif
401 
402  std::string prefix;
403  for(std::vector< viennacl::ocl::device >::const_iterator it = devices_.begin(); it != devices_.end(); ++it)
404  prefix += it->name() + it->vendor() + it->driver_version();
405  std::string sha1 = tools::sha1(prefix + source);
406 
407  std::ifstream cached((cache_path_+sha1).c_str(),std::ios::binary);
408  if (cached)
409  {
410  vcl_size_t len;
411  std::vector<unsigned char> buffer;
412 
413  cached.read((char*)&len, sizeof(vcl_size_t));
414  buffer.resize(len);
415  cached.read((char*)buffer.data(), std::streamsize(len));
416 
417  cl_int status;
418  cl_device_id devid = devices_[0].id();
419  const unsigned char * bufdata = buffer.data();
420  temp = clCreateProgramWithBinary(h_.get(),1,&devid,&len, &bufdata,&status,&err);
421  VIENNACL_ERR_CHECK(err);
422  }
423  }
424 
425  if (!temp)
426  {
427  temp = clCreateProgramWithSource(h_.get(), 1, (const char **)&source_text, &source_size, &err);
428  VIENNACL_ERR_CHECK(err);
429  }
430 
431  const char * options = build_options_.c_str();
432  err = clBuildProgram(temp, 0, NULL, options, NULL, NULL);
433 #ifndef VIENNACL_BUILD_INFO
434  if (err != CL_SUCCESS)
435 #endif
436  {
437  cl_build_status status;
438  clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL);
439  std::cout << "Build Status = " << status << " ( Err = " << err << " )" << std::endl;
440 
441  char *build_log;
442  size_t ret_val_size; // don't use vcl_size_t here
443  err = clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
444  build_log = new char[ret_val_size+1];
445  err = clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
446  build_log[ret_val_size] = '\0';
447  std::cout << "Log: " << build_log << std::endl;
448  delete[] build_log;
449 
450  std::cout << "Sources: " << source << std::endl;
451  }
452  VIENNACL_ERR_CHECK(err);
453 
454  //
455  // Store the program in the cache
456  //
457  if (cache_path_.size())
458  {
459  vcl_size_t len;
460 
461  std::vector<vcl_size_t> sizes(devices_.size());
462  clGetProgramInfo(temp,CL_PROGRAM_BINARY_SIZES,0,NULL,&len);
463  clGetProgramInfo(temp,CL_PROGRAM_BINARY_SIZES,len,(void*)sizes.data(),NULL);
464 
465  std::vector<unsigned char*> binaries;
466  for (vcl_size_t i = 0; i < devices_.size(); ++i)
467  binaries.push_back(new unsigned char[sizes[i]]);
468 
469  clGetProgramInfo(temp,CL_PROGRAM_BINARIES,0,NULL,&len);
470  clGetProgramInfo(temp,CL_PROGRAM_BINARIES,len,binaries.data(),NULL);
471 
472  std::string prefix;
473  for(std::vector< viennacl::ocl::device >::const_iterator it = devices_.begin(); it != devices_.end(); ++it)
474  prefix += it->name() + it->vendor() + it->driver_version();
475  std::string sha1 = tools::sha1(prefix + source);
476  std::ofstream cached((cache_path_+sha1).c_str(),std::ios::binary);
477 
478  cached.write((char*)&sizes[0], sizeof(vcl_size_t));
479  cached.write((char*)binaries[0], std::streamsize(sizes[0]));
480 
481  for (vcl_size_t i = 0; i < devices_.size(); ++i)
482  delete[] binaries[i];
483 
484  VIENNACL_ERR_CHECK(err);
485  }
486 
487 
488  programs_.push_back(tools::shared_ptr<ocl::program>(new ocl::program(temp, *this, prog_name)));
489 
490  viennacl::ocl::program & prog = *programs_.back();
491 
492  //
493  // Extract kernels
494  //
495  cl_kernel kernels[1024];
496  cl_uint num_kernels_in_prog;
497  err = clCreateKernelsInProgram(prog.handle().get(), 1024, kernels, &num_kernels_in_prog);
498  VIENNACL_ERR_CHECK(err);
499 
500  for (cl_uint i=0; i<num_kernels_in_prog; ++i)
501  {
502  char kernel_name[128];
503  err = clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAME, 128, kernel_name, NULL);
504  prog.add_kernel(kernels[i], std::string(kernel_name));
505  }
506 
507 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
508  std::cout << "ViennaCL: Stored program '" << programs_.back()->name() << "' in context " << h_ << std::endl;
509  std::cout << "ViennaCL: There is/are " << programs_.size() << " program(s)" << std::endl;
510 #endif
511 
512  return prog;
513  }
514 
516  void delete_program(std::string const & name)
517  {
518 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
519  std::cout << "ViennaCL: Deleting program '" << name << "' from context " << h_ << std::endl;
520 #endif
521  for (program_container_type::iterator it = programs_.begin();
522  it != programs_.end();
523  ++it)
524  {
525  if ((*it)->name() == name)
526  {
527  programs_.erase(it);
528  return;
529  }
530  }
531  }
532 
534  viennacl::ocl::program & get_program(std::string const & name)
535  {
536 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
537  std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
538  std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
539 #endif
540  for (program_container_type::iterator it = programs_.begin();
541  it != programs_.end();
542  ++it)
543  {
544  //std::cout << "Name: " << (*it)->name() << std::endl;
545  if ((*it)->name() == name)
546  return **it;
547  }
548  std::cerr << "ViennaCL: Could not find program '" << name << "'" << std::endl;
549  throw "In class 'context': name invalid in get_program()";
550  //return programs_[0]; //return a defined object
551  }
552 
553  viennacl::ocl::program const & get_program(std::string const & name) const
554  {
555 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
556  std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
557  std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
558 #endif
559  for (program_container_type::const_iterator it = programs_.begin();
560  it != programs_.end();
561  ++it)
562  {
563  //std::cout << "Name: " << (*it)->name() << std::endl;
564  if ((*it)->name() == name)
565  return **it;
566  }
567  std::cerr << "ViennaCL: Could not find program '" << name << "'" << std::endl;
568  throw "In class 'context': name invalid in get_program()";
569  //return programs_[0]; //return a defined object
570  }
571 
573  bool has_program(std::string const & name)
574  {
575  for (program_container_type::iterator it = programs_.begin();
576  it != programs_.end();
577  ++it)
578  {
579  if ((*it)->name() == name) return true;
580  }
581  return false;
582  }
583 
586  {
587 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
588  std::cout << "ViennaCL: Getting program '" << id << "' from context " << h_ << std::endl;
589  std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
590 #endif
591 
592  if (id >= programs_.size())
593  throw invalid_program();
594 
595  return *programs_[id];
596  }
597 
598  program_container_type get_programs()
599  {
600  return programs_;
601  }
602 
604  vcl_size_t program_num() { return programs_.size(); }
605 
607  viennacl::ocl::kernel & get_kernel(std::string const & program_name, std::string const & kernel_name) { return get_program(program_name).get_kernel(kernel_name); }
608 
610  vcl_size_t device_num() { return devices_.size(); }
611 
613  const viennacl::ocl::handle<cl_context> & handle() const { return h_; }
614 
616  std::string build_options() const { return build_options_; }
617 
619  void build_options(std::string op) { build_options_ = op; }
620 
622  vcl_size_t platform_index() const { return pf_index_; }
623 
625  void platform_index(vcl_size_t new_index)
626  {
627  assert(!initialized_ && bool("Platform ID must be set before context is initialized!"));
628  pf_index_ = new_index;
629  }
630 
632  bool operator<(context const & other) const
633  {
634  return h_.get() < other.h_.get();
635  }
636 
637  bool operator==(context const & other) const
638  {
639  return h_.get() == other.h_.get();
640  }
641 
642 private:
644  void init_new()
645  {
646  assert(!initialized_ && bool("ViennaCL FATAL error: Context already created!"));
647 
648 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
649  std::cout << "ViennaCL: Initializing new ViennaCL context." << std::endl;
650 #endif
651 
652  cl_int err;
653  std::vector<cl_device_id> device_id_array;
654  if (devices_.empty()) //get the default device if user has not yet specified a list of devices
655  {
656  //create an OpenCL context for the provided devices:
657 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
658  std::cout << "ViennaCL: Setting all devices for context..." << std::endl;
659 #endif
660 
661  platform pf(pf_index_);
662  std::vector<device> devices = pf.devices(device_type_);
663 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
664  std::cout << "ViennaCL: Number of devices for context: " << devices.size() << std::endl;
665 #endif
666  vcl_size_t device_num = std::min<vcl_size_t>(default_device_num_, devices.size());
667  for (vcl_size_t i=0; i<device_num; ++i)
668  devices_.push_back(devices[i]);
669 
670  if (devices.size() == 0)
671  {
672  std::cerr << "ViennaCL: FATAL ERROR: No devices of type '";
673  switch (device_type_)
674  {
675  case CL_DEVICE_TYPE_CPU: std::cout << "CPU"; break;
676  case CL_DEVICE_TYPE_GPU: std::cout << "GPU"; break;
677  case CL_DEVICE_TYPE_ACCELERATOR: std::cout << "ACCELERATOR"; break;
678  case CL_DEVICE_TYPE_DEFAULT: std::cout << "DEFAULT"; break;
679  default:
680  std::cout << "UNKNOWN" << std::endl;
681  }
682  std::cout << "' found!" << std::endl;
683  }
684  }
685 
686  //extract list of device ids:
687  for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
688  iter != devices_.end();
689  ++iter)
690  device_id_array.push_back(iter->id());
691 
692  h_ = clCreateContext(0,
693  static_cast<cl_uint>(devices_.size()),
694  &(device_id_array[0]),
695  NULL, NULL, &err);
696  VIENNACL_ERR_CHECK(err);
697 
698  initialized_ = true;
699 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
700  std::cout << "ViennaCL: Initialization of new ViennaCL context done." << std::endl;
701 #endif
702  }
703 
705  void init_existing(cl_context c)
706  {
707  assert(!initialized_ && bool("ViennaCL FATAL error: Context already created!"));
708 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
709  std::cout << "ViennaCL: Initialization of ViennaCL context from existing context." << std::endl;
710 #endif
711 
712  //set context handle:
713  h_ = c;
714  h_.inc(); // if the user provides the context, then the user will also call release() on the context. Without inc(), we would get a seg-fault due to double-free at program termination.
715 
716  if (devices_.empty())
717  {
718  //get devices for context:
719  cl_int err;
720  cl_uint num_devices;
721  vcl_size_t temp;
722  //Note: The obvious
723  // err = clGetContextInfo(h_, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL);
724  //does not work with NVIDIA OpenCL stack!
725  err = clGetContextInfo(h_.get(), CL_CONTEXT_DEVICES, VIENNACL_OCL_MAX_DEVICE_NUM * sizeof(cl_device_id), NULL, &temp);
726  VIENNACL_ERR_CHECK(err);
727  assert(temp > 0 && bool("ViennaCL: FATAL error: Provided context does not contain any devices!"));
728  num_devices = static_cast<cl_uint>(temp / sizeof(cl_device_id));
729 
730 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
731  std::cout << "ViennaCL: Reusing context with " << num_devices << " devices." << std::endl;
732 #endif
733 
734  std::vector<cl_device_id> device_ids(num_devices);
735  err = clGetContextInfo(h_.get(), CL_CONTEXT_DEVICES, num_devices * sizeof(cl_device_id), &(device_ids[0]), NULL);
736  VIENNACL_ERR_CHECK(err);
737 
738  for (vcl_size_t i=0; i<num_devices; ++i)
739  devices_.push_back(viennacl::ocl::device(device_ids[i]));
740  }
741  current_device_id_ = 0;
742 
743  initialized_ = true;
744 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
745  std::cout << "ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
746 #endif
747  }
748 
749 
750  bool initialized_;
751  std::string cache_path_;
752  cl_device_type device_type_;
754  std::vector< viennacl::ocl::device > devices_;
755  vcl_size_t current_device_id_;
756  vcl_size_t default_device_num_;
757  program_container_type programs_;
758  std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
759  std::string build_options_;
760  vcl_size_t pf_index_;
761  vcl_size_t current_queue_id_;
762 }; //context
763 
764 
765 
767 inline viennacl::ocl::kernel & viennacl::ocl::program::add_kernel(cl_kernel kernel_handle, std::string const & kernel_name)
768 {
769  assert(p_context_ != NULL && bool("Pointer to context invalid in viennacl::ocl::program object"));
770  kernels_.push_back(tools::shared_ptr<ocl::kernel>(new ocl::kernel(kernel_handle, *this, *p_context_, kernel_name)));
771  return *kernels_.back();
772 }
773 
776 {
777  //std::cout << "Requiring kernel " << name << " from program " << name_ << std::endl;
778  for (kernel_container_type::iterator it = kernels_.begin();
779  it != kernels_.end();
780  ++it)
781  {
782  if ((*it)->name() == name)
783  return **it;
784  }
785  std::cerr << "ViennaCL: FATAL ERROR: Could not find kernel '" << name << "' from program '" << name_ << "'" << std::endl;
786  std::cout << "Number of kernels in program: " << kernels_.size() << std::endl;
787  throw "Kernel not found";
788  //return kernels_[0]; //return a defined object
789 }
790 
791 
792 inline void viennacl::ocl::kernel::set_work_size_defaults()
793 {
794  assert( p_program_ != NULL && bool("Kernel not initialized, program pointer invalid."));
795  assert( p_context_ != NULL && bool("Kernel not initialized, context pointer invalid."));
796 
797  if ( (p_context_->current_device().type() == CL_DEVICE_TYPE_GPU)
798  || (p_context_->current_device().type() == CL_DEVICE_TYPE_ACCELERATOR) // Xeon Phi
799  )
800  {
801  local_work_size_[0] = 128; local_work_size_[1] = 0; local_work_size_[2] = 0;
802  global_work_size_[0] = 128*128; global_work_size_[1] = 0; global_work_size_[2] = 0;
803  }
804  else //assume CPU type:
805  {
806  //conservative assumption: one thread per CPU core:
807  local_work_size_[0] = 1; local_work_size_[1] = 0; local_work_size_[2] = 0;
808 
809  size_type units = p_context_->current_device().max_compute_units();
810  size_type s = 1;
811 
812  while (s < units) // find next power of 2. Important to make reductions work on e.g. six-core CPUs.
813  s *= 2;
814 
815  global_work_size_[0] = s * local_work_size_[0]; global_work_size_[1] = 0; global_work_size_[2] = 0;
816  }
817 }
818 
819 }
820 }
821 
822 #endif
viennacl::ocl::device const & current_device() const
Returns the current device.
Definition: context.hpp:111
This file provides the forward declarations for the OpenCL layer of ViennaCL.
void switch_queue(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:331
viennacl::ocl::kernel & add_kernel(cl_kernel kernel_handle, std::string const &kernel_name)
Adds a kernel to the program.
Definition: context.hpp:767
cl_device_id id() const
Returns the OpenCL device id.
Definition: device.hpp:981
void platform_index(vcl_size_t new_index)
Sets the platform ID of the platform to be used for the context.
Definition: context.hpp:625
program_container_type get_programs()
Definition: context.hpp:598
cl_mem create_memory_without_smart_handle(cl_mem_flags flags, unsigned int size, void *ptr=NULL) const
Creates a memory buffer within the context. Does not wrap the OpenCL handle into the smart-pointer-li...
Definition: context.hpp:195
Represents an OpenCL device within ViennaCL.
Implements a OpenCL platform within ViennaCL.
void add_queue(cl_device_id dev)
Adds a queue for the given device to the context.
Definition: context.hpp:245
void default_device_type(cl_device_type dtype)
Sets the device type for this context.
Definition: context.hpp:94
Wrapper class for an OpenCL platform.
Definition: platform.hpp:45
std::string build_options() const
Returns the current build option string.
Definition: context.hpp:616
void switch_device(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:118
viennacl::ocl::command_queue & get_queue()
Definition: context.hpp:265
Represents an OpenCL kernel within ViennaCL.
Definition: kernel.hpp:58
viennacl::ocl::program & get_program(std::string const &name)
Returns the program with the provided name.
Definition: context.hpp:534
void build_options(std::string op)
Sets the build option string, which is passed to the OpenCL compiler in subsequent compilations...
Definition: context.hpp:619
bool operator==(context const &other) const
Definition: context.hpp:637
const viennacl::ocl::handle< cl_program > & handle() const
Definition: program.hpp:72
void delete_program(std::string const &name)
Delete the program with the provided name.
Definition: context.hpp:516
cl_device_type default_device_type()
Returns the default device type for the context.
Definition: context.hpp:88
Manages an OpenCL context and provides the respective convenience functions for creating buffers...
Definition: context.hpp:54
A class representing a compute device (e.g. a GPU)
Definition: device.hpp:49
A class representing a command queue.
vcl_size_t program_num()
Returns the number of programs within this context.
Definition: context.hpp:604
vcl_size_t platform_index() const
Returns the platform ID of the platform to be used for the context.
Definition: context.hpp:622
const viennacl::ocl::handle< cl_context > & handle() const
Returns the context handle.
Definition: context.hpp:613
viennacl::ocl::handle< cl_command_queue > const & handle() const
Implementations of command queue representations.
vcl_size_t default_device_num() const
Returns the maximum number of devices to be set up for the context.
Definition: context.hpp:81
#define VIENNACL_ERR_CHECK(err)
Definition: error.hpp:656
Implementation of a shared pointer class (cf. std::shared_ptr, boost::shared_ptr). Will be used until C++11 is widely available.
Main namespace in ViennaCL. Holds all the basic types such as vector, matrix, etc. and defines operations upon them.
Definition: cpu_ram.hpp:29
void init()
Initializes a new context.
Definition: context.hpp:166
viennacl::ocl::program & add_program(cl_program p, std::string const &prog_name)
Adds a program to the context.
Definition: context.hpp:370
const OCL_TYPE & get() const
Definition: handle.hpp:189
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
Definition: size.hpp:144
bool operator<(context const &other) const
Less-than comparable for compatibility with std:map.
Definition: context.hpp:632
Exception thrown if an OpenCL program object handle is invalid (e.g. not initialized).
Definition: error.hpp:328
void inc()
Manually increment the OpenCL reference count. Typically called automatically, but is necessary if us...
Definition: handle.hpp:214
void init(cl_context c)
Initializes the context from an existing, user-supplied context.
Definition: context.hpp:172
viennacl::ocl::kernel & get_kernel(std::string const &program_name, std::string const &kernel_name)
Convenience function for retrieving the kernel of a program directly from the context.
Definition: context.hpp:607
Implements an OpenCL program class for ViennaCL.
viennacl::ocl::program & get_program(vcl_size_t id)
Returns the program with the provided id.
Definition: context.hpp:585
std::string cache_path() const
Returns the compiled kernel cache path.
Definition: context.hpp:74
Implementation of a smart-pointer-like class for handling OpenCL handles.
void add_queue(viennacl::ocl::device d)
Adds a queue for the given device to the context.
Definition: context.hpp:262
A shared pointer class similar to boost::shared_ptr. Reimplemented in order to avoid a Boost-dependen...
Definition: shared_ptr.hpp:83
void add_device(viennacl::ocl::device const &d)
Add a device to the context. Must be done before the context is initialized.
Definition: context.hpp:145
void cache_path(std::string new_path)
Sets the compiled kernel cache path.
Definition: context.hpp:77
std::size_t vcl_size_t
Definition: forwards.h:74
Wrapper class for an OpenCL program.
Definition: program.hpp:42
void add_queue(cl_device_id dev, cl_command_queue q)
Adds an existing queue for the given device to the context.
Definition: context.hpp:234
std::string name() const
Device name string.
Definition: device.hpp:566
viennacl::ocl::program const & get_program(std::string const &name) const
Definition: context.hpp:553
void default_device_num(vcl_size_t new_num)
Sets the maximum number of devices to be set up for the context.
Definition: context.hpp:84
Exception thrown if an invalid OpenCL command queue is provided to an OpenCL function.
Definition: error.hpp:248
void switch_queue(viennacl::ocl::command_queue const &q)
If the supplied command_queue is used within the context, it becomes the current active command_queue...
Definition: context.hpp:338
bool has_program(std::string const &name)
Returns whether the program with the provided name exists or not.
Definition: context.hpp:573
#define VIENNACL_OCL_MAX_DEVICE_NUM
Representation of an OpenCL kernel in ViennaCL.
viennacl::ocl::command_queue & get_queue(cl_device_id dev, vcl_size_t i=0)
Returns the queue with the provided index for the given device.
Definition: context.hpp:303
std::string sha1(std::string const &src)
Definition: sha1.hpp:206
viennacl::ocl::command_queue const & current_queue()
Returns the current device.
Definition: context.hpp:325
void add_device(cl_device_id d)
Add a device to the context. Must be done before the context is initialized.
Definition: context.hpp:156
viennacl::ocl::kernel & get_kernel(std::string const &name)
Returns the kernel with the provided name.
Definition: context.hpp:775
std::vector< viennacl::ocl::device > const & devices() const
Returns a vector with all devices in this context.
Definition: context.hpp:105
vcl_size_t device_num()
Returns the number of devices within this context.
Definition: context.hpp:610
void switch_device(viennacl::ocl::device const &d)
If the supplied device is used within the context, it becomes the current active device.
Definition: context.hpp:125
viennacl::ocl::handle< cl_mem > create_memory(cl_mem_flags flags, const VectorType< NumericT, A > &buffer) const
Creates a memory buffer within the context initialized from the supplied data.
Definition: context.hpp:226
viennacl::ocl::command_queue const & get_queue() const
Definition: context.hpp:275
viennacl::ocl::program & add_program(std::string const &source, std::string const &prog_name)
Adds a new program with the provided source to the context. Compiles the program and extracts all ker...
Definition: context.hpp:381
viennacl::ocl::handle< cl_mem > create_memory(cl_mem_flags flags, unsigned int size, void *ptr=NULL) const
Creates a memory buffer within the context.
Definition: context.hpp:215