cancel
Showing results for 
Search instead for 
Did you mean: 

Archives Discussions

settle
Challenger

Call-by-reference and const OpenCL Objects

This may be more of a C++ question than OpenCL, but I can't seem to make sense of some parts in the OpenCL C++ Wrapper API included in the AMD APP SDK (include/CL/cl.hpp).

Would someone mind explaining why vectors of OpenCL objects such as "Event" are sometimes passed by reference with "&" and othertimes "*"?

Case 1:

cl_int cl::CommandQueue::enqueueWaitForEvents(

const VECTOR_CLASS<Event>& events)

Case 2:

cl_int cl::CommandQueue::enqueueNDRangeKernel(

const Kernel& kernel,

const NDRange& offset,

const NDRange& global,

const NDRange& local,

const VECTOR_CLASS<Event> * events = NULL,

Event * event = NULL)

My initial hypothesis was because Case 2 sets a default value of NULL, but then I found other cases with "Device" that seem to refute that.

Case 3:

cl::Context::Context(VECTOR_CLASS<Device>& devices,

cl_context_properties * properties = NULL,

void (CL_CALLBACK * pfn_notify)(

const char * errorinfo,

const void * private_info_size,

::size_t cb,

void * user_data) = NULL,

void * user_data = NULL,

cl_int * err = NULL)

Case 4:

cl_int cl::Platform::getDevices(cl_device_type type,

VECTOR_CLASS<Device> * devices)

Secondly, why does the OpenCL C++ Wrapper API use "const" and pass-by-reference when passing memory objects

cl_int cl::CommandQueue::enqueueCopyBuffer(

const Buffer & src,

const Buffer & dst,

::size_t src_offset,

::size_t dst_offset,

::size_t size,

const VECTOR_CLASS<Event> * events = NULL,

Event * event = NULL)

but the the OpenCL C API uses neither

cl_int clEnqueueCopyBuffer (cl_command_queue command_queue,

cl_mem src_buffer,

cl_mem dst_buffer,

size_t src_offset,

size_t dst_offset,

size_t size,

cl_uint num_events_in_wait_list,

const cl_event *event_wait_list,

cl_event *event)

Frankly, it's hard/impossible to make sense of most OpenCL C data types and C++ Objects because the information is hidden away in opaque pointers (e.g., typedef struct _cl_mem * cl_mem;) or opaque classes (e.g., detail::Wrapper<cl_mem>).

0 Likes
1 Solution
LeeHowes
Staff

I think the consistent rule here is that a reference may be used for a by-reference passed parameter. A pointer is used either for a passed parameter that is optional, or for a call-by-return parameter. There may be inconsistencies in this rule however the examples you show follow it. WaitForEvents' event list is non-optional (it may be in the C API, but it would be meaningless to not pass events), enqueueNDRangeKernel's event list is optional, Context's device list is an input parameter, not an output parameter getDevices is an output parameter. You briefly concerned me that Context's constructor might not be right because the parameter is non-const, but in fact it is a const reference:

    Context(

        const VECTOR_CLASS<Device>& devices,

As for your other question, All entities through the cl API are pass-by-reference. The reason you don't see it is that what you are really doing is passing a handle by value, but the handle of course is a reference to a runtime object.

The reason for a difference in C++ is that even the C++ wrapper objects are simply zero overhead wrappers for those handles. To improve safety of API use these wrappers are not zero overhead in execution because they reference count the handle by automatically handling retain/release calls that many programmers use inappropriately in the OpenCL API simply because getting it right is a pain. So there are circumstances where you don't actually want to reference count because there is overhead to doing that. Copy buffer operations should not reference count each buffer by copy on entry and exit from the function, because they are not really making a copy - the entity that was used on entry is assumed to still be around in the calling thread. Enqueuing the copy operation will ref count inside the runtime anyway as clearly we cannot delete a buffer while we are copying from or to it.

We are going through the process of significantly improving the documentation of cl.hpp, which should help.

View solution in original post

0 Likes
2 Replies
LeeHowes
Staff

I think the consistent rule here is that a reference may be used for a by-reference passed parameter. A pointer is used either for a passed parameter that is optional, or for a call-by-return parameter. There may be inconsistencies in this rule however the examples you show follow it. WaitForEvents' event list is non-optional (it may be in the C API, but it would be meaningless to not pass events), enqueueNDRangeKernel's event list is optional, Context's device list is an input parameter, not an output parameter getDevices is an output parameter. You briefly concerned me that Context's constructor might not be right because the parameter is non-const, but in fact it is a const reference:

    Context(

        const VECTOR_CLASS<Device>& devices,

As for your other question, All entities through the cl API are pass-by-reference. The reason you don't see it is that what you are really doing is passing a handle by value, but the handle of course is a reference to a runtime object.

The reason for a difference in C++ is that even the C++ wrapper objects are simply zero overhead wrappers for those handles. To improve safety of API use these wrappers are not zero overhead in execution because they reference count the handle by automatically handling retain/release calls that many programmers use inappropriately in the OpenCL API simply because getting it right is a pain. So there are circumstances where you don't actually want to reference count because there is overhead to doing that. Copy buffer operations should not reference count each buffer by copy on entry and exit from the function, because they are not really making a copy - the entity that was used on entry is assumed to still be around in the calling thread. Enqueuing the copy operation will ref count inside the runtime anyway as clearly we cannot delete a buffer while we are copying from or to it.

We are going through the process of significantly improving the documentation of cl.hpp, which should help.

0 Likes

Hello Lee,

Thank you for your thorough answer.  I now can clearly see the pass-by-reference rule employed. 

Also, I'm sorry for raising concern about the const in the Context constructor.  I copied and pasted from the Khronos OpenCL C++ Wrapper API pdf, but I didn't double check with the actual cl.hpp header included with the AMD APP SDK.  I'm very happy with the cl.hpp provided by AMD already including many OpenCL 1.2 features and look forward to the updated documentation.

Cheers!

0 Likes