ViennaCL - The Vienna Computing Library  1.7.0
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-2015, 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 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/error.hpp"
38 #include "viennacl/ocl/handle.hpp"
39 #include "viennacl/ocl/kernel.hpp"
40 #include "viennacl/ocl/program.hpp"
41 #include "viennacl/ocl/device.hpp"
44 #include "viennacl/tools/sha1.hpp"
46 namespace viennacl
47 {
48 namespace ocl
49 {
55 class context
56 {
57  typedef std::vector< tools::shared_ptr<viennacl::ocl::program> > program_container_type;
58 
59 public:
60  context() : initialized_(false),
61  device_type_(CL_DEVICE_TYPE_DEFAULT),
62  current_device_id_(0),
63  default_device_num_(1),
64  pf_index_(0),
65  current_queue_id_(0)
66  {
67  if (std::getenv("VIENNACL_CACHE_PATH"))
68  cache_path_ = std::getenv("VIENNACL_CACHE_PATH");
69  else
70  cache_path_ = "";
71  }
72 
74 
75  std::string cache_path() const { return cache_path_; }
76 
78  void cache_path(std::string new_path) { cache_path_ = new_path; }
79 
81 
82  vcl_size_t default_device_num() const { return default_device_num_; }
83 
85  void default_device_num(vcl_size_t new_num) { default_device_num_ = new_num; }
86 
88 
89  cl_device_type default_device_type()
90  {
91  return device_type_;
92  }
93 
95  void default_device_type(cl_device_type dtype)
96  {
97 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
98  std::cout << "ViennaCL: Setting new device type for context " << h_ << std::endl;
99 #endif
100  if (!initialized_)
101  device_type_ = dtype; //assume that the user provided a correct value
102  }
103 
105 
106  std::vector<viennacl::ocl::device> const & devices() const
107  {
108  return devices_;
109  }
110 
113  {
114  //std::cout << "Current device id in context: " << current_device_id_ << std::endl;
115  return devices_[current_device_id_];
116  }
117 
120  {
121  assert(i < devices_.size() && bool("Provided device index out of range!"));
122  current_device_id_ = i;
123  }
124 
127  {
128 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
129  std::cout << "ViennaCL: Setting new current device for context " << h_ << std::endl;
130 #endif
131  bool found = false;
132  for (vcl_size_t i=0; i<devices_.size(); ++i)
133  {
134  if (devices_[i] == d)
135  {
136  found = true;
137  current_device_id_ = i;
138  break;
139  }
140  }
141  if (found == false)
142  std::cerr << "ViennaCL: Warning: Could not set device " << d.name() << " for context." << std::endl;
143  }
144 
147  {
148  assert(!initialized_ && bool("Device must be added to context before it is initialized!"));
149 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
150  std::cout << "ViennaCL: Adding new device to context " << h_ << std::endl;
151 #endif
152  if (std::find(devices_.begin(), devices_.end(), d) == devices_.end())
153  devices_.push_back(d);
154  }
155 
157  void add_device(cl_device_id d)
158  {
159  assert(!initialized_ && bool("Device must be added to context before it is initialized!"));
161  }
162 
163 
165 
167  void init()
168  {
169  init_new();
170  }
171 
173  void init(cl_context c)
174  {
175  init_existing(c);
176  }
177 
178  /* void existing_context(cl_context context_id)
179  {
180  assert(!initialized_ && bool("ViennaCL: FATAL error: Provided a new context for an already initialized context."));
181  #i#if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
182  std::cout << "ViennaCL: Reusing existing context " << h_ << std::endl;
183  #e#endif
184  h_ = context_id;
185  }*/
186 
188 
196  cl_mem create_memory_without_smart_handle(cl_mem_flags flags, unsigned int size, void * ptr = NULL) const
197  {
198 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
199  std::cout << "ViennaCL: Creating memory of size " << size << " for context " << h_ << " (unsafe, returning cl_mem directly)" << std::endl;
200 #endif
201  if (ptr)
202  flags |= CL_MEM_COPY_HOST_PTR;
203  cl_int err;
204  cl_mem mem = clCreateBuffer(h_.get(), flags, size, ptr, &err);
205  VIENNACL_ERR_CHECK(err);
206  return mem;
207  }
208 
209 
216  viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, unsigned int size, void * ptr = NULL) const
217  {
218  return viennacl::ocl::handle<cl_mem>(create_memory_without_smart_handle(flags, size, ptr), *this);
219  }
220 
226  template< typename NumericT, typename A, template<typename, typename> class VectorType >
227  viennacl::ocl::handle<cl_mem> create_memory(cl_mem_flags flags, const VectorType<NumericT, A> & buffer) const
228  {
229  return viennacl::ocl::handle<cl_mem>(create_memory_without_smart_handle(flags, static_cast<cl_uint>(sizeof(NumericT) * buffer.size()), (void*)&buffer[0]), *this);
230  }
231 
233 
235  void add_queue(cl_device_id dev, cl_command_queue q)
236  {
237 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
238  std::cout << "ViennaCL: Adding existing queue " << q << " for device " << dev << " to context " << h_ << std::endl;
239 #endif
240  viennacl::ocl::handle<cl_command_queue> queue_handle(q, *this);
241  queues_[dev].push_back(viennacl::ocl::command_queue(queue_handle));
242  queues_[dev].back().handle().inc();
243  }
244 
246  void add_queue(cl_device_id dev)
247  {
248 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
249  std::cout << "ViennaCL: Adding new queue for device " << dev << " to context " << h_ << std::endl;
250 #endif
251  cl_int err;
252 #ifdef VIENNACL_PROFILING_ENABLED
253  viennacl::ocl::handle<cl_command_queue> temp(clCreateCommandQueue(h_.get(), dev, CL_QUEUE_PROFILING_ENABLE, &err), *this);
254 #else
255  viennacl::ocl::handle<cl_command_queue> temp(clCreateCommandQueue(h_.get(), dev, 0, &err), *this);
256 #endif
257  VIENNACL_ERR_CHECK(err);
258 
259  queues_[dev].push_back(viennacl::ocl::command_queue(temp));
260  }
261 
264 
265  //get queue for default device:
267  {
268 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
269  std::cout << "ViennaCL: Getting queue for device " << devices_[current_device_id_].name() << " in context " << h_ << std::endl;
270  std::cout << "ViennaCL: Current queue id " << current_queue_id_ << std::endl;
271 #endif
272 
273  return queues_[devices_[current_device_id_].id()][current_queue_id_];
274  }
275 
277  {
278  typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
279 
280 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
281  std::cout << "ViennaCL: Getting const queue for device " << devices_[current_device_id_].name() << " in context " << h_ << std::endl;
282  std::cout << "ViennaCL: Current queue id " << current_queue_id_ << std::endl;
283 #endif
284 
285  // find queue:
286  QueueContainer::const_iterator it = queues_.find(devices_[current_device_id_].id());
287  if (it != queues_.end()) {
288 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
289  std::cout << "ViennaCL: Queue handle " << (it->second)[current_queue_id_].handle() << std::endl;
290 #endif
291  return (it->second)[current_queue_id_];
292  }
293 
294  throw queue_not_found("Could not obtain current command queue");
295 
296  //return ((*it)->second)[current_queue_id_];
297  }
298 
299  //get a particular queue:
302  {
303  if (i >= queues_[dev].size())
304  throw invalid_command_queue();
305 
306 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
307  std::cout << "ViennaCL: Getting queue " << i << " for device " << dev << " in context " << h_ << std::endl;
308 #endif
309  unsigned int device_index;
310  for (device_index = 0; device_index < devices_.size(); ++device_index)
311  {
312  if (devices_[device_index] == dev)
313  break;
314  }
315 
316  assert(device_index < devices_.size() && bool("Device not within context"));
317 
318  return queues_[devices_[device_index].id()][i];
319  }
320 
322  // TODO: work out the const issues
324  {
325  return queues_[devices_[current_device_id_].id()][current_queue_id_];
326  }
327 
330  {
331  assert(i < queues_[devices_[current_device_id_].id()].size() && bool("In class 'context': Provided queue index out of range for device!"));
332  current_queue_id_ = i;
333  }
334 
337  {
338 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
339  std::cout << "ViennaCL: Setting new current queue for context " << h_ << std::endl;
340 #endif
341  bool found = false;
342  typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
343 
344  // For each device:
345  vcl_size_t j = 0;
346  for (QueueContainer::const_iterator it=queues_.begin(); it != queues_.end(); it++,j++)
347  {
348  const std::vector<viennacl::ocl::command_queue> & qv = (it->second);
349  // For each queue candidate
350  for (vcl_size_t i=0; i<qv.size(); ++i)
351  {
352  if (qv[i] == q)
353  {
354  found = true;
355  current_device_id_ = j;
356  current_queue_id_ = i;
357  break;
358  }
359  }
360  }
361  if (found == false)
362  std::cerr << "ViennaCL: Warning: Could not set queue " << q.handle().get() << " for context." << std::endl;
363  }
364 
366 
368  viennacl::ocl::program & add_program(cl_program p, std::string const & prog_name)
369  {
370  programs_.push_back(tools::shared_ptr<ocl::program>(new viennacl::ocl::program(p, *this, prog_name)));
371 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
372  std::cout << "ViennaCL: Adding program '" << prog_name << "' with cl_program to context " << h_ << std::endl;
373 #endif
374  return *programs_.back();
375  }
376 
379  viennacl::ocl::program & add_program(std::string const & source, std::string const & prog_name)
380  {
381  const char * source_text = source.c_str();
382  vcl_size_t source_size = source.size();
383  cl_int err;
384 
385 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
386  std::cout << "ViennaCL: Adding program '" << prog_name << "' with source to context " << h_ << std::endl;
387 #endif
388 
389  cl_program temp = 0;
390 
391  //
392  // Retrieves the program in the cache
393  //
394  if (cache_path_.size())
395  {
396 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
397  std::cout << "ViennaCL: Cache at " << cache_path_ << std::endl;
398 #endif
399 
400  std::string prefix;
401  for(std::vector< viennacl::ocl::device >::const_iterator it = devices_.begin(); it != devices_.end(); ++it)
402  prefix += it->name() + it->vendor() + it->driver_version();
403  std::string sha1 = tools::sha1(prefix + source);
404 
405  std::ifstream cached((cache_path_+sha1).c_str(),std::ios::binary);
406  if (cached)
407  {
408  vcl_size_t len;
409  std::vector<unsigned char> buffer;
410 
411  cached.read((char*)&len, sizeof(vcl_size_t));
412  buffer.resize(len);
413  cached.read((char*)(&buffer[0]), std::streamsize(len));
414 
415  cl_int status;
416  cl_device_id devid = devices_[0].id();
417  const unsigned char * bufdata = &buffer[0];
418  temp = clCreateProgramWithBinary(h_.get(),1,&devid,&len, &bufdata,&status,&err);
419  VIENNACL_ERR_CHECK(err);
420  }
421  }
422 
423  if (!temp)
424  {
425  temp = clCreateProgramWithSource(h_.get(), 1, (const char **)&source_text, &source_size, &err);
426  VIENNACL_ERR_CHECK(err);
427  }
428 
429  const char * options = build_options_.c_str();
430  err = clBuildProgram(temp, 0, NULL, options, NULL, NULL);
431 #ifndef VIENNACL_BUILD_INFO
432  if (err != CL_SUCCESS)
433 #endif
434  {
435  cl_build_status status;
436  clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL);
437  std::cout << "Build Status = " << status << " ( Err = " << err << " )" << std::endl;
438 
439  char *build_log;
440  size_t ret_val_size; // don't use vcl_size_t here
441  err = clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
442  build_log = new char[ret_val_size+1];
443  err = clGetProgramBuildInfo(temp, devices_[0].id(), CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
444  build_log[ret_val_size] = '\0';
445  std::cout << "Log: " << build_log << std::endl;
446  delete[] build_log;
447 
448  std::cout << "Sources: " << source << std::endl;
449  }
450  VIENNACL_ERR_CHECK(err);
451 
452  //
453  // Store the program in the cache
454  //
455  if (cache_path_.size())
456  {
457  vcl_size_t len;
458 
459  std::vector<vcl_size_t> sizes(devices_.size());
460  clGetProgramInfo(temp,CL_PROGRAM_BINARY_SIZES,0,NULL,&len);
461  clGetProgramInfo(temp,CL_PROGRAM_BINARY_SIZES,len,(void*)&sizes[0],NULL);
462 
463  std::vector<unsigned char*> binaries;
464  for (vcl_size_t i = 0; i < devices_.size(); ++i)
465  binaries.push_back(new unsigned char[sizes[i]]);
466 
467  clGetProgramInfo(temp,CL_PROGRAM_BINARIES,0,NULL,&len);
468  clGetProgramInfo(temp,CL_PROGRAM_BINARIES,len,&binaries[0],NULL);
469 
470  std::string prefix;
471  for(std::vector< viennacl::ocl::device >::const_iterator it = devices_.begin(); it != devices_.end(); ++it)
472  prefix += it->name() + it->vendor() + it->driver_version();
473  std::string sha1 = tools::sha1(prefix + source);
474  std::ofstream cached((cache_path_+sha1).c_str(),std::ios::binary);
475 
476  cached.write((char*)&sizes[0], sizeof(vcl_size_t));
477  cached.write((char*)binaries[0], std::streamsize(sizes[0]));
478 
479  for (vcl_size_t i = 0; i < devices_.size(); ++i)
480  delete[] binaries[i];
481 
482  VIENNACL_ERR_CHECK(err);
483  }
484 
485 
486  programs_.push_back(tools::shared_ptr<ocl::program>(new ocl::program(temp, *this, prog_name)));
487 
488  viennacl::ocl::program & prog = *programs_.back();
489 
490  //
491  // Extract kernels
492  //
493  cl_kernel kernels[1024];
494  cl_uint num_kernels_in_prog;
495  err = clCreateKernelsInProgram(prog.handle().get(), 1024, kernels, &num_kernels_in_prog);
496  VIENNACL_ERR_CHECK(err);
497 
498  for (cl_uint i=0; i<num_kernels_in_prog; ++i)
499  {
500  char kernel_name[128];
501  err = clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAME, 128, kernel_name, NULL);
502  prog.add_kernel(kernels[i], std::string(kernel_name));
503  }
504 
505 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
506  std::cout << "ViennaCL: Stored program '" << programs_.back()->name() << "' in context " << h_ << std::endl;
507  std::cout << "ViennaCL: There is/are " << programs_.size() << " program(s)" << std::endl;
508 #endif
509 
510  return prog;
511  }
512 
514  void delete_program(std::string const & name)
515  {
516 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
517  std::cout << "ViennaCL: Deleting program '" << name << "' from context " << h_ << std::endl;
518 #endif
519  for (program_container_type::iterator it = programs_.begin();
520  it != programs_.end();
521  ++it)
522  {
523  if ((*it)->name() == name)
524  {
525  programs_.erase(it);
526  return;
527  }
528  }
529  }
530 
532  viennacl::ocl::program & get_program(std::string const & name)
533  {
534 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
535  std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
536  std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
537 #endif
538  for (program_container_type::iterator it = programs_.begin();
539  it != programs_.end();
540  ++it)
541  {
542  //std::cout << "Name: " << (*it)->name() << std::endl;
543  if ((*it)->name() == name)
544  return **it;
545  }
546  std::cerr << "ViennaCL: Could not find program '" << name << "'" << std::endl;
547  throw program_not_found(name);
548  //return programs_[0]; //return a defined object
549  }
550 
551  viennacl::ocl::program const & get_program(std::string const & name) const
552  {
553 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
554  std::cout << "ViennaCL: Getting program '" << name << "' from context " << h_ << std::endl;
555  std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
556 #endif
557  for (program_container_type::const_iterator it = programs_.begin();
558  it != programs_.end();
559  ++it)
560  {
561  //std::cout << "Name: " << (*it)->name() << std::endl;
562  if ((*it)->name() == name)
563  return **it;
564  }
565  std::cerr << "ViennaCL: Could not find program '" << name << "'" << std::endl;
566  throw program_not_found(name);
567  //return programs_[0]; //return a defined object
568  }
569 
571  bool has_program(std::string const & name)
572  {
573  for (program_container_type::iterator it = programs_.begin();
574  it != programs_.end();
575  ++it)
576  {
577  if ((*it)->name() == name) return true;
578  }
579  return false;
580  }
581 
584  {
585 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
586  std::cout << "ViennaCL: Getting program '" << id << "' from context " << h_ << std::endl;
587  std::cout << "ViennaCL: There are " << programs_.size() << " programs" << std::endl;
588 #endif
589 
590  if (id >= programs_.size())
591  throw invalid_program();
592 
593  return *programs_[id];
594  }
595 
596  program_container_type get_programs()
597  {
598  return programs_;
599  }
600 
602  vcl_size_t program_num() { return programs_.size(); }
603 
605  viennacl::ocl::kernel & get_kernel(std::string const & program_name, std::string const & kernel_name) { return get_program(program_name).get_kernel(kernel_name); }
606 
608  vcl_size_t device_num() { return devices_.size(); }
609 
611  const viennacl::ocl::handle<cl_context> & handle() const { return h_; }
612 
614  std::string build_options() const { return build_options_; }
615 
617  void build_options(std::string op) { build_options_ = op; }
618 
620  vcl_size_t platform_index() const { return pf_index_; }
621 
623  void platform_index(vcl_size_t new_index)
624  {
625  assert(!initialized_ && bool("Platform ID must be set before context is initialized!"));
626  pf_index_ = new_index;
627  }
628 
630  bool operator<(context const & other) const
631  {
632  return h_.get() < other.h_.get();
633  }
634 
635  bool operator==(context const & other) const
636  {
637  return h_.get() == other.h_.get();
638  }
639 
640 private:
642  void init_new()
643  {
644  assert(!initialized_ && bool("ViennaCL FATAL error: Context already created!"));
645 
646 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
647  std::cout << "ViennaCL: Initializing new ViennaCL context." << std::endl;
648 #endif
649 
650  cl_int err;
651  std::vector<cl_device_id> device_id_array;
652  if (devices_.empty()) //get the default device if user has not yet specified a list of devices
653  {
654  //create an OpenCL context for the provided devices:
655 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
656  std::cout << "ViennaCL: Setting all devices for context..." << std::endl;
657 #endif
658 
659  platform pf(pf_index_);
660  std::vector<device> devices = pf.devices(device_type_);
661 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
662  std::cout << "ViennaCL: Number of devices for context: " << devices.size() << std::endl;
663 #endif
664  vcl_size_t device_num = std::min<vcl_size_t>(default_device_num_, devices.size());
665  for (vcl_size_t i=0; i<device_num; ++i)
666  devices_.push_back(devices[i]);
667 
668  if (devices.size() == 0)
669  {
670  std::cerr << "ViennaCL: FATAL ERROR: No devices of type '";
671  switch (device_type_)
672  {
673  case CL_DEVICE_TYPE_CPU: std::cout << "CPU"; break;
674  case CL_DEVICE_TYPE_GPU: std::cout << "GPU"; break;
675  case CL_DEVICE_TYPE_ACCELERATOR: std::cout << "ACCELERATOR"; break;
676  case CL_DEVICE_TYPE_DEFAULT: std::cout << "DEFAULT"; break;
677  default:
678  std::cout << "UNKNOWN" << std::endl;
679  }
680  std::cout << "' found!" << std::endl;
681  }
682  }
683 
684  //extract list of device ids:
685  for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
686  iter != devices_.end();
687  ++iter)
688  device_id_array.push_back(iter->id());
689 
690  h_ = clCreateContext(0,
691  static_cast<cl_uint>(devices_.size()),
692  &(device_id_array[0]),
693  NULL, NULL, &err);
694  VIENNACL_ERR_CHECK(err);
695 
696  initialized_ = true;
697 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
698  std::cout << "ViennaCL: Initialization of new ViennaCL context done." << std::endl;
699 #endif
700  }
701 
703  void init_existing(cl_context c)
704  {
705  assert(!initialized_ && bool("ViennaCL FATAL error: Context already created!"));
706 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
707  std::cout << "ViennaCL: Initialization of ViennaCL context from existing context." << std::endl;
708 #endif
709 
710  //set context handle:
711  h_ = c;
712  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.
713 
714  if (devices_.empty())
715  {
716  //get devices for context:
717  cl_int err;
718  cl_uint num_devices;
719  vcl_size_t temp;
720  //Note: The obvious
721  // err = clGetContextInfo(h_, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL);
722  //does not work with NVIDIA OpenCL stack!
723  err = clGetContextInfo(h_.get(), CL_CONTEXT_DEVICES, VIENNACL_OCL_MAX_DEVICE_NUM * sizeof(cl_device_id), NULL, &temp);
724  VIENNACL_ERR_CHECK(err);
725  assert(temp > 0 && bool("ViennaCL: FATAL error: Provided context does not contain any devices!"));
726  num_devices = static_cast<cl_uint>(temp / sizeof(cl_device_id));
727 
728 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
729  std::cout << "ViennaCL: Reusing context with " << num_devices << " devices." << std::endl;
730 #endif
731 
732  std::vector<cl_device_id> device_ids(num_devices);
733  err = clGetContextInfo(h_.get(), CL_CONTEXT_DEVICES, num_devices * sizeof(cl_device_id), &(device_ids[0]), NULL);
734  VIENNACL_ERR_CHECK(err);
735 
736  for (vcl_size_t i=0; i<num_devices; ++i)
737  devices_.push_back(viennacl::ocl::device(device_ids[i]));
738  }
739  current_device_id_ = 0;
740 
741  initialized_ = true;
742 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
743  std::cout << "ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
744 #endif
745  }
746 
747 
748  bool initialized_;
749  std::string cache_path_;
750  cl_device_type device_type_;
752  std::vector< viennacl::ocl::device > devices_;
753  vcl_size_t current_device_id_;
754  vcl_size_t default_device_num_;
755  program_container_type programs_;
756  std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
757  std::string build_options_;
758  vcl_size_t pf_index_;
759  vcl_size_t current_queue_id_;
760 }; //context
761 
762 
763 
765 inline viennacl::ocl::kernel & viennacl::ocl::program::add_kernel(cl_kernel kernel_handle, std::string const & kernel_name)
766 {
767  assert(p_context_ != NULL && bool("Pointer to context invalid in viennacl::ocl::program object"));
768  kernels_.push_back(tools::shared_ptr<ocl::kernel>(new ocl::kernel(kernel_handle, *this, *p_context_, kernel_name)));
769  return *kernels_.back();
770 }
771 
774 {
775  //std::cout << "Requiring kernel " << name << " from program " << name_ << std::endl;
776  for (kernel_container_type::iterator it = kernels_.begin();
777  it != kernels_.end();
778  ++it)
779  {
780  if ((*it)->name() == name)
781  return **it;
782  }
783  std::cerr << "ViennaCL: FATAL ERROR: Could not find kernel '" << name << "' from program '" << name_ << "'" << std::endl;
784  std::cout << "Number of kernels in program: " << kernels_.size() << std::endl;
785  throw kernel_not_found("Kernel not found");
786  //return kernels_[0]; //return a defined object
787 }
788 
789 
790 inline void viennacl::ocl::kernel::set_work_size_defaults()
791 {
792  assert( p_program_ != NULL && bool("Kernel not initialized, program pointer invalid."));
793  assert( p_context_ != NULL && bool("Kernel not initialized, context pointer invalid."));
794 
795  if ( (p_context_->current_device().type() == CL_DEVICE_TYPE_GPU)
796  || (p_context_->current_device().type() == CL_DEVICE_TYPE_ACCELERATOR) // Xeon Phi
797  )
798  {
799  local_work_size_[0] = 128; local_work_size_[1] = 0; local_work_size_[2] = 0;
800  global_work_size_[0] = 128*128; global_work_size_[1] = 0; global_work_size_[2] = 0;
801  }
802  else //assume CPU type:
803  {
804  //conservative assumption: one thread per CPU core:
805  local_work_size_[0] = 1; local_work_size_[1] = 0; local_work_size_[2] = 0;
806 
807  size_type units = p_context_->current_device().max_compute_units();
808  size_type s = 1;
809 
810  while (s < units) // find next power of 2. Important to make reductions work on e.g. six-core CPUs.
811  s *= 2;
812 
813  global_work_size_[0] = s * local_work_size_[0]; global_work_size_[1] = 0; global_work_size_[2] = 0;
814  }
815 }
816 
817 }
818 }
819 
820 #endif
viennacl::ocl::device const & current_device() const
Returns the current device.
Definition: context.hpp:112
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:329
viennacl::ocl::kernel & add_kernel(cl_kernel kernel_handle, std::string const &kernel_name)
Adds a kernel to the program.
Definition: context.hpp:765
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:623
program_container_type get_programs()
Definition: context.hpp:596
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:196
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:246
void default_device_type(cl_device_type dtype)
Sets the device type for this context.
Definition: context.hpp:95
Wrapper class for an OpenCL platform.
Definition: platform.hpp:45
std::string build_options() const
Returns the current build option string.
Definition: context.hpp:614
void switch_device(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:119
viennacl::ocl::command_queue & get_queue()
Definition: context.hpp:266
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:532
void build_options(std::string op)
Sets the build option string, which is passed to the OpenCL compiler in subsequent compilations...
Definition: context.hpp:617
bool operator==(context const &other) const
Definition: context.hpp:635
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:514
cl_device_type default_device_type()
Returns the default device type for the context.
Definition: context.hpp:89
Manages an OpenCL context and provides the respective convenience functions for creating buffers...
Definition: context.hpp:55
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:602
vcl_size_t platform_index() const
Returns the platform ID of the platform to be used for the context.
Definition: context.hpp:620
const viennacl::ocl::handle< cl_context > & handle() const
Returns the context handle.
Definition: context.hpp:611
viennacl::ocl::handle< cl_command_queue > const & handle() const
float NumericT
Definition: bisect.cpp:40
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:82
#define VIENNACL_ERR_CHECK(err)
Definition: error.hpp:681
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:34
void init()
Initializes a new context.
Definition: context.hpp:167
viennacl::ocl::program & add_program(cl_program p, std::string const &prog_name)
Adds a program to the context.
Definition: context.hpp:368
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:235
bool operator<(context const &other) const
Less-than comparable for compatibility with std:map.
Definition: context.hpp:630
Exception thrown if an OpenCL program object handle is invalid (e.g. not initialized).
Definition: error.hpp:353
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:173
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:605
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:583
std::string cache_path() const
Returns the compiled kernel cache path.
Definition: context.hpp:75
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:263
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:146
void cache_path(std::string new_path)
Sets the compiled kernel cache path.
Definition: context.hpp:78
std::size_t vcl_size_t
Definition: forwards.h:75
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:235
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:551
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:85
Exception thrown if an invalid OpenCL command queue is provided to an OpenCL function.
Definition: error.hpp:273
Error handling for the OpenCL layer of ViennaCL.
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:336
bool has_program(std::string const &name)
Returns whether the program with the provided name exists or not.
Definition: context.hpp:571
#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:301
std::string sha1(std::string const &src)
Definition: sha1.hpp:220
viennacl::ocl::command_queue const & current_queue()
Returns the current device.
Definition: context.hpp:323
void add_device(cl_device_id d)
Add a device to the context. Must be done before the context is initialized.
Definition: context.hpp:157
viennacl::ocl::kernel & get_kernel(std::string const &name)
Returns the kernel with the provided name.
Definition: context.hpp:773
std::vector< viennacl::ocl::device > const & devices() const
Returns a vector with all devices in this context.
Definition: context.hpp:106
vcl_size_t device_num()
Returns the number of devices within this context.
Definition: context.hpp:608
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:126
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:227
viennacl::ocl::command_queue const & get_queue() const
Definition: context.hpp:276
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:379
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:216