Files
rocm-systems/opencl/amdocl/cl_command.cpp
T

405 строки
14 KiB
C++

//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#include "cl_common.hpp"
#include "platform/object.hpp"
#include "platform/context.hpp"
#include "platform/command.hpp"
#include "platform/agent.hpp"
/*! \addtogroup API
* @{
*
* \addtogroup CL_Queues
*
* OpenCL objects such as memory objects, program and kernel objects are
* created using a context. Operations on these objects are performed using
* a command-queue. The command-queue can be used to queue a set of operations
* (referred to as commands) in order. Having multiple command-queues allows
* applications to queue multiple independent commands without requiring
* synchronization. Note that this should work as long as these objects are
* not being shared. Sharing of objects across multiple command-queues will
* require the application to perform appropriate synchronization.
*
* @{
*/
/*! \brief Create a command-queue on a specific device.
*
* \param context must be a valid OpenCL context.
*
* \param device must be a device associated with context. It can either be
* in the list of devices specified when context is created using
* clCreateContext or have the same device type as device type specified wheni
* context is created using clCreateContextFromType.
*
* \param properties specifies a list of properties for the command-queue.
*
* \param errcode_ret will return an appropriate error code. If \a errcode_ret
* is NULL, no error code is returned.
*
* \return A valid non-zero command-queue and \a errcode_ret is set to
* CL_SUCCESS if the command-queue is created successfully or a NULL value
* with one of the following error values returned \a in errcode_ret:
* - CL_INVALID_CONTEXT if context is not a valid.
* - CL_INVALID_DEVICE if device is not a valid device or is not associated
* with context
* - CL_INVALID_VALUE if values specified in properties are not valid.
* - CL_INVALID_QUEUE_PROPERTIES if values specified in properties are valid
* but are not supported by the device.
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources
* required by the runtime.
*
* \version 1.0r33
*/
RUNTIME_ENTRY_RET(cl_command_queue, clCreateCommandQueueWithProperties,
(cl_context context, cl_device_id device,
const cl_queue_properties* queue_properties, cl_int* errcode_ret)) {
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
return (cl_command_queue)0;
}
amd::Context& amdContext = *as_amd(context);
amd::Device& amdDevice = *as_amd(device);
if (!is_valid(device) || !amdContext.containsDevice(&amdDevice)) {
*not_null(errcode_ret) = CL_INVALID_DEVICE;
return (cl_command_queue)0;
}
cl_command_queue_properties properties = 0;
const struct QueueProperty {
cl_queue_properties name;
union {
cl_queue_properties raw;
// FIXME_lmoriche: Check with Khronos. cl_queue_properties is an intptr,
// but cl_command_queue_properties is a bitfield (truncate?).
// cl_command_queue_properties properties;
cl_uint size;
} value;
}* p = reinterpret_cast<const QueueProperty*>(queue_properties);
uint queueSize = amdDevice.info().queueOnDevicePreferredSize_;
uint queueRTCUs = amd::CommandQueue::RealTimeDisabled;
amd::CommandQueue::Priority priority = amd::CommandQueue::Priority::Normal;
if (p != NULL)
while (p->name != 0) {
switch (p->name) {
case CL_QUEUE_PROPERTIES:
// FIXME_lmoriche: See comment above.
// properties = p->value.properties;
properties = static_cast<cl_command_queue_properties>(p->value.raw);
break;
case CL_QUEUE_SIZE:
queueSize = p->value.size;
break;
#define CL_QUEUE_REAL_TIME_COMPUTE_UNITS_AMD 0x404f
case CL_QUEUE_REAL_TIME_COMPUTE_UNITS_AMD:
queueRTCUs = p->value.size;
break;
#define CL_QUEUE_MEDIUM_PRIORITY_AMD 0x4050
case CL_QUEUE_MEDIUM_PRIORITY_AMD:
priority = amd::CommandQueue::Priority::Medium;
if (p->value.size != 0) {
queueRTCUs = p->value.size;
}
break;
default:
*not_null(errcode_ret) = CL_INVALID_QUEUE_PROPERTIES;
LogWarning("invalid property name");
return (cl_command_queue)0;
}
++p;
}
if (queueSize > amdDevice.info().queueOnDeviceMaxSize_) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
return (cl_command_queue)0;
}
if ((queueRTCUs != amd::CommandQueue::RealTimeDisabled) &&
((queueRTCUs > amdDevice.info().numRTCUs_) || (queueRTCUs == 0))) {
*not_null(errcode_ret) = CL_INVALID_VALUE;
return (cl_command_queue)0;
}
amd::CommandQueue* queue = NULL;
{
amd::ScopedLock lock(amdContext.lock());
// Check if the app creates a host queue
if (!(properties & CL_QUEUE_ON_DEVICE)) {
queue = new amd::HostQueue(amdContext, amdDevice, properties, queueRTCUs, priority);
} else {
// Is it a device default queue
if (properties & CL_QUEUE_ON_DEVICE_DEFAULT) {
queue = amdContext.defDeviceQueue(amdDevice);
// If current context has one already then return it
if (NULL != queue) {
queue->retain();
*not_null(errcode_ret) = CL_SUCCESS;
return as_cl(queue);
}
}
// Check if runtime can allocate a new device queue on this context
if (amdContext.isDevQueuePossible(amdDevice)) {
queue = new amd::DeviceQueue(amdContext, amdDevice, properties, queueSize);
}
}
if (queue == NULL || !queue->create()) {
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
delete queue;
return (cl_command_queue)0;
}
}
if (amd::Agent::shouldPostCommandQueueEvents()) {
amd::Agent::postCommandQueueCreate(as_cl(queue->asCommandQueue()));
}
*not_null(errcode_ret) = CL_SUCCESS;
return as_cl(queue);
}
RUNTIME_EXIT
RUNTIME_ENTRY_RET(cl_command_queue, clCreateCommandQueue,
(cl_context context, cl_device_id device, cl_command_queue_properties properties,
cl_int* errcode_ret)) {
const cl_queue_properties cprops[] = {CL_QUEUE_PROPERTIES,
static_cast<cl_queue_properties>(properties), 0};
return clCreateCommandQueueWithProperties(context, device, properties ? cprops : NULL,
errcode_ret);
}
RUNTIME_EXIT
/*! \brief Replaces the default command queue on the device
*
* \param context must be a valid OpenCL context.
*
* \param device must be a device associated with context.
*
* \param command_queue specifies the default command-queue.
*
* \reture One of the following values:
* - CL_SUCCESS if the function executed successfully.
* - CL_INVALID_CONTEXT if \a context is not a valid context.
* - CL_INVALID_DEVICE if \a device is not a valid device or is not
* associated with context.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid command-
* queue for device.
*/
RUNTIME_ENTRY(cl_int, clSetDefaultDeviceCommandQueue,
(cl_context context, cl_device_id device, cl_command_queue command_queue)) {
if (!is_valid(context)) {
return CL_INVALID_CONTEXT;
}
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
amd::Context* amdContext = as_amd(context);
amd::Device* amdDevice = as_amd(device);
if (!is_valid(device) || !amdContext->containsDevice(amdDevice)) {
return CL_INVALID_DEVICE;
}
amd::DeviceQueue* deviceQueue = as_amd(command_queue)->asDeviceQueue();
if ((deviceQueue == NULL) || (amdContext != &deviceQueue->context()) ||
(amdDevice != &deviceQueue->device())) {
return CL_INVALID_COMMAND_QUEUE;
}
{
amd::ScopedLock lock(amdContext->lock());
amdContext->setDefDeviceQueue(*amdDevice, deviceQueue);
}
return CL_SUCCESS;
}
RUNTIME_EXIT
/*! \brief Increment the \a command_queue reference count.
*
* \return One of the following values:
* - CL_SUCCESS if the function is executed successfully.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid
* command-queue.
*
* clCreateCommandQueue performs an implicit retain. This is very helpful for
* 3rd party libraries, which typically get a command-queue passed to them
* by the application. However, it is possible that the application may delete
* the command-queue without informing the library. Allowing functions to
* attach to (i.e. retain) and release a command-queue solves the problem of a
* command-queue being used by a library no longer being valid.
*
* \version 1.0r33
*/
RUNTIME_ENTRY(cl_int, clRetainCommandQueue, (cl_command_queue command_queue)) {
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
as_amd(command_queue)->retain();
return CL_SUCCESS;
}
RUNTIME_EXIT
/*! \brief Decrement the \a command_queue reference count.
*
* \return One of the following values:
* - CL_SUCCESS if the function is executed successfully.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid
* command-queue.
*
* After the command_queue reference count becomes zero and all commands queued
* to \a command_queue have finished (eg. kernel executions, memory object
* updates etc.), the command-queue is deleted.
*
* \version 1.0r33
*/
RUNTIME_ENTRY(cl_int, clReleaseCommandQueue, (cl_command_queue command_queue)) {
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
as_amd(command_queue)->release();
return CL_SUCCESS;
}
RUNTIME_EXIT
/*! \brief Query information about a command-queue.
*
* \param command_queue specifies the command-queue being queried.
*
* \param param_name specifies the information to query.
*
* \param param_value is a pointer to memory where the appropriate result
* being queried is returned. If \a param_value is NULL, it is ignored.
*
* \param param_value_size is used to specify the size in bytes of memory
* pointed to by \a param_value. This size must be >= size of return type.
* If param_value is NULL, it is ignored.
*
* \param param_value_size_ret returns the actual size in bytes of data being
* queried by \a param_value. If \a param_value_size_ret is NULL,
* it is ignored.
*
* \return One of the following values:
* - CL_SUCCESS if the function is executed successfully.
* - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid
* command-queue.
* - CL_INVALID_VALUE if \a param_name is not one of the supported
* values or if size in bytes specified by \a param_value_size is < size of
* return type and \a param_value is not a NULL value.
*
* \version 1.0r33
*/
RUNTIME_ENTRY(cl_int, clGetCommandQueueInfo,
(cl_command_queue command_queue, cl_command_queue_info param_name,
size_t param_value_size, void* param_value, size_t* param_value_size_ret)) {
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
switch (param_name) {
case CL_QUEUE_CONTEXT: {
cl_context context = const_cast<cl_context>(as_cl(&as_amd(command_queue)->context()));
return amd::clGetInfo(context, param_value_size, param_value, param_value_size_ret);
}
case CL_QUEUE_DEVICE: {
cl_device_id device = const_cast<cl_device_id>(as_cl(&as_amd(command_queue)->device()));
return amd::clGetInfo(device, param_value_size, param_value, param_value_size_ret);
}
case CL_QUEUE_PROPERTIES: {
cl_command_queue_properties properties = as_amd(command_queue)->properties().value_;
return amd::clGetInfo(properties, param_value_size, param_value, param_value_size_ret);
}
case CL_QUEUE_REFERENCE_COUNT: {
cl_uint count = as_amd(command_queue)->referenceCount();
return amd::clGetInfo(count, param_value_size, param_value, param_value_size_ret);
}
case CL_QUEUE_SIZE: {
const amd::DeviceQueue* deviceQueue = as_amd(command_queue)->asDeviceQueue();
if (NULL == deviceQueue) {
return CL_INVALID_COMMAND_QUEUE;
}
cl_uint size = deviceQueue->size();
return amd::clGetInfo(size, param_value_size, param_value, param_value_size_ret);
}
case CL_QUEUE_THREAD_HANDLE_AMD: {
const amd::HostQueue* hostQueue = as_amd(command_queue)->asHostQueue();
if (NULL == hostQueue) {
return CL_INVALID_COMMAND_QUEUE;
}
const void* handle = hostQueue->thread().handle();
return amd::clGetInfo(handle, param_value_size, param_value, param_value_size_ret);
}
case CL_QUEUE_DEVICE_DEFAULT: {
const amd::Device& device = as_amd(command_queue)->device();
amd::CommandQueue* defQueue = as_amd(command_queue)->context().defDeviceQueue(device);
cl_command_queue queue = defQueue ? as_cl(defQueue) : NULL;
return amd::clGetInfo(queue, param_value_size, param_value, param_value_size_ret);
}
default:
break;
}
return CL_INVALID_VALUE;
}
RUNTIME_EXIT
/*! \brief Enable or disable the properties of a command-queue.
*
* \param command_queue specifies the command-queue being queried.
*
* \param properties specifies the new command-queue properties to be applied
* to \a command_queue .
*
* \param enable determines whether the values specified by properties are
* enabled (if enable is CL_TRUE) or disabled (if enable is CL_FALSE) for the
* command-queue .
*
* \param old_properties returns the command-queue properties before they were
* changed by clSetCommandQueueProperty. If \a old_properties is NULL,
* it is ignored.
*
* \return One of the following values:
* - CL_SUCCESS if the command-queue properties are successfully updated.
* - CL_INVALID_COMMAND_QUEUE if command_queue is not a valid command-queue.
* - CL_INVALID_VALUE if the values specified in properties are not valid.
* - CL_INVALID_QUEUE_PROPERTIES if values specified in properties are
* not supported by the device.
*
* \version 1.0r33
*/
RUNTIME_ENTRY(cl_int, clSetCommandQueueProperty,
(cl_command_queue command_queue, cl_command_queue_properties properties,
cl_bool enable, cl_command_queue_properties* old_properties)) {
if (!is_valid(command_queue)) {
return CL_INVALID_COMMAND_QUEUE;
}
*not_null(old_properties) = as_amd(command_queue)->properties().value_;
if (properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) {
clFinish(command_queue);
}
bool success;
if (enable == CL_TRUE) {
success = as_amd(command_queue)->properties().set(properties);
} else {
success = as_amd(command_queue)->properties().clear(properties);
}
return success ? CL_SUCCESS : CL_INVALID_QUEUE_PROPERTIES;
}
RUNTIME_EXIT
/*! @}
* @}
*/