1 #ifndef VIENNACL_OCL_CONTEXT_HPP_
2 #define VIENNACL_OCL_CONTEXT_HPP_
26 #include <OpenCL/cl.h>
56 typedef std::vector< tools::shared_ptr<viennacl::ocl::program> > program_container_type;
60 device_type_(CL_DEVICE_TYPE_DEFAULT),
61 current_device_id_(0),
62 default_device_num_(1),
66 if (std::getenv(
"VIENNACL_CACHE_PATH"))
67 cache_path_ = std::getenv(
"VIENNACL_CACHE_PATH");
77 void cache_path(std::string new_path) { cache_path_ = new_path; }
96 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
97 std::cout <<
"ViennaCL: Setting new device type for context " << h_ << std::endl;
100 device_type_ = dtype;
105 std::vector<viennacl::ocl::device>
const &
devices()
const
114 return devices_[current_device_id_];
120 assert(i < devices_.size() && bool(
"Provided device index out of range!"));
121 current_device_id_ = i;
127 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
128 std::cout <<
"ViennaCL: Setting new current device for context " << h_ << std::endl;
133 if (devices_[i] == d)
136 current_device_id_ = i;
141 std::cerr <<
"ViennaCL: Warning: Could not set device " << d.
name() <<
" for context." << std::endl;
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;
151 if (std::find(devices_.begin(), devices_.end(), d) == devices_.end())
152 devices_.push_back(d);
158 assert(!initialized_ &&
bool(
"Device must be added to context before it is initialized!"));
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;
201 flags |= CL_MEM_COPY_HOST_PTR;
203 cl_mem mem = clCreateBuffer(h_.
get(), flags,
size, ptr, &err);
225 template<
typename NumericT,
typename A,
template<
typename,
typename>
class VectorType >
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;
241 queues_[dev].back().handle().inc();
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;
251 #ifdef VIENNACL_PROFILING_ENABLED
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;
272 return queues_[devices_[current_device_id_].id()][current_queue_id_];
277 typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
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;
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;
290 return (it->second)[current_queue_id_];
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!";
305 if (i >= queues_[dev].
size())
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;
311 unsigned int device_index;
312 for (device_index = 0; device_index < devices_.size(); ++device_index)
314 if (devices_[device_index] == dev)
318 assert(device_index < devices_.size() && bool(
"Device not within context"));
320 return queues_[devices_[device_index].id()][i];
327 return queues_[devices_[current_device_id_].id()][current_queue_id_];
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;
340 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
341 std::cout <<
"ViennaCL: Setting new current queue for context " << h_ << std::endl;
344 typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
348 for (QueueContainer::const_iterator it=queues_.begin(); it != queues_.end(); it++,j++)
350 const std::vector<viennacl::ocl::command_queue> & qv = (it->second);
357 current_device_id_ = j;
358 current_queue_id_ = i;
364 std::cerr <<
"ViennaCL: Warning: Could not set queue " << q.
handle().
get() <<
" for context." << std::endl;
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;
376 return *programs_.back();
383 const char * source_text = source.c_str();
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;
396 if (cache_path_.size())
398 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
399 std::cout <<
"ViennaCL: Cache at " << cache_path_ << std::endl;
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();
407 std::ifstream cached((cache_path_+sha1).c_str(),std::ios::binary);
411 std::vector<unsigned char> buffer;
415 cached.read((
char*)buffer.data(), std::streamsize(len));
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);
427 temp = clCreateProgramWithSource(h_.
get(), 1, (
const char **)&source_text, &source_size, &err);
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)
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;
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;
450 std::cout <<
"Sources: " << source << std::endl;
457 if (cache_path_.size())
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);
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]]);
469 clGetProgramInfo(temp,CL_PROGRAM_BINARIES,0,NULL,&len);
470 clGetProgramInfo(temp,CL_PROGRAM_BINARIES,len,binaries.data(),NULL);
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();
476 std::ofstream cached((cache_path_+sha1).c_str(),std::ios::binary);
478 cached.write((
char*)&sizes[0],
sizeof(
vcl_size_t));
479 cached.write((
char*)binaries[0], std::streamsize(sizes[0]));
481 for (
vcl_size_t i = 0; i < devices_.size(); ++i)
482 delete[] binaries[i];
495 cl_kernel kernels[1024];
496 cl_uint num_kernels_in_prog;
497 err = clCreateKernelsInProgram(prog.
handle().
get(), 1024, kernels, &num_kernels_in_prog);
500 for (cl_uint i=0; i<num_kernels_in_prog; ++i)
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));
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;
518 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
519 std::cout <<
"ViennaCL: Deleting program '" << name <<
"' from context " << h_ << std::endl;
521 for (program_container_type::iterator it = programs_.begin();
522 it != programs_.end();
525 if ((*it)->name() == name)
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;
540 for (program_container_type::iterator it = programs_.begin();
541 it != programs_.end();
545 if ((*it)->name() == name)
548 std::cerr <<
"ViennaCL: Could not find program '" << name <<
"'" << std::endl;
549 throw "In class 'context': name invalid in get_program()";
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;
559 for (program_container_type::const_iterator it = programs_.begin();
560 it != programs_.end();
564 if ((*it)->name() == name)
567 std::cerr <<
"ViennaCL: Could not find program '" << name <<
"'" << std::endl;
568 throw "In class 'context': name invalid in get_program()";
575 for (program_container_type::iterator it = programs_.begin();
576 it != programs_.end();
579 if ((*it)->name() == name)
return true;
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;
592 if (
id >= programs_.size())
595 return *programs_[id];
627 assert(!initialized_ &&
bool(
"Platform ID must be set before context is initialized!"));
628 pf_index_ = new_index;
634 return h_.
get() < other.h_.
get();
639 return h_.
get() == other.h_.
get();
646 assert(!initialized_ &&
bool(
"ViennaCL FATAL error: Context already created!"));
648 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
649 std::cout <<
"ViennaCL: Initializing new ViennaCL context." << std::endl;
653 std::vector<cl_device_id> device_id_array;
654 if (devices_.empty())
657 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
658 std::cout <<
"ViennaCL: Setting all devices for context..." << std::endl;
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;
668 devices_.push_back(devices[i]);
670 if (devices.size() == 0)
672 std::cerr <<
"ViennaCL: FATAL ERROR: No devices of type '";
673 switch (device_type_)
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;
680 std::cout <<
"UNKNOWN" << std::endl;
682 std::cout <<
"' found!" << std::endl;
687 for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
688 iter != devices_.end();
690 device_id_array.push_back(iter->id());
692 h_ = clCreateContext(0,
693 static_cast<cl_uint>(devices_.size()),
694 &(device_id_array[0]),
699 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
700 std::cout <<
"ViennaCL: Initialization of new ViennaCL context done." << std::endl;
705 void init_existing(cl_context c)
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;
716 if (devices_.empty())
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));
730 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
731 std::cout <<
"ViennaCL: Reusing context with " << num_devices <<
" devices." << std::endl;
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);
741 current_device_id_ = 0;
744 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
745 std::cout <<
"ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
751 std::string cache_path_;
752 cl_device_type device_type_;
754 std::vector< viennacl::ocl::device > devices_;
757 program_container_type programs_;
758 std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
759 std::string build_options_;
769 assert(p_context_ != NULL &&
bool(
"Pointer to context invalid in viennacl::ocl::program object"));
771 return *kernels_.back();
778 for (kernel_container_type::iterator it = kernels_.begin();
779 it != kernels_.end();
782 if ((*it)->name() == name)
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";
792 inline void viennacl::ocl::kernel::set_work_size_defaults()
794 assert( p_program_ != NULL &&
bool(
"Kernel not initialized, program pointer invalid."));
795 assert( p_context_ != NULL &&
bool(
"Kernel not initialized, context pointer invalid."));
797 if ( (p_context_->current_device().type() == CL_DEVICE_TYPE_GPU)
798 || (p_context_->current_device().type() == CL_DEVICE_TYPE_ACCELERATOR)
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;
807 local_work_size_[0] = 1; local_work_size_[1] = 0; local_work_size_[2] = 0;
809 size_type units = p_context_->current_device().max_compute_units();
815 global_work_size_[0] = s * local_work_size_[0]; global_work_size_[1] = 0; global_work_size_[2] = 0;
viennacl::ocl::device const & current_device() const
Returns the current device.
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.
viennacl::ocl::kernel & add_kernel(cl_kernel kernel_handle, std::string const &kernel_name)
Adds a kernel to the program.
cl_device_id id() const
Returns the OpenCL device id.
void platform_index(vcl_size_t new_index)
Sets the platform ID of the platform to be used for the context.
program_container_type get_programs()
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...
Represents an OpenCL device within ViennaCL.
void add_queue(cl_device_id dev)
Adds a queue for the given device to the context.
void default_device_type(cl_device_type dtype)
Sets the device type for this context.
std::string build_options() const
Returns the current build option string.
void switch_device(vcl_size_t i)
Switches the current device to the i-th device in this context.
viennacl::ocl::command_queue & get_queue()
Represents an OpenCL kernel within ViennaCL.
viennacl::ocl::program & get_program(std::string const &name)
Returns the program with the provided name.
void build_options(std::string op)
Sets the build option string, which is passed to the OpenCL compiler in subsequent compilations...
bool operator==(context const &other) const
const viennacl::ocl::handle< cl_program > & handle() const
void delete_program(std::string const &name)
Delete the program with the provided name.
cl_device_type default_device_type()
Returns the default device type for the context.
Manages an OpenCL context and provides the respective convenience functions for creating buffers...
A class representing a compute device (e.g. a GPU)
A class representing a command queue.
vcl_size_t program_num()
Returns the number of programs within this context.
vcl_size_t platform_index() const
Returns the platform ID of the platform to be used for the context.
const viennacl::ocl::handle< cl_context > & handle() const
Returns the context handle.
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.
#define VIENNACL_ERR_CHECK(err)
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.
void init()
Initializes a new context.
viennacl::ocl::program & add_program(cl_program p, std::string const &prog_name)
Adds a program to the context.
const OCL_TYPE & get() const
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
bool operator<(context const &other) const
Less-than comparable for compatibility with std:map.
Exception thrown if an OpenCL program object handle is invalid (e.g. not initialized).
void inc()
Manually increment the OpenCL reference count. Typically called automatically, but is necessary if us...
void init(cl_context c)
Initializes the context from an existing, user-supplied context.
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.
Implements an OpenCL program class for ViennaCL.
viennacl::ocl::program & get_program(vcl_size_t id)
Returns the program with the provided id.
std::string cache_path() const
Returns the compiled kernel cache path.
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.
void add_device(viennacl::ocl::device const &d)
Add a device to the context. Must be done before the context is initialized.
void cache_path(std::string new_path)
Sets the compiled kernel cache path.
Wrapper class for an OpenCL program.
void add_queue(cl_device_id dev, cl_command_queue q)
Adds an existing queue for the given device to the context.
std::string name() const
Device name string.
viennacl::ocl::program const & get_program(std::string const &name) const
void default_device_num(vcl_size_t new_num)
Sets the maximum number of devices to be set up for the context.
Exception thrown if an invalid OpenCL command queue is provided to an OpenCL function.
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...
bool has_program(std::string const &name)
Returns whether the program with the provided name exists or not.
#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.
viennacl::ocl::command_queue const & current_queue()
Returns the current device.
void add_device(cl_device_id d)
Add a device to the context. Must be done before the context is initialized.
viennacl::ocl::kernel & get_kernel(std::string const &name)
Returns the kernel with the provided name.
std::vector< viennacl::ocl::device > const & devices() const
Returns a vector with all devices in this context.
vcl_size_t device_num()
Returns the number of devices within this context.
void switch_device(viennacl::ocl::device const &d)
If the supplied device is used within the context, it becomes the current active device.
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.
viennacl::ocl::command_queue const & get_queue() const
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...
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.