1 #ifndef VIENNACL_OCL_CONTEXT_HPP_
2 #define VIENNACL_OCL_CONTEXT_HPP_
26 #include <OpenCL/cl.h>
53 typedef std::vector< viennacl::ocl::program > ProgramContainer;
57 device_type_(CL_DEVICE_TYPE_DEFAULT),
58 current_device_id_(0),
59 default_device_num_(1),
61 current_queue_id_(0) {}
80 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
81 std::cout <<
"ViennaCL: Setting new device type for context " << h_ << std::endl;
89 std::vector<viennacl::ocl::device>
const &
devices()
const
98 return devices_[current_device_id_];
104 assert(i < devices_.size() && bool(
"Provided device index out of range!"));
105 current_device_id_ = i;
111 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
112 std::cout <<
"ViennaCL: Setting new current device for context " << h_ << std::endl;
117 if (devices_[i] == d)
120 current_device_id_ = i;
125 std::cerr <<
"ViennaCL: Warning: Could not set device " << d.
name() <<
" for context." << std::endl;
131 assert(!initialized_ &&
bool(
"Device must be added to context before it is initialized!"));
132 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
133 std::cout <<
"ViennaCL: Adding new device to context " << h_ << std::endl;
135 if (std::find(devices_.begin(), devices_.end(), d) == devices_.end())
136 devices_.push_back(d);
142 assert(!initialized_ &&
bool(
"Device must be added to context before it is initialized!"));
181 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
182 std::cout <<
"ViennaCL: Creating memory of size " << size <<
" for context " << h_ <<
" (unsafe, returning cl_mem directly)" << std::endl;
185 flags |= CL_MEM_COPY_HOST_PTR;
187 cl_mem mem = clCreateBuffer(h_.
get(), flags,
size, ptr, &err);
209 template <
typename SCALARTYPE,
typename A,
template <
typename,
typename>
class VectorType >
220 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
221 std::cout <<
"ViennaCL: Adding existing queue " << q <<
" for device " << dev <<
" to context " << h_ << std::endl;
225 queues_[dev].back().handle().inc();
231 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
232 std::cout <<
"ViennaCL: Adding new queue for device " << dev <<
" to context " << h_ << std::endl;
235 #ifdef VIENNACL_PROFILING_ENABLED
251 return queues_[devices_[current_device_id_].id()][current_queue_id_];
256 typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
259 QueueContainer::const_iterator it = queues_.find(devices_[current_device_id_].
id());
260 if (it != queues_.end())
261 return (it->second)[current_queue_id_];
263 std::cerr <<
"ViennaCL: FATAL ERROR: Could not obtain current command queue!" << std::endl;
264 std::cout <<
"Number of queues in context: " << queues_.size() << std::endl;
265 std::cout <<
"Number of devices in context: " << devices_.size() << std::endl;
266 throw "queue not found!";
275 assert(i < queues_.size() && bool(
"In class 'context': id invalid in get_queue()"));
276 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
277 std::cout <<
"ViennaCL: Getting queue " << i <<
" for device " << dev <<
" in context " << h_ << std::endl;
279 unsigned int device_index;
280 for (device_index = 0; device_index < devices_.size(); ++device_index)
282 if (devices_[device_index] == dev)
286 assert(device_index < devices_.size() && bool(
"Device not within context"));
288 return queues_[devices_[device_index].id()][i];
295 return queues_[devices_[current_device_id_].id()][current_queue_id_];
301 assert(i < queues_[devices_[current_device_id_].
id()].
size() &&
bool(
"In class 'context': Provided queue index out of range for device!"));
302 current_queue_id_ = i;
309 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
310 std::cout <<
"ViennaCL: Setting new current queue for context " << h_ << std::endl;
313 typedef std::map< cl_device_id, std::vector<viennacl::ocl::command_queue> > QueueContainer;
317 for (QueueContainer::const_iterator it=queues_.begin(); it != queues_.end(); it++,j++)
319 const std::vector<viennacl::ocl::command_queue> & qv = (it->second);
326 current_device_id_ = j;
327 current_queue_id_ = i;
333 std::cerr <<
"ViennaCL: Warning: Could not set queue " << q.
handle().
get() <<
" for context." << std::endl;
343 return programs_.back();
350 const char * source_text = source.c_str();
354 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
355 std::cout <<
"ViennaCL: Adding program '" << prog_name <<
"' to context " << h_ << std::endl;
361 cl_program temp = clCreateProgramWithSource(h_.
get(), 1, (
const char **)&source_text, &source_size, &err);
364 const char * options = build_options_.c_str();
365 err = clBuildProgram(temp, 0, NULL, options, NULL, NULL);
366 if (err != CL_SUCCESS)
369 cl_build_status status;
370 clGetProgramBuildInfo(temp, devices_[0].
id(), CL_PROGRAM_BUILD_STATUS,
sizeof(cl_build_status), &status, NULL);
371 clGetProgramBuildInfo(temp, devices_[0].
id(), CL_PROGRAM_BUILD_LOG,
sizeof(
char)*8192, &buffer, NULL);
372 std::cout <<
"Build Scalar: Err = " << err <<
" Status = " << status << std::endl;
373 std::cout <<
"Log: " << buffer << std::endl;
374 std::cout <<
"Sources: " << source << std::endl;
385 cl_kernel kernels[1024];
386 cl_uint num_kernels_in_prog;
387 err = clCreateKernelsInProgram(prog.
handle().
get(), 1024, kernels, &num_kernels_in_prog);
390 for (cl_uint i=0; i<num_kernels_in_prog; ++i)
392 char kernel_name[128];
393 err = clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAME, 128, kernel_name, NULL);
394 prog.
add_kernel(kernels[i], std::string(kernel_name));
402 for (ProgramContainer::iterator it = programs_.begin();
403 it != programs_.end();
406 if (it->name() == name){
416 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
417 std::cout <<
"ViennaCL: Getting program '" << name <<
"' from context " << h_ << std::endl;
419 for (ProgramContainer::iterator it = programs_.begin();
420 it != programs_.end();
423 if (it->name() == name)
426 std::cerr <<
"Could not find program '" << name <<
"'" << std::endl;
427 throw "In class 'context': name invalid in get_program()";
433 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
434 std::cout <<
"ViennaCL: Getting program '" << name <<
"' from context " << h_ << std::endl;
436 for (ProgramContainer::const_iterator it = programs_.begin();
437 it != programs_.end();
440 if (it->name() == name)
443 std::cerr <<
"Could not find program '" << name <<
"'" << std::endl;
444 throw "In class 'context': name invalid in get_program()";
450 for (ProgramContainer::iterator it = programs_.begin();
451 it != programs_.end();
454 if (it->name() == name)
return true;
462 assert(
id < programs_.size() && bool(
"In class 'context': id invalid in get_program()"));
463 return programs_[id];
490 assert(!initialized_ &&
bool(
"Platform ID must be set before context is initialized!"));
491 pf_index_ = new_index;
497 return h_.
get() < other.h_.
get();
502 return h_.
get() == other.h_.
get();
509 assert(!initialized_ &&
bool(
"ViennaCL FATAL error: Context already created!"));
511 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
512 std::cout <<
"ViennaCL: Initializing new ViennaCL context." << std::endl;
516 std::vector<cl_device_id> device_id_array;
517 if (devices_.empty())
520 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
521 std::cout <<
"ViennaCL: Setting all devices for context..." << std::endl;
525 std::vector<device>
devices = pf.devices(device_type_);
526 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
527 std::cout <<
"ViennaCL: Number of devices for context: " << devices.size() << std::endl;
531 devices_.push_back(devices[i]);
533 if (devices.size() == 0)
535 std::cerr <<
"ViennaCL: FATAL ERROR: No devices of type '";
536 switch (device_type_)
538 case CL_DEVICE_TYPE_CPU: std::cout <<
"CPU";
break;
539 case CL_DEVICE_TYPE_GPU: std::cout <<
"GPU";
break;
540 case CL_DEVICE_TYPE_ACCELERATOR: std::cout <<
"ACCELERATOR";
break;
541 case CL_DEVICE_TYPE_DEFAULT: std::cout <<
"DEFAULT";
break;
543 std::cout <<
"UNKNOWN" << std::endl;
545 std::cout <<
"' found!" << std::endl;
550 for (std::vector< viennacl::ocl::device >::const_iterator iter = devices_.begin();
551 iter != devices_.end();
553 device_id_array.push_back(iter->id());
555 h_ = clCreateContext(0,
556 static_cast<cl_uint>(devices_.size()),
557 &(device_id_array[0]),
562 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
563 std::cout <<
"ViennaCL: Initialization of new ViennaCL context done." << std::endl;
568 void init_existing(cl_context c)
570 assert(!initialized_ &&
bool(
"ViennaCL FATAL error: Context already created!"));
571 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
572 std::cout <<
"ViennaCL: Initialization of ViennaCL context from existing context." << std::endl;
579 if (devices_.empty())
590 assert(temp > 0 &&
bool(
"ViennaCL: FATAL error: Provided context does not contain any devices!"));
591 num_devices =
static_cast<cl_uint
>(temp /
sizeof(cl_device_id));
593 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
594 std::cout <<
"ViennaCL: Reusing context with " << num_devices <<
" devices." << std::endl;
597 std::vector<cl_device_id> device_ids(num_devices);
598 err = clGetContextInfo(h_.
get(), CL_CONTEXT_DEVICES, num_devices *
sizeof(cl_device_id), &(device_ids[0]), NULL);
604 current_device_id_ = 0;
607 #if defined(VIENNACL_DEBUG_ALL) || defined(VIENNACL_DEBUG_CONTEXT)
608 std::cout <<
"ViennaCL: Initialization of ViennaCL context from existing context done." << std::endl;
614 cl_device_type device_type_;
616 std::vector< viennacl::ocl::device > devices_;
619 ProgramContainer programs_;
620 std::map< cl_device_id, std::vector< viennacl::ocl::command_queue> > queues_;
621 std::string build_options_;
631 assert(p_context_ != NULL &&
bool(
"Pointer to context invalid in viennacl::ocl::program object"));
633 kernels_.push_back(temp);
634 return kernels_.back();
641 for (KernelContainer::iterator it = kernels_.begin();
642 it != kernels_.end();
645 if (it->name() == name)
648 std::cerr <<
"ViennaCL: FATAL ERROR: Could not find kernel '" << name <<
"' from program '" << name_ <<
"'" << std::endl;
649 std::cout <<
"Number of kernels in program: " << kernels_.size() << std::endl;
650 throw "Kernel not found";
655 inline void viennacl::ocl::kernel::set_work_size_defaults()
657 assert( p_program_ != NULL &&
bool(
"Kernel not initialized, program pointer invalid."));
658 assert( p_context_ != NULL &&
bool(
"Kernel not initialized, context pointer invalid."));
660 if ( (p_context_->current_device().type() == CL_DEVICE_TYPE_GPU)
661 || (p_context_->current_device().type() == CL_DEVICE_TYPE_ACCELERATOR)
664 local_work_size_[0] = 128; local_work_size_[1] = 0; local_work_size_[2] = 0;
665 global_work_size_[0] = 128*128; global_work_size_[1] = 0; global_work_size_[2] = 0;
670 local_work_size_[0] = 1; local_work_size_[1] = 0; local_work_size_[2] = 0;
672 size_type units = p_context_->current_device().max_compute_units();
678 global_work_size_[0] = s; global_work_size_[1] = 0; global_work_size_[2] = 0;
std::string name() const
Device name string.
Definition: device.hpp:566
void add_device(cl_device_id d)
Add a device to the context. Must be done before the context is initialized.
Definition: context.hpp:140
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:470
This file provides the forward declarations for the OpenCL layer of ViennaCL.
std::size_t vcl_size_t
Definition: forwards.h:58
void delete_program(std::string const &name)
Delete the program with the provided name.
Definition: context.hpp:401
bool operator<(context const &other) const
Less-than comparable for compatibility with std:map.
Definition: context.hpp:495
void inc()
Manually increment the OpenCL reference count. Typically called automatically, but is necessary if us...
Definition: handle.hpp:214
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:307
Represents an OpenCL device within ViennaCL.
bool operator==(context const &other) const
Definition: context.hpp:500
viennacl::ocl::command_queue const & current_queue()
Returns the current device.
Definition: context.hpp:293
vcl_size_t device_num()
Returns the number of devices within this context.
Definition: context.hpp:473
Represents an OpenCL kernel within ViennaCL.
Definition: kernel.hpp:59
Manages an OpenCL context and provides the respective convenience functions for creating buffers...
Definition: context.hpp:51
cl_device_type default_device_type()
Returns the default device type for the context.
Definition: context.hpp:72
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:179
void init(cl_context c)
Initializes the context from an existing, user-supplied context.
Definition: context.hpp:156
A class representing a compute device (e.g. a GPU)
Definition: device.hpp:49
void switch_device(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:102
viennacl::ocl::program & add_program(cl_program p, std::string const &prog_name)
Adds a program to the context.
Definition: context.hpp:340
void add_queue(viennacl::ocl::device d)
Adds a queue for the given device to the context.
Definition: context.hpp:246
A class representing a command queue.
Definition: command_queue.hpp:45
void init()
Initializes a new context.
Definition: context.hpp:150
viennacl::ocl::handle< cl_command_queue > const & handle() const
Definition: command_queue.hpp:81
viennacl::ocl::program const & get_program(std::string const &name) const
Definition: context.hpp:431
viennacl::ocl::program & get_program(std::string const &name)
Returns the program with the provided name.
Definition: context.hpp:414
bool has_program(std::string const &name)
Returns whether the program with the provided name exists or not.
Definition: context.hpp:449
const viennacl::ocl::handle< cl_context > & handle() const
Returns the context handle.
Definition: context.hpp:476
Implementations of command queue representations.
viennacl::ocl::device const & current_device() const
Returns the current device.
Definition: context.hpp:95
#define VIENNACL_ERR_CHECK(err)
Definition: error.hpp:655
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
Definition: size.hpp:144
viennacl::ocl::command_queue & get_queue()
Definition: context.hpp:249
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:199
const OCL_TYPE & get() const
Definition: handle.hpp:189
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:109
cl_device_id id() const
Returns the OpenCL device id.
Definition: device.hpp:981
Implements an OpenCL program class for ViennaCL.
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:68
Implementation of a smart-pointer-like class for handling OpenCL handles.
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:218
viennacl::ocl::program & get_program(vcl_size_t id)
Returns the program with the provided id.
Definition: context.hpp:460
viennacl::ocl::kernel & add_kernel(cl_kernel kernel_handle, std::string const &kernel_name)
Adds a kernel to the program.
Definition: context.hpp:629
const viennacl::ocl::handle< cl_program > & handle() const
Definition: program.hpp:68
void add_queue(cl_device_id dev)
Adds a queue for the given device to the context.
Definition: context.hpp:229
Wrapper class for an OpenCL program.
Definition: program.hpp:40
void default_device_type(cl_device_type dtype)
Sets the device type for this context.
Definition: context.hpp:78
vcl_size_t platform_index() const
Returns the platform ID of the platform to be used for the context.
Definition: context.hpp:485
#define VIENNACL_OCL_MAX_DEVICE_NUM
Definition: device_utils.hpp:25
vcl_size_t program_num()
Returns the number of programs within this context.
Definition: context.hpp:467
std::string build_options() const
Returns the current build option string.
Definition: context.hpp:479
viennacl::ocl::kernel & get_kernel(std::string const &name)
Returns the kernel with the provided name.
Definition: context.hpp:638
Representation of an OpenCL kernel in ViennaCL.
vcl_size_t default_device_num() const
Returns the maximum number of devices to be set up for the context.
Definition: context.hpp:65
void platform_index(vcl_size_t new_index)
Sets the platform ID of the platform to be used for the context.
Definition: context.hpp:488
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:273
void build_options(std::string op)
Sets the build option string, which is passed to the OpenCL compiler in subsequent compilations...
Definition: context.hpp:482
viennacl::ocl::handle< cl_mem > create_memory(cl_mem_flags flags, const VectorType< SCALARTYPE, A > &buffer) const
Creates a memory buffer within the context initialized from the supplied data.
Definition: context.hpp:210
std::vector< viennacl::ocl::device > const & devices() const
Returns a vector with all devices in this context.
Definition: context.hpp:89
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:129
context()
Definition: context.hpp:56
void switch_queue(vcl_size_t i)
Switches the current device to the i-th device in this context.
Definition: context.hpp:299
viennacl::ocl::command_queue const & get_queue() const
Definition: context.hpp:254
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:348