Initial open source release of OpenCL 2.2 CTS.

This commit is contained in:
Kedar Patil
2017-05-16 18:25:37 +05:30
parent 6911ba5116
commit 2821bf1323
1035 changed files with 343518 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
set(MODULE_NAME EVENTS)
set(${MODULE_NAME}_SOURCES
main.c
test_events.cpp
test_event_dependencies.cpp
test_waitlists.cpp
test_userevents.cpp
test_userevents_multithreaded.cpp
action_classes.cpp
test_callbacks.cpp
../../test_common/harness/genericThread.cpp
../../test_common/harness/errorHelpers.c
../../test_common/harness/threadTesting.c
../../test_common/harness/testHarness.c
../../test_common/harness/kernelHelpers.c
../../test_common/harness/typeWrappers.cpp
../../test_common/harness/mt19937.c
../../test_common/harness/conversions.c
../../test_common/harness/msvc9.c
../../test_common/harness/ThreadPool.c
../../test_common/harness/parseParameters.cpp
)
include(../CMakeCommon.txt)

View File

@@ -0,0 +1,18 @@
project
: requirements
<toolset>gcc:<cflags>-xc++
<toolset>msvc:<cflags>"/TP"
;
exe test_events
: main.c
test_event_dependencies.cpp
test_events.cpp
test_waitlists.cpp
;
install dist
: test_events
: <variant>debug:<location>$(DIST)/debug/tests/test_conformance/events
<variant>release:<location>$(DIST)/release/tests/test_conformance/events
;

View File

@@ -0,0 +1,51 @@
ifdef BUILD_WITH_ATF
ATF = -framework ATF
USE_ATF = -DUSE_ATF
endif
SRCS = main.c \
test_events.cpp \
test_event_dependencies.cpp \
test_userevents.cpp \
test_waitlists.cpp \
test_callbacks.cpp \
action_classes.cpp \
test_userevents_multithreaded.cpp \
../../test_common/harness/errorHelpers.c \
../../test_common/harness/threadTesting.c \
../../test_common/harness/testHarness.c \
../../test_common/harness/genericThread.cpp \
../../test_common/harness/kernelHelpers.c \
../../test_common/harness/typeWrappers.cpp \
../../test_common/harness/mt19937.c \
../../test_common/harness/conversions.c \
../../test_common/harness/ThreadPool.c \
DEFINES = DONT_TEST_GARBAGE_POINTERS
SOURCES = $(abspath $(SRCS))
LIBPATH += -L/System/Library/Frameworks/OpenCL.framework/Libraries
LIBPATH += -L.
HEADERS =
TARGET = test_events
INCLUDE =
COMPILERFLAGS = -c -Wall -g -Wshorten-64-to-32
CC = c++
CFLAGS = $(COMPILERFLAGS) ${RC_CFLAGS} ${USE_ATF} $(DEFINES:%=-D%) $(INCLUDE)
CXXFLAGS = $(COMPILERFLAGS) ${RC_CFLAGS} ${USE_ATF} $(DEFINES:%=-D%) $(INCLUDE)
LIBRARIES = -framework OpenCL -framework OpenGL -framework GLUT -framework AppKit ${ATF}
OBJECTS := ${SOURCES:.c=.o}
OBJECTS := ${OBJECTS:.cpp=.o}
TARGETOBJECT =
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(RC_CFLAGS) $(OBJECTS) -o $@ $(LIBPATH) $(LIBRARIES)
clean:
rm -f $(TARGET) $(OBJECTS)
.DEFAULT:
@echo The target \"$@\" does not exist in Makefile.

View File

@@ -0,0 +1,658 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "action_classes.h"
#pragma mark -------------------- Base Action Class -------------------------
const cl_uint BufferSizeReductionFactor = 20;
cl_int Action::IGetPreferredImageSize2D( cl_device_id device, size_t &outWidth, size_t &outHeight )
{
cl_ulong maxAllocSize;
size_t maxWidth, maxHeight;
cl_int error;
// Get the largest possible buffer we could allocate
error = clGetDeviceInfo( device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof( maxAllocSize ), &maxAllocSize, NULL );
error |= clGetDeviceInfo( device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof( maxWidth ), &maxWidth, NULL );
error |= clGetDeviceInfo( device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof( maxHeight ), &maxHeight, NULL );
test_error( error, "Unable to get device config" );
// Create something of a decent size
if( maxWidth * maxHeight * 4 > maxAllocSize / BufferSizeReductionFactor )
{
float rootSize = sqrtf( (float)( maxAllocSize / ( BufferSizeReductionFactor * 4 ) ) );
if( (size_t)rootSize > maxWidth )
outWidth = maxWidth;
else
outWidth = (size_t)rootSize;
outHeight = (size_t)( ( maxAllocSize / ( BufferSizeReductionFactor * 4 ) ) / outWidth );
if( outHeight > maxHeight )
outHeight = maxHeight;
}
else
{
outWidth = maxWidth;
outHeight = maxHeight;
}
outWidth /=2;
outHeight /=2;
if (outWidth > 2048)
outWidth = 2048;
if (outHeight > 2048)
outHeight = 2048;
log_info("\tImage size: %d x %d (%gMB)\n", (int)outWidth, (int)outHeight,
(double)((int)outWidth*(int)outHeight*4)/(1024.0*1024.0));
return CL_SUCCESS;
}
cl_int Action::IGetPreferredImageSize3D( cl_device_id device, size_t &outWidth, size_t &outHeight, size_t &outDepth )
{
cl_ulong maxAllocSize;
size_t maxWidth, maxHeight, maxDepth;
cl_int error;
// Get the largest possible buffer we could allocate
error = clGetDeviceInfo( device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof( maxAllocSize ), &maxAllocSize, NULL );
error |= clGetDeviceInfo( device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof( maxWidth ), &maxWidth, NULL );
error |= clGetDeviceInfo( device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof( maxHeight ), &maxHeight, NULL );
error |= clGetDeviceInfo( device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof( maxDepth ), &maxDepth, NULL );
test_error( error, "Unable to get device config" );
// Create something of a decent size
if( (cl_ulong)maxWidth * maxHeight * maxDepth > maxAllocSize / ( BufferSizeReductionFactor * 4 ) )
{
float rootSize = cbrtf( (float)( maxAllocSize / ( BufferSizeReductionFactor * 4 ) ) );
if( (size_t)rootSize > maxWidth )
outWidth = maxWidth;
else
outWidth = (size_t)rootSize;
if( (size_t)rootSize > maxHeight )
outHeight = maxHeight;
else
outHeight = (size_t)rootSize;
outDepth = (size_t)( ( maxAllocSize / ( BufferSizeReductionFactor * 4 ) ) / ( outWidth * outHeight ) );
if( outDepth > maxDepth )
outDepth = maxDepth;
}
else
{
outWidth = maxWidth;
outHeight = maxHeight;
outDepth = maxDepth;
}
outWidth /=2;
outHeight /=2;
outDepth /=2;
if (outWidth > 512)
outWidth = 512;
if (outHeight > 512)
outHeight = 512;
if (outDepth > 512)
outDepth = 512;
log_info("\tImage size: %d x %d x %d (%gMB)\n", (int)outWidth, (int)outHeight, (int)outDepth,
(double)((int)outWidth*(int)outHeight*(int)outDepth*4)/(1024.0*1024.0));
return CL_SUCCESS;
}
#pragma mark -------------------- Execution Sub-Classes -------------------------
cl_int NDRangeKernelAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
const char *long_kernel[] = {
"__kernel void sample_test(__global float *src, __global int *dst)\n"
"{\n"
" int tid = get_global_id(0);\n"
" int i;\n"
"\n"
" for( i = 0; i < 100000; i++ )\n"
" {\n"
" dst[tid] = (int)src[tid] * 3;\n"
" }\n"
"\n"
"}\n" };
size_t threads[1] = { 1000 };
int error;
if( create_single_kernel_helper( context, &mProgram, &mKernel, 1, long_kernel, "sample_test" ) )
{
return -1;
}
error = get_max_common_work_group_size( context, mKernel, threads[0], &mLocalThreads[0] );
test_error( error, "Unable to get work group size to use" );
mStreams[0] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1000, NULL, &error );
test_error( error, "Creating test array failed" );
mStreams[1] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_int) * 1000, NULL, &error );
test_error( error, "Creating test array failed" );
/* Set the arguments */
error = clSetKernelArg( mKernel, 0, sizeof( mStreams[0] ), &mStreams[0] );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( mKernel, 1, sizeof( mStreams[1] ), &mStreams[1] );
test_error( error, "Unable to set kernel arguments" );
return CL_SUCCESS;
}
cl_int NDRangeKernelAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t threads[1] = { 1000 };
cl_int error = clEnqueueNDRangeKernel( queue, mKernel, 1, NULL, threads, mLocalThreads, numWaits, waits, outEvent );
test_error( error, "Unable to execute kernel" );
return CL_SUCCESS;
}
#pragma mark -------------------- Buffer Sub-Classes -------------------------
cl_int BufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue, bool allocate )
{
cl_int error;
cl_ulong maxAllocSize;
// Get the largest possible buffer we could allocate
error = clGetDeviceInfo( device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof( maxAllocSize ), &maxAllocSize, NULL );
// Don't create a buffer quite that big, just so we have some space left over for other work
mSize = (size_t)( maxAllocSize / BufferSizeReductionFactor );
// Cap at 128M so tests complete in a reasonable amount of time.
if (mSize > 128 << 20)
mSize = 128 << 20;
mSize /=2;
log_info("\tBuffer size: %gMB\n", (double)mSize/(1024.0*1024.0));
mBuffer = clCreateBuffer( context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, mSize, NULL, &error );
test_error( error, "Unable to create buffer to test against" );
mOutBuffer = malloc( mSize );
if( mOutBuffer == NULL )
{
log_error( "ERROR: Unable to allocate temp buffer (out of memory)\n" );
return CL_OUT_OF_RESOURCES;
}
return CL_SUCCESS;
}
cl_int ReadBufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
return BufferAction::Setup( device, context, queue, true );
}
cl_int ReadBufferAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
cl_int error = clEnqueueReadBuffer( queue, mBuffer, CL_FALSE, 0, mSize, mOutBuffer, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue buffer read" );
return CL_SUCCESS;
}
cl_int WriteBufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
return BufferAction::Setup( device, context, queue, true );
}
cl_int WriteBufferAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
cl_int error = clEnqueueWriteBuffer( queue, mBuffer, CL_FALSE, 0, mSize, mOutBuffer, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue buffer write" );
return CL_SUCCESS;
}
MapBufferAction::~MapBufferAction()
{
if (mQueue)
clEnqueueUnmapMemObject( mQueue, mBuffer, mMappedPtr, 0, NULL, NULL );
}
cl_int MapBufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
return BufferAction::Setup( device, context, queue, false );
}
cl_int MapBufferAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
cl_int error;
mQueue = queue;
mMappedPtr = clEnqueueMapBuffer( queue, mBuffer, CL_FALSE, CL_MAP_READ, 0, mSize, numWaits, waits, outEvent, &error );
test_error( error, "Unable to enqueue buffer map" );
return CL_SUCCESS;
}
cl_int UnmapBufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error = BufferAction::Setup( device, context, queue, false );
if( error != CL_SUCCESS )
return error;
mMappedPtr = clEnqueueMapBuffer( queue, mBuffer, CL_TRUE, CL_MAP_READ, 0, mSize, 0, NULL, NULL, &error );
test_error( error, "Unable to enqueue buffer map" );
return CL_SUCCESS;
}
cl_int UnmapBufferAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
cl_int error = clEnqueueUnmapMemObject( queue, mBuffer, mMappedPtr, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue buffer unmap" );
return CL_SUCCESS;
}
#pragma mark -------------------- Read/Write Image Classes -------------------------
cl_int ReadImage2DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize2D( device, mWidth, mHeight ) ) )
return error;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mImage = create_image_2d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mOutput = malloc( mWidth * mHeight * 4 );
if( mOutput == NULL )
{
log_error( "ERROR: Unable to allocate buffer: out of memory\n" );
return CL_OUT_OF_RESOURCES;
}
return CL_SUCCESS;
}
cl_int ReadImage2DAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, 1 };
cl_int error = clEnqueueReadImage( queue, mImage, CL_FALSE, origin, region, 0, 0, mOutput, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image read" );
return CL_SUCCESS;
}
cl_int ReadImage3DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mOutput = malloc( mWidth * mHeight * mDepth * 4 );
if( mOutput == NULL )
{
log_error( "ERROR: Unable to allocate buffer: out of memory\n" );
return CL_OUT_OF_RESOURCES;
}
return CL_SUCCESS;
}
cl_int ReadImage3DAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, mDepth };
cl_int error = clEnqueueReadImage( queue, mImage, CL_FALSE, origin, region, 0, 0, mOutput, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image read" );
return CL_SUCCESS;
}
cl_int WriteImage2DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize2D( device, mWidth, mHeight ) ) )
return error;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mImage = create_image_2d( context, CL_MEM_WRITE_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mOutput = malloc( mWidth * mHeight * 4 );
if( mOutput == NULL )
{
log_error( "ERROR: Unable to allocate buffer: out of memory\n" );
return CL_OUT_OF_RESOURCES;
}
return CL_SUCCESS;
}
cl_int WriteImage2DAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, 1 };
cl_int error = clEnqueueWriteImage( queue, mImage, CL_FALSE, origin, region, 0, 0, mOutput, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image write" );
return CL_SUCCESS;
}
cl_int WriteImage3DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mOutput = malloc( mWidth * mHeight * mDepth * 4 );
if( mOutput == NULL )
{
log_error( "ERROR: Unable to allocate buffer: out of memory\n" );
return CL_OUT_OF_RESOURCES;
}
return CL_SUCCESS;
}
cl_int WriteImage3DAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, mDepth };
cl_int error = clEnqueueWriteImage( queue, mImage, CL_FALSE, origin, region, 0, 0, mOutput, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image write" );
return CL_SUCCESS;
}
#pragma mark -------------------- Copy Image Classes -------------------------
cl_int CopyImageAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, mDepth };
cl_int error = clEnqueueCopyImage( queue, mSrcImage, mDstImage, origin, origin, region, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image copy" );
return CL_SUCCESS;
}
cl_int CopyImage2Dto2DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize2D( device, mWidth, mHeight ) ) )
return error;
mWidth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcImage = create_image_2d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDstImage = create_image_2d( context, CL_MEM_WRITE_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDepth = 1;
return CL_SUCCESS;
}
cl_int CopyImage2Dto3DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
mDepth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcImage = create_image_2d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDstImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDepth = 1;
return CL_SUCCESS;
}
cl_int CopyImage3Dto2DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
mDepth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDstImage = create_image_2d( context, CL_MEM_WRITE_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDepth = 1;
return CL_SUCCESS;
}
cl_int CopyImage3Dto3DAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
mDepth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDstImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
return CL_SUCCESS;
}
#pragma mark -------------------- Copy Image/Buffer Classes -------------------------
cl_int Copy2DImageToBufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize2D( device, mWidth, mHeight ) ) )
return error;
mWidth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcImage = create_image_2d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDstBuffer = clCreateBuffer( context, CL_MEM_WRITE_ONLY, mWidth * mHeight * 4, NULL, &error );
test_error( error, "Unable to create buffer to test against" );
return CL_SUCCESS;
}
cl_int Copy2DImageToBufferAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, 1 };
cl_int error = clEnqueueCopyImageToBuffer( queue, mSrcImage, mDstBuffer, origin, region, 0, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image to buffer copy" );
return CL_SUCCESS;
}
cl_int Copy3DImageToBufferAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
mDepth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
mDstBuffer = clCreateBuffer( context, CL_MEM_WRITE_ONLY, mWidth * mHeight * mDepth * 4, NULL, &error );
test_error( error, "Unable to create buffer to test against" );
return CL_SUCCESS;
}
cl_int Copy3DImageToBufferAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, mDepth };
cl_int error = clEnqueueCopyImageToBuffer( queue, mSrcImage, mDstBuffer, origin, region, 0, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue image to buffer copy" );
return CL_SUCCESS;
}
cl_int CopyBufferTo2DImageAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize2D( device, mWidth, mHeight ) ) )
return error;
mWidth /= 2;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mSrcBuffer = clCreateBuffer( context, CL_MEM_READ_ONLY, mWidth * mHeight * 4, NULL, &error );
test_error( error, "Unable to create buffer to test against" );
mDstImage = create_image_2d( context, CL_MEM_WRITE_ONLY, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
return CL_SUCCESS;
}
cl_int CopyBufferTo2DImageAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, 1 };
cl_int error = clEnqueueCopyBufferToImage( queue, mSrcBuffer, mDstImage, 0, origin, region, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue buffer to image copy" );
return CL_SUCCESS;
}
cl_int CopyBufferTo3DImageAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize3D( device, mWidth, mHeight, mDepth ) ) )
return error;
mDepth /= 2;
mSrcBuffer = clCreateBuffer( context, CL_MEM_READ_ONLY, mWidth * mHeight * mDepth * 4, NULL, &error );
test_error( error, "Unable to create buffer to test against" );
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mDstImage = create_image_3d( context, CL_MEM_READ_ONLY, &format, mWidth, mHeight, mDepth, 0, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
return CL_SUCCESS;
}
cl_int CopyBufferTo3DImageAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, mDepth };
cl_int error = clEnqueueCopyBufferToImage( queue, mSrcBuffer, mDstImage, 0, origin, region, numWaits, waits, outEvent );
test_error( error, "Unable to enqueue buffer to image copy" );
return CL_SUCCESS;
}
#pragma mark -------------------- Map Image Class -------------------------
MapImageAction::~MapImageAction()
{
if (mQueue)
clEnqueueUnmapMemObject( mQueue, mImage, mMappedPtr, 0, NULL, NULL );
}
cl_int MapImageAction::Setup( cl_device_id device, cl_context context, cl_command_queue queue )
{
cl_int error;
if( ( error = IGetPreferredImageSize2D( device, mWidth, mHeight ) ) )
return error;
cl_image_format format = { CL_RGBA, CL_SIGNED_INT8 };
mImage = create_image_2d( context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &format, mWidth, mHeight, 0, NULL, &error );
test_error( error, "Unable to create image to test against" );
return CL_SUCCESS;
}
cl_int MapImageAction::Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent )
{
cl_int error;
size_t origin[ 3 ] = { 0, 0, 0 }, region[ 3 ] = { mWidth, mHeight, 1 };
size_t outPitch;
mQueue = queue;
mMappedPtr = clEnqueueMapImage( queue, mImage, CL_FALSE, CL_MAP_READ, origin, region, &outPitch, NULL, numWaits, waits, outEvent, &error );
test_error( error, "Unable to enqueue image map" );
return CL_SUCCESS;
}

View File

@@ -0,0 +1,326 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef _action_classes_h
#define _action_classes_h
#include "testBase.h"
// This is a base class from which all actions are born
// Note: No actions should actually feed I/O to each other, because then
// it would potentially be possible for an implementation to make actions
// wait on one another based on their shared I/O, not because of their
// wait lists!
class Action
{
public:
Action() {}
virtual ~Action() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue ) = 0;
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent ) = 0;
virtual const char * GetName( void ) const = 0;
protected:
cl_int IGetPreferredImageSize2D( cl_device_id device, size_t &outWidth, size_t &outHeight );
cl_int IGetPreferredImageSize3D( cl_device_id device, size_t &outWidth, size_t &outHeight, size_t &outDepth );
};
// Simple NDRangeKernel execution that takes a noticable amount of time
class NDRangeKernelAction : public Action
{
public:
NDRangeKernelAction() {}
virtual ~NDRangeKernelAction() {}
size_t mLocalThreads[ 1 ];
clMemWrapper mStreams[ 2 ];
clProgramWrapper mProgram;
clKernelWrapper mKernel;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "NDRangeKernel"; }
};
// Base action for buffer actions
class BufferAction : public Action
{
public:
clMemWrapper mBuffer;
size_t mSize;
void *mOutBuffer;
BufferAction() { mOutBuffer = NULL; }
virtual ~BufferAction() { free( mOutBuffer ); }
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue, bool allocate );
};
class ReadBufferAction : public BufferAction
{
public:
ReadBufferAction() {}
virtual ~ReadBufferAction() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "ReadBuffer"; }
};
class WriteBufferAction : public BufferAction
{
public:
WriteBufferAction() {}
virtual ~WriteBufferAction() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "WriteBuffer"; }
};
class MapBufferAction : public BufferAction
{
public:
MapBufferAction() : mQueue(0) {}
cl_command_queue mQueue;
void *mMappedPtr;
virtual ~MapBufferAction();
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "MapBuffer"; }
};
class UnmapBufferAction : public BufferAction
{
public:
UnmapBufferAction() {}
virtual ~UnmapBufferAction() {}
void *mMappedPtr;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "UnmapBuffer"; }
};
class ReadImage2DAction : public Action
{
public:
ReadImage2DAction() { mOutput = NULL; }
virtual ~ReadImage2DAction() { free( mOutput ); }
clMemWrapper mImage;
size_t mWidth, mHeight;
void *mOutput;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "ReadImage2D"; }
};
class ReadImage3DAction : public Action
{
public:
ReadImage3DAction() { mOutput = NULL; }
virtual ~ReadImage3DAction() { free( mOutput ); }
clMemWrapper mImage;
size_t mWidth, mHeight, mDepth;
void *mOutput;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "ReadImage3D"; }
};
class WriteImage2DAction : public Action
{
public:
clMemWrapper mImage;
size_t mWidth, mHeight;
void *mOutput;
WriteImage2DAction() { mOutput = NULL; }
virtual ~WriteImage2DAction() { free( mOutput ); }
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "WriteImage2D"; }
};
class WriteImage3DAction : public Action
{
public:
clMemWrapper mImage;
size_t mWidth, mHeight, mDepth;
void *mOutput;
WriteImage3DAction() { mOutput = NULL; }
virtual ~WriteImage3DAction() { free( mOutput ); }
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "WriteImage3D"; }
};
class CopyImageAction : public Action
{
public:
CopyImageAction() {}
virtual ~CopyImageAction() {}
clMemWrapper mSrcImage, mDstImage;
size_t mWidth, mHeight, mDepth;
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
};
class CopyImage2Dto2DAction : public CopyImageAction
{
public:
CopyImage2Dto2DAction() {}
virtual ~CopyImage2Dto2DAction() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual const char * GetName( void ) const { return "CopyImage2Dto2D"; }
};
class CopyImage2Dto3DAction : public CopyImageAction
{
public:
CopyImage2Dto3DAction() {}
virtual ~CopyImage2Dto3DAction() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual const char * GetName( void ) const { return "CopyImage2Dto3D"; }
};
class CopyImage3Dto2DAction : public CopyImageAction
{
public:
CopyImage3Dto2DAction() {}
virtual ~CopyImage3Dto2DAction() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual const char * GetName( void ) const { return "CopyImage3Dto2D"; }
};
class CopyImage3Dto3DAction : public CopyImageAction
{
public:
CopyImage3Dto3DAction() {}
virtual ~CopyImage3Dto3DAction() {}
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual const char * GetName( void ) const { return "CopyImage3Dto3D"; }
};
class Copy2DImageToBufferAction : public Action
{
public:
Copy2DImageToBufferAction() {}
virtual ~Copy2DImageToBufferAction() {}
clMemWrapper mSrcImage, mDstBuffer;
size_t mWidth, mHeight;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "Copy2DImageToBuffer"; }
};
class Copy3DImageToBufferAction : public Action
{
public:
Copy3DImageToBufferAction() {}
virtual ~Copy3DImageToBufferAction() {}
clMemWrapper mSrcImage, mDstBuffer;
size_t mWidth, mHeight, mDepth;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "Copy3DImageToBuffer"; }
};
class CopyBufferTo2DImageAction : public Action
{
public:
CopyBufferTo2DImageAction() {}
virtual ~CopyBufferTo2DImageAction() {}
clMemWrapper mSrcBuffer, mDstImage;
size_t mWidth, mHeight;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "CopyBufferTo2D"; }
};
class CopyBufferTo3DImageAction : public Action
{
public:
CopyBufferTo3DImageAction() {}
virtual ~CopyBufferTo3DImageAction() {}
clMemWrapper mSrcBuffer, mDstImage;
size_t mWidth, mHeight, mDepth;
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "CopyBufferTo3D"; }
};
class MapImageAction : public Action
{
public:
MapImageAction() : mQueue(0) {}
clMemWrapper mImage;
size_t mWidth, mHeight;
void *mMappedPtr;
cl_command_queue mQueue;
virtual ~MapImageAction();
virtual cl_int Setup( cl_device_id device, cl_context context, cl_command_queue queue );
virtual cl_int Execute( cl_command_queue queue, cl_uint numWaits, cl_event *waits, cl_event *outEvent );
virtual const char * GetName( void ) const { return "MapImage"; }
};
#endif // _action_classes_h

View File

@@ -0,0 +1,108 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "../../test_common/harness/compat.h"
#include <stdio.h>
#include <string.h>
#include "procs.h"
#include "../../test_common/harness/testHarness.h"
#if !defined(_WIN32)
#include <unistd.h>
#endif
basefn basefn_list[] = {
test_event_get_execute_status,
test_event_get_write_array_status,
test_event_get_read_array_status,
test_event_get_info,
test_event_wait_for_execute,
test_event_wait_for_array,
test_event_flush,
test_event_finish_execute,
test_event_finish_array,
test_event_release_before_done,
test_event_enqueue_marker,
#ifdef CL_VERSION_1_2
test_event_enqueue_marker_with_list,
test_event_enqueue_barrier_with_list,
#endif
test_event_waitlist_single_queue,
test_event_waitlist_multi_queue,
test_event_waitlist_multi_queue_multi_device,
test_event_enqueue_wait_for_events_single_queue,
test_event_enqueue_wait_for_events_multi_queue,
test_event_enqueue_wait_for_events_multi_queue_multi_device,
test_event_enqueue_marker_single_queue,
test_event_enqueue_marker_multi_queue,
test_event_enqueue_marker_multi_queue_multi_device,
test_event_enqueue_barrier_single_queue,
test_waitlists,
test_userevents,
test_callbacks,
test_callbacks_simultaneous,
test_userevents_multithreaded,
};
const char *basefn_names[] = {
"event_get_execute_status",
"event_get_write_array_status",
"event_get_read_array_status",
"event_get_info",
"event_wait_for_execute",
"event_wait_for_array",
"event_flush",
"event_finish_execute",
"event_finish_array",
"event_release_before_done",
"event_enqueue_marker",
#ifdef CL_VERSION_1_2
"event_enqueue_marker_with_event_list",
"event_enqueue_barrier_with_event_list",
#endif
"out_of_order_event_waitlist_single_queue",
"out_of_order_event_waitlist_multi_queue",
"out_of_order_event_waitlist_multi_queue_multi_device",
"out_of_order_event_enqueue_wait_for_events_single_queue",
"out_of_order_event_enqueue_wait_for_events_multi_queue",
"out_of_order_event_enqueue_wait_for_events_multi_queue_multi_device",
"out_of_order_event_enqueue_marker_single_queue",
"out_of_order_event_enqueue_marker_multi_queue",
"out_of_order_event_enqueue_marker_multi_queue_multi_device",
"out_of_order_event_enqueue_barrier_single_queue",
"waitlists",
"test_userevents",
"callbacks",
"callbacks_simultaneous",
"userevents_multithreaded",
};
ct_assert((sizeof(basefn_names) / sizeof(basefn_names[0])) == (sizeof(basefn_list) / sizeof(basefn_list[0])));
int num_fns = sizeof(basefn_names) / sizeof(char *);
int main(int argc, const char *argv[])
{
return runTestHarness( argc, argv, num_fns, basefn_list, basefn_names, false, false, 0 );
}

View File

@@ -0,0 +1,61 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "../../test_common/harness/errorHelpers.h"
#include "../../test_common/harness/kernelHelpers.h"
#include "../../test_common/harness/typeWrappers.h"
#include "../../test_common/harness/clImageHelper.h"
extern float random_float(float low, float high);
extern float calculate_ulperror(float a, float b);
extern int test_event_get_execute_status(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_get_write_array_status(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_get_read_array_status(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_get_info( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_wait_for_execute(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_wait_for_array(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_flush(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_finish_execute(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_finish_array(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_release_before_done(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_marker(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
#ifdef CL_VERSION_1_2
extern int test_event_enqueue_marker_with_list(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_barrier_with_list(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
#endif
extern int test_event_waitlist_single_queue(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_waitlist_multi_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_waitlist_multi_queue_multi_device(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_wait_for_events_single_queue(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_wait_for_events_multi_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_wait_for_events_multi_queue_multi_device(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_barrier_single_queue(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_marker_single_queue(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_marker_multi_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_event_enqueue_marker_multi_queue_multi_device(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_waitlists( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements );
extern int test_userevents( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements );
extern int test_callbacks( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements );
extern int test_callbacks_simultaneous( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements );
extern int test_userevents_multithreaded( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements );

View File

@@ -0,0 +1,31 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef _testBase_h
#define _testBase_h
#include "../../test_common/harness/compat.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "procs.h"
#endif // _testBase_h

View File

@@ -0,0 +1,341 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "action_classes.h"
#include "../../test_common/harness/conversions.h"
#include "../../test_common/harness/ThreadPool.h"
#if !defined (_MSC_VER)
#include <unistd.h>
#endif // !_MSC_VER
extern const char *IGetStatusString( cl_int status );
#define PRINT_OPS 0
// Yes, this is somewhat nasty, in that we're relying on the CPU (the real CPU, not the OpenCL device)
// to be atomic w.r.t. boolean values. Although if it isn't, we'll just miss the check on this bool
// until the next time around, so it's not that big of a deal. Ideally, we'd be using a semaphore with
// a trywait on it, but then that introduces the fun issue of what to do on Win32, etc. This way is
// far more portable, and worst case of failure is a slightly longer test run.
static bool sCallbackTriggered = false;
#define EVENT_CALLBACK_TYPE_TOTAL 3
static bool sCallbackTriggered_flag[ EVENT_CALLBACK_TYPE_TOTAL ] ={ false,false, false };
cl_int event_callback_types[EVENT_CALLBACK_TYPE_TOTAL] ={ CL_SUBMITTED, CL_RUNNING, CL_COMPLETE};
// Our callback function
/*void CL_CALLBACK single_event_callback_function( cl_event event, cl_int commandStatus, void * userData )
{
int i=*static_cast<int *>(userData);
log_info( "\tEvent callback %d triggered\n", i);
sCallbackTriggered_flag [ i ] = true;
}*/
/* use struct as call back para */
typedef struct { cl_int enevt_type; int index; } CALL_BACK_USER_DATA;
void CL_CALLBACK single_event_callback_function_flags( cl_event event, cl_int commandStatus, void * userData )
{
// int i=*static_cast<int *>(userData);
CALL_BACK_USER_DATA *pdata= static_cast<CALL_BACK_USER_DATA *>(userData);
log_info( "\tEvent callback %d of type %d triggered\n", pdata->index, pdata->enevt_type);
sCallbackTriggered_flag [pdata->index ] = true;
}
int test_callback_event_single( cl_device_id device, cl_context context, cl_command_queue queue, Action *actionToTest )
{
// Note: we don't use the waiting feature here. We just want to verify that we get a callback called
// when the given event finishes
cl_int error = actionToTest->Setup( device, context, queue );
test_error( error, "Unable to set up test action" );
// Set up a user event, which we use as a gate for the second event
clEventWrapper gateEvent = clCreateUserEvent( context, &error );
test_error( error, "Unable to set up user gate event" );
// Set up the execution of the action with its actual event
clEventWrapper actualEvent;
error = actionToTest->Execute( queue, 1, &gateEvent, &actualEvent );
test_error( error, "Unable to set up action execution" );
// Set up the callback on the actual event
/* use struct as call back para */
CALL_BACK_USER_DATA user_data[EVENT_CALLBACK_TYPE_TOTAL];
int index [EVENT_CALLBACK_TYPE_TOTAL]={ 0,1,2};
for( int i=0;i< EVENT_CALLBACK_TYPE_TOTAL; i++)
{
user_data[i].enevt_type=event_callback_types[i];
user_data[i].index =i;
error = clSetEventCallback( actualEvent, event_callback_types[i], single_event_callback_function_flags, user_data+i );
}
// Now release the user event, which will allow our actual action to run
error = clSetUserEventStatus( gateEvent, CL_COMPLETE );
test_error( error, "Unable to trigger gate event" );
// Now we wait for completion. Note that we can actually wait on the event itself, at least at first
error = clWaitForEvents( 1, &actualEvent );
test_error( error, "Unable to wait for actual test event" );
// Note: we can check our callback now, and it MIGHT have been triggered, but that's not guaranteed
if( sCallbackTriggered )
{
// We're all good, so return success
return 0;
}
// The callback has not yet been called, but that doesn't mean it won't be. So wait for it
log_info( "\tWaiting for callback..." );
fflush( stdout );
for( int i = 0; i < 10 * 10; i++ )
{
usleep( 100000 ); // 1/10th second
int cc=0;
for( int k=0;k< EVENT_CALLBACK_TYPE_TOTAL;k++)
if (sCallbackTriggered_flag[k]) {
cc++;
}
if (cc== EVENT_CALLBACK_TYPE_TOTAL )
{
log_info( "\n" );
return 0;
}
log_info( "." );
fflush( stdout );
}
// If we got here, we never got the callback
log_error( "\nCallback not called within 10 seconds! (assuming failure)\n" );
return -1;
}
#define TEST_ACTION( name ) \
{ \
name##Action action; \
log_info( "-- Testing " #name "...\n" ); \
if( ( error = test_callback_event_single( deviceID, context, queue, &action ) ) != CL_SUCCESS ) \
retVal++; \
clFinish( queue ); \
}
int test_callbacks( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements )
{
cl_int error;
int retVal = 0;
log_info( "\n" );
TEST_ACTION( NDRangeKernel )
TEST_ACTION( ReadBuffer )
TEST_ACTION( WriteBuffer )
TEST_ACTION( MapBuffer )
TEST_ACTION( UnmapBuffer )
if( checkForImageSupport( deviceID ) == CL_IMAGE_FORMAT_NOT_SUPPORTED )
{
log_info( "\nNote: device does not support images. Skipping remainder of callback tests...\n" );
}
else
{
TEST_ACTION( ReadImage2D )
TEST_ACTION( WriteImage2D )
TEST_ACTION( CopyImage2Dto2D )
TEST_ACTION( Copy2DImageToBuffer )
TEST_ACTION( CopyBufferTo2DImage )
TEST_ACTION( MapImage )
if( checkFor3DImageSupport( deviceID ) == CL_IMAGE_FORMAT_NOT_SUPPORTED )
log_info( "\nNote: device does not support 3D images. Skipping remainder of waitlist tests...\n" );
else
{
TEST_ACTION( ReadImage3D )
TEST_ACTION( WriteImage3D )
TEST_ACTION( CopyImage2Dto3D )
TEST_ACTION( CopyImage3Dto2D )
TEST_ACTION( CopyImage3Dto3D )
TEST_ACTION( Copy3DImageToBuffer )
TEST_ACTION( CopyBufferTo3DImage )
}
}
return retVal;
}
#define SIMUTANEOUS_ACTION_TOTAL 18
static bool sSimultaneousFlags[ 54 ];// for 18 actions with 3 callback status
static volatile int sSimultaneousCount;
Action * actions[ 19 ] = { 0 };
// Callback for the simultaneous tests
void CL_CALLBACK simultaneous_event_callback_function( cl_event event, cl_int commandStatus, void * userData )
{
int eventIndex = (int)(size_t)userData;
int actionIndex = eventIndex/EVENT_CALLBACK_TYPE_TOTAL;
int statusIndex = eventIndex%EVENT_CALLBACK_TYPE_TOTAL;
log_info( "\tEvent callback triggered for action %s callback type %s \n", actions[actionIndex]->GetName(), IGetStatusString(statusIndex) );
sSimultaneousFlags[ actionIndex ] = true;
ThreadPool_AtomicAdd(&sSimultaneousCount,1);
}
int test_callbacks_simultaneous( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements )
{
cl_int error;
// Unlike the singles test, in this one, we run a bunch of events all at once, to verify that
// the callbacks do get called once-and-only-once for each event, even if the run out of order or
// are dependent on each other
// First, the list of actions to run
int actionCount = 0, index = 0;
actions[ index++ ] = new NDRangeKernelAction();
actions[ index++ ] = new ReadBufferAction();
actions[ index++ ] = new WriteBufferAction();
actions[ index++ ] = new MapBufferAction();
actions[ index++ ] = new UnmapBufferAction();
if( checkForImageSupport( deviceID ) != CL_IMAGE_FORMAT_NOT_SUPPORTED )
{
actions[ index++ ] = new ReadImage2DAction();
actions[ index++ ] = new WriteImage2DAction();
actions[ index++ ] = new CopyImage2Dto2DAction();
actions[ index++ ] = new Copy2DImageToBufferAction();
actions[ index++ ] = new CopyBufferTo2DImageAction();
actions[ index++ ] = new MapImageAction();
if( checkFor3DImageSupport( deviceID ) != CL_IMAGE_FORMAT_NOT_SUPPORTED )
{
actions[ index++ ] = new ReadImage3DAction();
actions[ index++ ] = new WriteImage3DAction();
actions[ index++ ] = new CopyImage2Dto3DAction();
actions[ index++ ] = new CopyImage3Dto2DAction();
actions[ index++ ] = new CopyImage3Dto3DAction();
actions[ index++ ] = new Copy3DImageToBufferAction();
actions[ index++ ] = new CopyBufferTo3DImageAction();
}
}
actionCount = index;
actions[ index++ ] = NULL;
// Now set them all up
log_info( "\tSetting up test events...\n" );
for( index = 0; actions[ index ] != NULL; index++ )
{
error = actions[ index ]->Setup( deviceID, context, queue );
test_error( error, "Unable to set up test action" );
sSimultaneousFlags[ index ] = false;
}
sSimultaneousCount = 0;
// Set up the user event to start them all
clEventWrapper gateEvent = clCreateUserEvent( context, &error );
test_error( error, "Unable to set up user gate event" );
// Start executing, all tied to the gate event
//clEventWrapper actionEvents[ 18 ];// current actionCount is 18
clEventWrapper *actionEvents= new clEventWrapper[actionCount];
if (actionEvents == NULL)
{
log_error(" memory error in test_callbacks_simultaneous \n");
for (size_t i=0;i<(sizeof(actions)/sizeof(actions[0]));++i)
if (actions[i]) delete actions[i];
return -1;
}
RandomSeed seed( gRandomSeed );
for( index = 0; actions[ index ] != NULL; index++ )
{
// Randomly choose to wait on the gate, or wait on the previous event
cl_event * eventPtr = &gateEvent;
if( ( index > 0 ) && ( random_in_range( 0, 255, seed ) & 1 ) )
eventPtr = &actionEvents[ index - 1 ];
error = actions[ index ]->Execute( queue, 1, eventPtr, &actionEvents[ index ] );
test_error( error, "Unable to execute test action" );
for( int k=0; k< EVENT_CALLBACK_TYPE_TOTAL; k++)
{
error = clSetEventCallback( actionEvents[index], event_callback_types[k], simultaneous_event_callback_function, (void *)(size_t)(index*EVENT_CALLBACK_TYPE_TOTAL+k ) );
test_error( error, "Unable to set event callback function" );
}
}
int total_callbacks= actionCount * EVENT_CALLBACK_TYPE_TOTAL;
// Now release the user event, which will allow our actual action to run
error = clSetUserEventStatus( gateEvent, CL_COMPLETE );
test_error( error, "Unable to trigger gate event" );
// Wait on the actual action events now
log_info( "\tWaiting for test completions...\n" );
error = clWaitForEvents( actionCount, &actionEvents[ 0 ] );
test_error( error, "Unable to wait for actual test events" );
// Note: we can check our callback now, and it MIGHT have been triggered, but that's not guaranteed
int last_count = 0;
if( ((last_count = sSimultaneousCount)) == total_callbacks)
{
// We're all good, so return success
log_info( "\t%d of %d callbacks received\n", sSimultaneousCount, total_callbacks );
if (actionEvents) delete [] actionEvents;
for (size_t i=0;i<(sizeof(actions)/sizeof(actions[0]));++i)
if (actions[i]) delete actions[i];
return 0;
}
// We haven't gotten (all) of the callbacks, so wait for them
log_info( "\tWe've only received %d of the %d callbacks we expected; waiting for more...\n", last_count, total_callbacks );
for( int i = 0; i < 10 * 10; i++ )
{
usleep( 100000 ); // 1/10th second
if( ((last_count = sSimultaneousCount)) == total_callbacks )
{
// All of the callbacks were executed
if (actionEvents) delete [] actionEvents;
for (size_t i=0;i<(sizeof(actions)/sizeof(actions[0]));++i)
if (actions[i]) delete actions[i];
return 0;
}
}
// If we got here, some of the callbacks did not occur in time
log_error( "\nError: We only ever received %d of our %d callbacks!\n", last_count, total_callbacks );
log_error( "Events that did not receive callbacks:\n" );
for( index = 0; actions[ index ] != NULL; index++ )
{
if( !sSimultaneousFlags[ index ] )
log_error( "\t%s\n", actions[ index ]->GetName() );
}
if (actionEvents) delete [] actionEvents;
return -1;
}

View File

@@ -0,0 +1,509 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "../../test_common/harness/testHarness.h"
const char *write_kernels[] = {
"__kernel void write_up(__global int *dst, int length)\n"
"{\n"
"\n"
" dst[get_global_id(0)] *= 2;\n"
"\n"
"}\n"
"__kernel void write_down(__global int *dst, int length)\n"
"{\n"
"\n"
" dst[get_global_id(0)]--;\n"
"\n"
"}\n"
};
#define TEST_SIZE 10000
#define TEST_COUNT 100
#define RANDOMIZE 1
#define DEBUG_OUT 0
/*
Tests event dependencies by running two kernels that use the same buffer.
If two_queues is set they are run in separate queues.
If test_enqueue_wait_for_events is set then clEnqueueWaitForEvent is called between them.
If test_barrier is set then clEnqueueBarrier is called between them (only for single queue).
If neither are set, nothing is done to prevent them from executing in the wrong order. This can be used for verification.
*/
int test_event_enqueue_wait_for_events_run_test( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements, int two_queues, int two_devices,
int test_enqueue_wait_for_events, int test_barrier, int use_waitlist, int use_marker)
{
cl_int error = CL_SUCCESS;
size_t threads[3] = {TEST_SIZE,0,0};
int i, loop_count, event_count, expected_value, failed;
int expected_if_only_queue[2];
int max_count = TEST_SIZE;
cl_platform_id platform;
cl_command_queue queues[2]; // Not a wrapper so we don't autorelease if they are the same
clCommandQueueWrapper queueWrappers[2]; // If they are different, we use the wrapper so it will auto release
clContextWrapper context_to_use;
clMemWrapper data;
clProgramWrapper program;
clKernelWrapper kernel1[TEST_COUNT], kernel2[TEST_COUNT];
clEventWrapper event[TEST_COUNT*4+2]; // If we usemarkers we get 2 more events per iteration
if (test_enqueue_wait_for_events)
log_info("\tTesting with clEnqueueBarrierWithWaitList as barrier function.\n");
if (test_barrier)
log_info("\tTesting with clEnqueueBarrierWithWaitList as barrier function.\n");
if (use_waitlist)
log_info("\tTesting with waitlist-based depenednecies between kernels.\n");
if (use_marker)
log_info("\tTesting with clEnqueueMarker as a barrier function.\n");
if (test_barrier && (two_queues || two_devices)) {
log_error("\tTest requested with clEnqueueBarrier across two queues. This is not a valid combination.\n");
return -1;
}
error = clGetPlatformIDs(1, &platform, NULL);
test_error(error, "clGetPlatformIDs failed.");
// If we are to use two devices, then get them and create a context with both.
cl_device_id *two_device_ids;
if (two_devices) {
two_device_ids = (cl_device_id*)malloc(sizeof(cl_device_id)*2);
cl_uint number_returned;
error = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 2, two_device_ids, &number_returned);
test_error( error, "clGetDeviceIDs for CL_DEVICE_TYPE_ALL failed.");
if (number_returned != 2) {
log_info("Failed to obtain two devices. Test can not run.\n");
free(two_device_ids);
return 0;
}
for (i=0; i<2; i++) {
cl_device_type type;
error = clGetDeviceInfo(two_device_ids[i], CL_DEVICE_TYPE, sizeof(cl_device_type), &type, NULL);
test_error( error, "clGetDeviceInfo failed.");
if (type & CL_DEVICE_TYPE_CPU)
log_info("\tDevice %d is CL_DEVICE_TYPE_CPU.\n", i);
if (type & CL_DEVICE_TYPE_GPU)
log_info("\tDevice %d is CL_DEVICE_TYPE_GPU.\n", i);
if (type & CL_DEVICE_TYPE_ACCELERATOR)
log_info("\tDevice %d is CL_DEVICE_TYPE_ACCELERATOR.\n", i);
if (type & CL_DEVICE_TYPE_DEFAULT)
log_info("\tDevice %d is CL_DEVICE_TYPE_DEFAULT.\n", i);
}
context_to_use = clCreateContext(NULL, 2, two_device_ids, notify_callback, NULL, &error);
test_error(error, "clCreateContext failed for two devices.");
log_info("\tTesting with two devices.\n");
} else {
context_to_use = clCreateContext(NULL, 1, &deviceID, NULL, NULL, &error);
test_error(error, "clCreateContext failed for one device.");
log_info("\tTesting with one device.\n");
}
// If we are using two queues then create them
cl_queue_properties props[] = {CL_QUEUE_PROPERTIES, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, 0};
if (two_queues) {
// Get a second queue
if (two_devices)
{
if( !checkDeviceForQueueSupport( two_device_ids[ 0 ], props[1] ) ||
!checkDeviceForQueueSupport( two_device_ids[ 1 ], props[1] ) )
{
log_info( "WARNING: One or more device for multi-device test does not support out-of-order exec mode; skipping test.\n" );
return -1942;
}
queueWrappers[0] = clCreateCommandQueueWithProperties(context_to_use, two_device_ids[0], &props[0], &error);
test_error(error, "clCreateCommandQueue for first queue on first device failed.");
queueWrappers[1] = clCreateCommandQueueWithProperties(context_to_use, two_device_ids[1], &props[0], &error);
test_error(error, "clCreateCommandQueue for second queue on second device failed.");
}
else
{
// Single device has already been checked for out-of-order exec support
queueWrappers[0] = clCreateCommandQueueWithProperties(context_to_use, deviceID, &props[0], &error);
test_error(error, "clCreateCommandQueue for first queue failed.");
queueWrappers[1] = clCreateCommandQueueWithProperties(context_to_use, deviceID, &props[0], &error);
test_error(error, "clCreateCommandQueue for second queue failed.");
}
// Ugly hack to make sure we only have the wrapper auto-release if they are different queues
queues[0] = queueWrappers[0];
queues[1] = queueWrappers[1];
log_info("\tTesting with two queues.\n");
}
else
{
// (Note: single device has already been checked for out-of-order exec support)
// Otherwise create one queue and have the second one be the same
queueWrappers[0] = clCreateCommandQueueWithProperties(context_to_use, deviceID, &props[0], &error);
test_error(error, "clCreateCommandQueue for first queue failed.");
queues[0] = queueWrappers[0];
queues[1] = (cl_command_queue)queues[0];
log_info("\tTesting with one queue.\n");
}
// Setup - create a buffer and the two kernels
data = clCreateBuffer(context_to_use, CL_MEM_READ_WRITE, TEST_SIZE*sizeof(cl_int), NULL, &error);
test_error( error, "clCreateBuffer failed");
// Initialize the values to zero
cl_int *values = (cl_int*)malloc(TEST_SIZE*sizeof(cl_int));
for (i=0; i<(int)TEST_SIZE; i++)
values[i] = 0;
error = clEnqueueWriteBuffer(queues[0], data, CL_TRUE, 0, TEST_SIZE*sizeof(cl_int), values, 0, NULL, NULL);
test_error( error, "clEnqueueWriteBuffer failed");
expected_value = 0;
// Build the kernels
if (create_single_kernel_helper( context_to_use, &program, &kernel1[0], 1, write_kernels, "write_up" ))
return -1;
error = clSetKernelArg(kernel1[0], 0, sizeof(data), &data);
error |= clSetKernelArg(kernel1[0], 1, sizeof(max_count), &max_count);
test_error( error, "clSetKernelArg 1 failed");
for (i=1; i<TEST_COUNT; i++) {
kernel1[i] = clCreateKernel(program, "write_up", &error);
test_error( error, "clCreateKernel 1 failed");
error = clSetKernelArg(kernel1[i], 0, sizeof(data), &data);
error |= clSetKernelArg(kernel1[i], 1, sizeof(max_count), &max_count);
test_error( error, "clSetKernelArg 1 failed");
}
for (i=0; i<TEST_COUNT; i++) {
kernel2[i] = clCreateKernel(program, "write_down", &error);
test_error( error, "clCreateKernel 2 failed");
error = clSetKernelArg(kernel2[i], 0, sizeof(data), &data);
error |= clSetKernelArg(kernel2[i], 1, sizeof(max_count), &max_count);
test_error( error, "clSetKernelArg 2 failed");
}
// Execution - run the first kernel, then enqueue the wait on the events, then the second kernel
// If clEnqueueBarrierWithWaitList works, the buffer will be filled with 1s, then multiplied by 4s,
// then incremented to 5s, repeatedly. Otherwise the values may be 2s (if the first one doesn't work) or 8s
// (if the second one doesn't work).
if (RANDOMIZE)
log_info("Queues chosen randomly for each kernel exection.\n");
else
log_info("Queues chosen alternatily for each kernel execution.\n");
event_count = 0;
for (i=0; i<(int)TEST_SIZE; i++)
values[i] = 1;
error = clEnqueueWriteBuffer(queues[0], data, CL_FALSE, 0, TEST_SIZE*sizeof(cl_int), values, 0, NULL, &event[event_count]);
test_error( error, "clEnqueueWriteBuffer 2 failed");
expected_value = 1;
expected_if_only_queue[0] = 1;
expected_if_only_queue[1] = 1;
int queue_to_use = 1;
if (test_enqueue_wait_for_events) {
error = clEnqueueBarrierWithWaitList(queues[queue_to_use], 1, &event[event_count], NULL );
test_error( error, "Unable to queue wait for events" );
} else if (test_barrier) {
error = clEnqueueBarrierWithWaitList(queues[queue_to_use], 0, NULL, NULL);
test_error( error, "Unable to queue barrier" );
}
for (loop_count=0; loop_count<TEST_COUNT; loop_count++) {
// Execute kernel 1
event_count++;
if (use_waitlist | use_marker) {
if (DEBUG_OUT) log_info("clEnqueueNDRangeKernel(queues[%d], kernel1[%d], 1, NULL, threads, NULL, 1, &event[%d], &event[%d])\n", queue_to_use, loop_count, event_count-1, event_count);
error = clEnqueueNDRangeKernel(queues[queue_to_use], kernel1[loop_count], 1, NULL, threads, NULL, 1, &event[event_count-1], &event[event_count]);
} else {
if (DEBUG_OUT) log_info("clEnqueueNDRangeKernel(queues[%d], kernel1[%d], 1, NULL, threads, NULL, 0, NULL, &event[%d])\n", queue_to_use, loop_count, event_count);
error = clEnqueueNDRangeKernel(queues[queue_to_use], kernel1[loop_count], 1, NULL, threads, NULL, 0, NULL, &event[event_count]);
}
if (error) {
log_info("\tLoop count %d\n", loop_count);
print_error( error, "clEnqueueNDRangeKernel for kernel 1 failed");
return error;
}
expected_value *= 2;
expected_if_only_queue[queue_to_use] *= 2;
// If we are using a marker, it needs to go in the same queue
if (use_marker) {
event_count++;
if (DEBUG_OUT) log_info("clEnqueueMarker(queues[%d], event[%d])\n", queue_to_use, event_count);
#ifdef CL_VERSION_1_2
error = clEnqueueMarkerWithWaitList(queues[queue_to_use], 0, NULL, &event[event_count]);
#else
error = clEnqueueMarker(queues[queue_to_use], &event[event_count]);
#endif
}
// Pick the next queue to run
if (RANDOMIZE)
queue_to_use = rand()%2;
else
queue_to_use = (queue_to_use + 1)%2;
// Put in a barrier if requested
if (test_enqueue_wait_for_events) {
if (DEBUG_OUT) log_info("clEnqueueBarrierWithWaitList(queues[%d], 1, &event[%d], NULL)\n", queue_to_use, event_count);
error = clEnqueueBarrierWithWaitList(queues[queue_to_use], 1, &event[event_count], NULL);
test_error( error, "Unable to queue wait for events" );
} else if (test_barrier) {
if (DEBUG_OUT) log_info("clEnqueueBarrierWithWaitList(queues[%d])\n", queue_to_use);
error = clEnqueueBarrierWithWaitList(queues[queue_to_use], 0, NULL, NULL);
test_error( error, "Unable to queue barrier" );
}
// Execute Kernel 2
event_count++;
if (use_waitlist | use_marker) {
if (DEBUG_OUT) log_info("clEnqueueNDRangeKernel(queues[%d], kernel2[%d], 1, NULL, threads, NULL, 1, &event[%d], &event[%d])\n", queue_to_use, loop_count, event_count-1, event_count);
error = clEnqueueNDRangeKernel(queues[queue_to_use], kernel2[loop_count], 1, NULL, threads, NULL, 1, &event[event_count-1], &event[event_count]);
} else {
if (DEBUG_OUT) log_info("clEnqueueNDRangeKernel(queues[%d], kernel2[%d], 1, NULL, threads, NULL, 0, NULL, &event[%d])\n", queue_to_use, loop_count, event_count);
error = clEnqueueNDRangeKernel(queues[queue_to_use], kernel2[loop_count], 1, NULL, threads, NULL, 0, NULL, &event[event_count]);
}
if (error) {
log_info("\tLoop count %d\n", loop_count);
print_error( error, "clEnqueueNDRangeKernel for kernel 2 failed");
return error;
}
expected_value--;
expected_if_only_queue[queue_to_use]--;
// If we are using a marker, it needs to go in the same queue
if (use_marker) {
event_count++;
if (DEBUG_OUT) log_info("clEnqueueMarker(queues[%d], event[%d])\n", queue_to_use, event_count);
#ifdef CL_VERSION_1_2
error = clEnqueueMarkerWithWaitList(queues[queue_to_use], 0, NULL, &event[event_count]);
#else
error = clEnqueueMarker(queues[queue_to_use], &event[event_count]);
#endif
}
// Pick the next queue to run
if (RANDOMIZE)
queue_to_use = rand()%2;
else
queue_to_use = (queue_to_use + 1)%2;
// Put in a barrier if requested
if (test_enqueue_wait_for_events) {
if (DEBUG_OUT) log_info("clEnqueueBarrierWithWaitList(queues[%d], 1, &event[%d], NULL)\n", queue_to_use, event_count);
error = clEnqueueBarrierWithWaitList(queues[queue_to_use], 1, &event[event_count], NULL );
test_error( error, "Unable to queue wait for events" );
} else if (test_barrier) {
if (DEBUG_OUT) log_info("clEnqueueBarrierWithWaitList(queues[%d])\n", queue_to_use);
error = clEnqueueBarrierWithWaitList(queues[queue_to_use], 0, NULL, NULL);
test_error( error, "Unable to queue barrier" );
}
}
// Now finish up everything
if (two_queues) {
error = clFlush(queues[1]);
test_error( error, "clFlush[1] failed");
}
error = clEnqueueReadBuffer(queues[0], data, CL_TRUE, 0, TEST_SIZE*sizeof(cl_int), values, 1, &event[event_count], NULL);
test_error(error, "clEnqueueReadBuffer failed");
failed = 0;
for (i=0; i<(int)TEST_SIZE; i++)
if (values[i] != expected_value) {
failed = 1;
log_info("\tvalues[%d] = %d, expected %d (If only queue 1 accessed memory: %d only queue 2 accessed memory: %d)\n",
i, values[i], expected_value, expected_if_only_queue[0], expected_if_only_queue[1]);
break;
}
free(values);
if (two_devices)
free(two_device_ids);
return failed;
}
int test( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements,
int two_queues, int two_devices,
int test_enqueue_wait_for_events, int test_barrier, int use_waitlists, int use_marker)
{
if( !checkDeviceForQueueSupport( deviceID, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) )
{
log_info( "WARNING: Device does not support out-of-order exec mode; skipping test.\n" );
return 0;
}
log_info("Running test for baseline results to determine if out-of-order execution can be detected...\n");
int baseline_results = test_event_enqueue_wait_for_events_run_test(deviceID, context, queue, num_elements, two_queues, two_devices, 0, 0, 0, 0);
if (baseline_results == 0) {
if (test_enqueue_wait_for_events)
log_info("WARNING: could not detect any out-of-order execution without using clEnqueueBarrierWithWaitList, so this test is not a valid test of out-of-order event dependencies.\n");
if (test_barrier)
log_info("WARNING: could not detect any out-of-order execution without using clEnqueueBarrierWithWaitList, so this test is not a valid test of out-of-order event dependencies.\n");
if (use_waitlists)
log_info("WARNING: could not detect any out-of-order execution without using waitlists, so this test is not a valid test of out-of-order event dependencies.\n");
if (use_marker)
log_info("WARNING: could not detect any out-of-order execution without using clEnqueueMarker, so this test is not a valid test of out-of-order event dependencies.\n");
} else if (baseline_results == 1) {
if (test_enqueue_wait_for_events)
log_info("Detected incorrect execution (possibly out-of-order) without clEnqueueBarrierWithWaitList. Test can be a valid test of out-of-order event dependencies.\n");
if (test_barrier)
log_info("Detected incorrect execution (possibly out-of-order) without clEnqueueBarrierWithWaitList. Test can be a valid test of out-of-order event dependencies.\n");
if (use_waitlists)
log_info("Detected incorrect execution (possibly out-of-order) without waitlists. Test can be a valid test of out-of-order event dependencies.\n");
if (use_marker)
log_info("Detected incorrect execution (possibly out-of-order) without clEnqueueMarker. Test can be a valid test of out-of-order event dependencies.\n");
} else if( baseline_results == -1942 ) {
// Just ignore and return (out-of-order exec mode not supported)
return 0;
} else {
print_error(baseline_results, "Baseline run failed");
return baseline_results;
}
log_info("Running test for actual results...\n");
return test_event_enqueue_wait_for_events_run_test(deviceID, context, queue, num_elements, two_queues, two_devices,
test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_waitlist_single_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 0;
int two_devices = 0;
int test_enqueue_wait_for_events = 0;
int test_barrier = 0;
int use_waitlists = 1;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_waitlist_multi_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 1;
int two_devices = 0;
int test_enqueue_wait_for_events = 0;
int test_barrier = 0;
int use_waitlists = 1;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_waitlist_multi_queue_multi_device( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 1;
int two_devices = 1;
int test_enqueue_wait_for_events = 0;
int test_barrier = 0;
int use_waitlists = 1;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_wait_for_events_single_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 0;
int two_devices = 0;
int test_enqueue_wait_for_events = 1;
int test_barrier = 0;
int use_waitlists = 0;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_wait_for_events_multi_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 1;
int two_devices = 0;
int test_enqueue_wait_for_events = 1;
int test_barrier = 0;
int use_waitlists = 0;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_wait_for_events_multi_queue_multi_device( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 1;
int two_devices = 1;
int test_enqueue_wait_for_events = 1;
int test_barrier = 0;
int use_waitlists = 0;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_barrier_single_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 0;
int two_devices = 0;
int test_enqueue_wait_for_events = 0;
int test_barrier = 1;
int use_waitlists = 0;
int use_marker = 0;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_marker_single_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 0;
int two_devices = 0;
int test_enqueue_wait_for_events = 0;
int test_barrier = 0;
int use_waitlists = 0;
int use_marker = 1;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_marker_multi_queue( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 1;
int two_devices = 0;
int test_enqueue_wait_for_events = 0;
int test_barrier = 0;
int use_waitlists = 0;
int use_marker = 1;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}
int test_event_enqueue_marker_multi_queue_multi_device( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int two_queues = 1;
int two_devices = 1;
int test_enqueue_wait_for_events = 0;
int test_barrier = 0;
int use_waitlists = 0;
int use_marker = 1;
return test(deviceID, context, queue, num_elements, two_queues, two_devices, test_enqueue_wait_for_events, test_barrier, use_waitlists, use_marker);
}

View File

@@ -0,0 +1,682 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#if ! defined( _WIN32 )
#include "unistd.h" // for "sleep" used in the "while (1)" busy wait loop in
#endif
// test_event_flush
const char *sample_long_test_kernel[] = {
"__kernel void sample_test(__global float *src, __global int *dst)\n"
"{\n"
" int tid = get_global_id(0);\n"
" int i;\n"
"\n"
" for( i = 0; i < 10000; i++ )\n"
" {\n"
" dst[tid] = (int)src[tid] * 3;\n"
" }\n"
"\n"
"}\n" };
int create_and_execute_kernel( cl_context inContext, cl_command_queue inQueue, cl_program *outProgram, cl_kernel *outKernel, cl_mem *streams,
unsigned int lineCount, const char **lines, const char *kernelName, cl_event *outEvent )
{
size_t threads[1] = { 1000 }, localThreads[1];
int error;
if( create_single_kernel_helper( inContext, outProgram, outKernel, lineCount, lines, kernelName ) )
{
return -1;
}
error = get_max_common_work_group_size( inContext, *outKernel, threads[0], &localThreads[0] );
test_error( error, "Unable to get work group size to use" );
streams[0] = clCreateBuffer(inContext, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1000, NULL, &error);
test_error( error, "Creating test array failed" );
streams[1] = clCreateBuffer(inContext, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_int) * 1000, NULL, &error);
test_error( error, "Creating test array failed" );
/* Set the arguments */
error = clSetKernelArg( *outKernel, 0, sizeof( streams[0] ), &streams[0] );
test_error( error, "Unable to set kernel arguments" );
error = clSetKernelArg( *outKernel, 1, sizeof( streams[1] ), &streams[1] );
test_error( error, "Unable to set kernel arguments" );
error = clEnqueueNDRangeKernel(inQueue, *outKernel, 1, NULL, threads, localThreads, 0, NULL, outEvent);
test_error( error, "Unable to execute test kernel" );
return 0;
}
#define SETUP_EVENT( c, q ) \
clProgramWrapper program; \
clKernelWrapper kernel; \
clMemWrapper streams[2]; \
clEventWrapper event; \
int error; \
if( create_and_execute_kernel( c, q, &program, &kernel, &streams[0], 1, sample_long_test_kernel, "sample_test", &event ) ) return -1;
#define FINISH_EVENT(_q) clFinish(_q)
const char *IGetStatusString( cl_int status )
{
static char tempString[ 128 ];
switch( status )
{
case CL_COMPLETE: return "CL_COMPLETE";
case CL_RUNNING: return "CL_RUNNING";
case CL_QUEUED: return "CL_QUEUED";
case CL_SUBMITTED: return "CL_SUBMITTED";
default:
sprintf( tempString, "<unknown: %d>", (int)status );
return tempString;
}
}
/* Note: tests clGetEventStatus and clReleaseEvent (implicitly) */
int test_event_get_execute_status( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int status;
SETUP_EVENT( context, queue );
/* Now wait for it to be done */
error = clWaitForEvents( 1, &event );
test_error( error, "Unable to wait for event" );
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus to wait for event completion failed" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after event complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
FINISH_EVENT(queue);
return 0;
}
int test_event_get_info( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
SETUP_EVENT( context, queue );
/* Verify parameters of clGetEventInfo not already tested by other tests */
cl_command_queue otherQueue;
size_t size;
error = clGetEventInfo( event, CL_EVENT_COMMAND_QUEUE, sizeof( otherQueue ), &otherQueue, &size );
test_error( error, "Unable to get event info!" );
// We can not check if this is the right queue because this is an opaque object.
if( size != sizeof( queue ) )
{
log_error( "ERROR: Returned command queue size does not validate (expected %d, got %d)\n", (int)sizeof( queue ), (int)size );
return -1;
}
cl_command_type type;
error = clGetEventInfo( event, CL_EVENT_COMMAND_TYPE, sizeof( type ), &type, &size );
test_error( error, "Unable to get event info!" );
if( type != CL_COMMAND_NDRANGE_KERNEL )
{
log_error( "ERROR: Returned command type does not validate (expected %d, got %d)\n", (int)CL_COMMAND_NDRANGE_KERNEL, (int)type );
return -1;
}
if( size != sizeof( type ) )
{
log_error( "ERROR: Returned command type size does not validate (expected %d, got %d)\n", (int)sizeof( type ), (int)size );
return -1;
}
cl_uint count;
error = clGetEventInfo( event, CL_EVENT_REFERENCE_COUNT, sizeof( count ), &count, &size );
test_error( error, "Unable to get event info for CL_EVENT_REFERENCE_COUNT!" );
if( size != sizeof( count ) )
{
log_error( "ERROR: Returned command type size does not validate (expected %d, got %d)\n", (int)sizeof( type ), (int)size );
return -1;
}
cl_context testCtx;
error = clGetEventInfo( event, CL_EVENT_CONTEXT, sizeof( testCtx ), &testCtx, &size );
test_error( error, "Unable to get event context info!" );
if( size != sizeof( context ) )
{
log_error( "ERROR: Returned context size does not validate (expected %d, got %d)\n", (int)sizeof( context ), (int)size );
return -1;
}
if( testCtx != context )
{
log_error( "ERROR: Returned context does not match (expected %p, got %p)\n", (void *)context, (void *)testCtx );
return -1;
}
FINISH_EVENT(queue);
return 0;
}
int test_event_get_write_array_status( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_mem stream;
cl_float testArray[ 1024 * 32 ];
cl_event event;
int error;
cl_int status;
stream = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1024 * 32, NULL, &error );
test_error( error, "Creating test array failed" );
error = clEnqueueWriteBuffer(queue, stream, CL_FALSE, 0, sizeof(cl_float)*1024*32, (void *)testArray, 0, NULL, &event);
test_error( error, "Unable to set testing kernel data" );
/* Now wait for it to be done */
error = clWaitForEvents( 1, &event );
test_error( error, "Unable to wait for event" );
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus to wait for event completion failed" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after array write complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
clReleaseMemObject( stream );
clReleaseEvent( event );
return 0;
}
int test_event_get_read_array_status( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_mem stream;
cl_float testArray[ 1024 * 32 ];
cl_event event;
int error;
cl_int status;
stream = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1024 * 32, NULL, &error );
test_error( error, "Creating test array failed" );
error = clEnqueueReadBuffer(queue, stream, CL_FALSE, 0, sizeof(cl_float)*1024*32, (void *)testArray, 0, NULL, &event);
test_error( error, "Unable to get testing kernel data" );
/* It should still be running... */
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_RUNNING && status != CL_QUEUED && status != CL_SUBMITTED && status != CL_COMPLETE)
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus during array read (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
/* Now wait for it to be done */
error = clWaitForEvents( 1, &event );
test_error( error, "Unable to wait for event" );
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus to wait for event completion failed" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after array read complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
clReleaseMemObject( stream );
clReleaseEvent( event );
return 0;
}
/* clGetEventStatus not implemented yet */
int test_event_wait_for_execute( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int status;
SETUP_EVENT( context, queue );
/* Now we wait for it to be done, then test the status again */
error = clWaitForEvents( 1, &event );
test_error( error, "Unable to wait for execute event" );
/* Make sure it worked */
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after event complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
FINISH_EVENT(queue);
return 0;
}
int test_event_wait_for_array( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_mem streams[2];
cl_float readArray[ 1024 * 32 ];
cl_float writeArray[ 1024 * 32 ];
cl_event events[2];
int error;
cl_int status;
streams[0] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1024 * 32, NULL, &error );
test_error( error, "Creating test array failed" );
streams[1] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1024 * 32, NULL, &error );
test_error( error, "Creating test array failed" );
error = clEnqueueReadBuffer(queue, streams[0], CL_FALSE, 0, sizeof(cl_float)*1024*32, (void *)readArray, 0, NULL, &events[0]);
test_error( error, "Unable to read testing kernel data" );
error = clEnqueueWriteBuffer(queue, streams[1], CL_FALSE, 0, sizeof(cl_float)*1024*32, (void *)writeArray, 0, NULL, &events[1]);
test_error( error, "Unable to write testing kernel data" );
/* Both should still be running */
error = clGetEventInfo( events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_RUNNING && status != CL_QUEUED && status != CL_SUBMITTED && status != CL_COMPLETE)
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus during array read (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
error = clGetEventInfo( events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_RUNNING && status != CL_QUEUED && status != CL_SUBMITTED && status != CL_COMPLETE)
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus during array write (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
/* Now try waiting for both */
error = clWaitForEvents( 2, events );
test_error( error, "Unable to wait for array events" );
/* Double check status on both */
error = clGetEventInfo( events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after array read complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
error = clGetEventInfo( events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after array write complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
clReleaseMemObject( streams[0] );
clReleaseMemObject( streams[1] );
clReleaseEvent( events[0] );
clReleaseEvent( events[1] );
return 0;
}
int test_event_flush( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
int loopCount = 0;
cl_int status;
SETUP_EVENT( context, queue );
/* Now flush. Note that we can't guarantee this actually lets the op finish, but we can guarantee it's no longer queued */
error = clFlush( queue );
test_error( error, "Unable to flush events" );
/* Make sure it worked */
while (1) {
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS,
sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_QUEUED )
break;
#if ! defined( _WIN32 )
sleep(1); // give it some time here.
#else // _WIN32
Sleep(1000);
#endif
++loopCount;
}
/*
CL_QUEUED (command has been enqueued in the command-queue),
CL_SUBMITTED (enqueued command has been submitted by the host to the device associated with the command-queue),
CL_RUNNING (device is currently executing this command),
CL_COMPLETE (the command has completed), or
Error code given by a negative integer value. (command was abnormally terminated this may be caused by a bad memory access etc.).
*/
if(status != CL_COMPLETE && status != CL_SUBMITTED &&
status != CL_RUNNING && status != CL_COMPLETE)
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after event flush (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
/* Now wait */
error = clFinish( queue );
test_error( error, "Unable to finish events" );
FINISH_EVENT(queue);
return 0;
}
int test_event_finish_execute( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int status;
SETUP_EVENT( context, queue );
/* Now flush and finish all ops */
error = clFinish( queue );
test_error( error, "Unable to finish all events" );
/* Make sure it worked */
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after event complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
FINISH_EVENT(queue);
return 0;
}
int test_event_finish_array( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_mem streams[2];
cl_float readArray[ 1024 * 32 ];
cl_float writeArray[ 1024 * 32 ];
cl_event events[2];
int error;
cl_int status;
streams[0] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1024 * 32, NULL, &error );
test_error( error, "Creating test array failed" );
streams[1] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * 1024 * 32, NULL, &error );
test_error( error, "Creating test array failed" );
error = clEnqueueReadBuffer(queue, streams[0], CL_FALSE, 0, sizeof(cl_float)*1024*32, (void *)readArray, 0, NULL, &events[0]);
test_error( error, "Unable to read testing kernel data" );
error = clEnqueueWriteBuffer(queue, streams[1], CL_FALSE, 0, sizeof(cl_float)*1024*32, (void *)writeArray, 0, NULL, &events[1]);
test_error( error, "Unable to write testing kernel data" );
/* Both should still be running */
error = clGetEventInfo( events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_RUNNING && status != CL_QUEUED && status != CL_SUBMITTED && status != CL_COMPLETE)
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus during array read (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
error = clGetEventInfo( events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_RUNNING && status != CL_QUEUED && status != CL_SUBMITTED && status != CL_COMPLETE)
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus during array write (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
/* Now try finishing all ops */
error = clFinish( queue );
test_error( error, "Unable to finish all events" );
/* Double check status on both */
error = clGetEventInfo( events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after array read complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
error = clGetEventInfo( events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventStatus didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetErrorStatus after array write complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
clReleaseMemObject( streams[0] );
clReleaseMemObject( streams[1] );
clReleaseEvent( events[0] );
clReleaseEvent( events[1] );
return 0;
}
#define NUM_EVENT_RUNS 100
int test_event_release_before_done( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
// Create a kernel to run
clProgramWrapper program;
clKernelWrapper kernel[NUM_EVENT_RUNS];
size_t threads[1] = { 1000 };
cl_event events[NUM_EVENT_RUNS];
cl_int status;
clMemWrapper streams[NUM_EVENT_RUNS][2];
int error, i;
// Create a kernel
if( create_single_kernel_helper( context, &program, &kernel[0], 1, sample_long_test_kernel, "sample_test" ) )
{
return -1;
}
for( i = 1; i < NUM_EVENT_RUNS; i++ ) {
kernel[i] = clCreateKernel(program, "sample_test", &error);
test_error(error, "Unable to create kernel");
}
error = get_max_common_work_group_size( context, kernel[0], 1024, &threads[0] );
test_error( error, "Unable to get work group size to use" );
// Create a set of streams to use as arguments
for( i = 0; i < NUM_EVENT_RUNS; i++ )
{
streams[i][0] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_float) * threads[0], NULL, &error );
streams[i][1] = clCreateBuffer( context, (cl_mem_flags)(CL_MEM_READ_WRITE), sizeof(cl_int) * threads[0], NULL, &error );
if( ( streams[i][0] == NULL ) || ( streams[i][1] == NULL ) )
{
log_error( "ERROR: Unable to allocate testing streams" );
return -1;
}
}
// Execute the kernels one by one, hopefully making sure they won't be done by the time we get to the end
for( i = 0; i < NUM_EVENT_RUNS; i++ )
{
error = clSetKernelArg( kernel[i], 0, sizeof( cl_mem ), &streams[i][0] );
error |= clSetKernelArg( kernel[i], 1, sizeof( cl_mem ), &streams[i][1] );
test_error( error, "Unable to set kernel arguments" );
error = clEnqueueNDRangeKernel( queue, kernel[i], 1, NULL, threads, threads, 0, NULL, &events[i]);
test_error( error, "Unable to execute test kernel" );
}
// Free all but the last event
for( i = 0; i < NUM_EVENT_RUNS - 1; i++ )
{
clReleaseEvent( events[ i ] );
}
// Get status on the last one, then free it
error = clGetEventInfo( events[ NUM_EVENT_RUNS - 1 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Unable to get event status" );
clReleaseEvent( events[ NUM_EVENT_RUNS - 1 ] );
// Was the status still-running?
if( status == CL_COMPLETE )
{
log_info( "WARNING: Events completed before they could be released, so test is a null-op. Increase workload and try again." );
}
else if( status == CL_RUNNING || status == CL_QUEUED || status == CL_SUBMITTED )
{
log_info( "Note: Event status was running or queued when released, so test was good.\n" );
}
// If we didn't crash by now, the test succeeded
clFinish( queue );
return 0;
}
int test_event_enqueue_marker( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int status;
SETUP_EVENT( context, queue );
/* Now we queue a marker and wait for that, which--since it queues afterwards--should guarantee the execute finishes too */
clEventWrapper markerEvent;
//error = clEnqueueMarker( queue, &markerEvent );
#ifdef CL_VERSION_1_2
error = clEnqueueMarkerWithWaitList(queue, 0, NULL, &markerEvent );
#else
error = clEnqueueMarker( queue, &markerEvent );
#endif
test_error( error, "Unable to queue marker" );
/* Now we wait for it to be done, then test the status again */
error = clWaitForEvents( 1, &markerEvent );
test_error( error, "Unable to wait for marker event" );
/* Check the status of the first event */
error = clGetEventInfo( event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status ), &status, NULL );
test_error( error, "Calling clGetEventInfo didn't work!" );
if( status != CL_COMPLETE )
{
log_error( "ERROR: Incorrect status returned from clGetEventInfo after event complete (%d:%s)\n", status, IGetStatusString( status ) );
return -1;
}
FINISH_EVENT(queue);
return 0;
}
#ifdef CL_VERSION_1_2
int test_event_enqueue_marker_with_list( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int status;
SETUP_EVENT( context, queue );
cl_event event_list[3]={ NULL, NULL, NULL};
size_t threads[1] = { 10 }, localThreads[1]={1};
cl_uint event_count=2;
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[0]);
test_error( error, " clEnqueueMarkerWithWaitList 1 " );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[1]);
test_error( error, " clEnqueueMarkerWithWaitList 2" );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, NULL);
test_error( error, " clEnqueueMarkerWithWaitList 3" );
// test the case event returned
error =clEnqueueMarkerWithWaitList(queue, event_count, event_list, &event_list[2]);
test_error( error, " clEnqueueMarkerWithWaitList " );
error = clReleaseEvent(event_list[0]);
error |= clReleaseEvent(event_list[1]);
test_error( error, "clReleaseEvent" );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[0]);
test_error( error, " clEnqueueMarkerWithWaitList 1 -1 " );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[1]);
test_error( error, " clEnqueueMarkerWithWaitList 2-2" );
// test the case event =NULL, caused [CL_INVALID_VALUE] : OpenCL Error : clEnqueueMarkerWithWaitList failed: event is a NULL value
error =clEnqueueMarkerWithWaitList(queue, event_count, event_list, NULL);
test_error( error, " clEnqueueMarkerWithWaitList " );
error = clReleaseEvent(event_list[0]);
error |= clReleaseEvent(event_list[1]);
error |= clReleaseEvent(event_list[2]);
test_error( error, "clReleaseEvent" );
FINISH_EVENT(queue);
return 0;
}
#endif
#ifdef CL_VERSION_1_2
int test_event_enqueue_barrier_with_list( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int status;
SETUP_EVENT( context, queue );
cl_event event_list[3]={ NULL, NULL, NULL};
size_t threads[1] = { 10 }, localThreads[1]={1};
cl_uint event_count=2;
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[0]);
test_error( error, " clEnqueueBarrierWithWaitList 1 " );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[1]);
test_error( error, " clEnqueueBarrierWithWaitList 2" );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, NULL);
test_error( error, " clEnqueueBarrierWithWaitList 20" );
// test the case event returned
error =clEnqueueBarrierWithWaitList(queue, event_count, event_list, &event_list[2]);
test_error( error, " clEnqueueBarrierWithWaitList " );
clReleaseEvent(event_list[0]);
clReleaseEvent(event_list[1]);
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[0]);
test_error( error, " clEnqueueBarrierWithWaitList 1 " );
error= clEnqueueNDRangeKernel( queue,kernel,1,NULL, threads, localThreads, 0, NULL, &event_list[1]);
test_error( error, " clEnqueueBarrierWithWaitList 2" );
// test the case event =NULL, caused [CL_INVALID_VALUE] : OpenCL Error : clEnqueueMarkerWithWaitList failed: event is a NULL value
error = clEnqueueBarrierWithWaitList(queue, event_count, event_list, NULL);
test_error( error, " clEnqueueBarrierWithWaitList " );
clReleaseEvent(event_list[0]);
clReleaseEvent(event_list[1]);
clReleaseEvent(event_list[2]);
FINISH_EVENT(queue);
return 0;
}
#endif

View File

@@ -0,0 +1,293 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#if defined(__APPLE__)
#include <OpenCL/opencl.h>
#include <mach/mach_time.h>
#else
#include <CL/cl.h>
#include <malloc.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "../../test_common/harness/kernelHelpers.h"
///////////////////////////////////////////////////////////////////////////////
// ATF performance framework.
#if USE_ATF
#include <ATF/ATF.h>
#define test_start() ATFTestStart()
#define log_perf(_number, _higherBetter, _numType, _format, ...) ATFLogPerformanceNumber(_number, _higherBetter, _numType, _format,##__VA_ARGS__)
#define log_info ATFLogInfo
#define log_error ATFLogError
#define log_no_atf
#define test_finish() ATFTestFinish()
#else
#define test_start()
#define log_perf(_number, _higherBetter, _numType, _format, ...) printf("Performance Number " _format " (in %s, %s): %g\n",##__VA_ARGS__, _numType, _higherBetter?"higher is better":"lower is better" , _number)
#define log_info(...) fprintf(stdout, ## __VA_ARGS__ )
#define log_error(...) fprintf(stderr, ## __VA_ARGS__ )
#define log_info_no_atf(...) log_info(## __VA_ARGS__ )
#define test_finish()
#endif
///////////////////////////////////////////////////////////////////////////////
// CL error checking.
#define CL_DEVICE_TYPE_ENV_MUST_BE( bitfield_ )\
{\
cl_device_type device_type = CL_DEVICE_TYPE_DEFAULT;\
const char* device_env = getenv("CL_DEVICE_TYPE");\
if (device_env != NULL) {\
if (!strcmp( device_env, "gpu" ) || !strcmp( device_env, "CL_DEVICE_TYPE_GPU" ))\
device_type = CL_DEVICE_TYPE_GPU;\
else if(!strcmp( device_env, "cpu" ) || !strcmp( device_env, "CL_DEVICE_TYPE_CPU" ))\
device_type = CL_DEVICE_TYPE_CPU;\
else if(!strcmp( device_env, "default" ) || !strcmp( device_env, "CL_DEVICE_TYPE_DEFAULT" ))\
device_type = CL_DEVICE_TYPE_DEFAULT;\
if (!(device_type & bitfield_)) {\
log_error( "CL_DEVICE_TYPE environment variable \"%s\" must be \"%s\".", device_env, #bitfield_ );\
abort();\
}\
}\
}\
#define CL_DEVICE_TYPE_ENV( device_type_ )\
{\
const char* device_env = getenv("CL_DEVICE_TYPE");\
if (device_env != NULL) {\
if (!strcmp( device_env, "gpu" ) || !strcmp( device_env, "CL_DEVICE_TYPE_GPU" ))\
device_type_ = CL_DEVICE_TYPE_GPU;\
else if(!strcmp( device_env, "cpu" ) || !strcmp( device_env, "CL_DEVICE_TYPE_CPU" ))\
device_type_ = CL_DEVICE_TYPE_CPU;\
else if(!strcmp( device_env, "default" ) || !strcmp( device_env, "CL_DEVICE_TYPE_DEFAULT" ))\
device_type_ = CL_DEVICE_TYPE_DEFAULT;\
}\
}
#if defined(_MSC_VER)
#define CL_EXIT_ERROR(cmd,...) \
{ \
if ((cmd) != CL_SUCCESS) { \
log_error("CL ERROR: %s %u: ", __FILE__,__LINE__);\
log_error(## __VA_ARGS__ );\
log_error("\n");\
return -1;\
}\
}
#else
#define CL_EXIT_ERROR(cmd,format,...) \
{ \
if ((cmd) != CL_SUCCESS) { \
log_error("CL ERROR: %s %u: ", __FILE__,__LINE__);\
log_error(format,## __VA_ARGS__ );\
log_error("\n");\
return -1;\
}\
}
#endif
#define CL_EXIT_BUILD_ERROR(cmd,program,format,...) \
{ \
if ((cmd) != CL_SUCCESS) { \
cl_uint num_devices_;\
clGetProgramInfo(program,CL_PROGRAM_NUM_DEVICES,sizeof(num_devices_),&num_devices_,NULL);\
cl_device_id *device_list;\
device_list=(cl_device_id *)malloc(num_devices_*sizeof(cl_device_id));\
clGetProgramInfo(program,CL_PROGRAM_DEVICES,num_devices_*sizeof(cl_device_id),device_list,NULL);\
for (unsigned i=0;i<num_devices_;++i) {\
size_t len;\
char buffer[2048];\
clGetProgramBuildInfo(program,device_list[i],CL_PROGRAM_BUILD_LOG,sizeof(buffer),buffer,&len);\
log_error("DEVICE %u CL BUILD ERROR: %s(%u): ",i,__FILE__,__LINE__);\
log_error(format,## __VA_ARGS__ );\
log_error("\n");\
}\
free(device_list);\
return -1;\
}\
}
const char* src[] = {
"__kernel void simple_task(__global float* output) {\n"
" output[0] += 1;\n"
"}\n"
};
enum { MaxDevices = 8 };
int test_userevents( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements)
{
cl_int err;
cl_event u1 = clCreateUserEvent( context, &err );
CL_EXIT_ERROR(err,"clCreateUserEvent failed");
// Test event properties.
cl_int s;
size_t sizeofs;
CL_EXIT_ERROR(clGetEventInfo(u1, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof s, &s, &sizeofs),"clGetEventInfo failed");
CL_EXIT_ERROR((sizeof s == sizeofs) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong size for CL_EVENT_COMMAND_EXECUTION_STATUS");
CL_EXIT_ERROR((s == CL_SUBMITTED) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong value for CL_EVENT_COMMAND_EXECUTION_STATUS");
cl_command_type t;
size_t sizeoft;
CL_EXIT_ERROR(clGetEventInfo(u1, CL_EVENT_COMMAND_TYPE, sizeof t, &t, &sizeoft),"clGetEventInfo failed");
CL_EXIT_ERROR((sizeof t == sizeoft) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong size for CL_EVENT_COMMAND_TYPE");
CL_EXIT_ERROR((t == CL_COMMAND_USER) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong value for CL_EVENT_COMMAND_TYPE");
cl_command_queue q;
size_t sizeofq;
CL_EXIT_ERROR(clGetEventInfo(u1, CL_EVENT_COMMAND_QUEUE, sizeof q, &q, &sizeofq),"clGetEventInfo failed");
CL_EXIT_ERROR((sizeof q == sizeofq) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong size for CL_EVENT_COMMAND_QUEUE");
CL_EXIT_ERROR((q == NULL) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong value for CL_EVENT_COMMAND_QUEUE");
cl_context c;
size_t sizeofc;
CL_EXIT_ERROR(clGetEventInfo(u1, CL_EVENT_CONTEXT, sizeof c, &c, &sizeofc),"clGetEventInfo failed");
CL_EXIT_ERROR((sizeof c == sizeofc) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong size for CL_EVENT_CONTEXT");
CL_EXIT_ERROR((c == context) ? CL_SUCCESS : -1,"clGetEventInfo returned wrong value for CL_EVENT_CONTEXT");
cl_ulong p;
err = clGetEventProfilingInfo(u1,CL_PROFILING_COMMAND_QUEUED,sizeof p,&p,0);
CL_EXIT_ERROR((err != CL_SUCCESS) ? CL_SUCCESS : -1,"clGetEventProfilingInfo returned wrong error.");
// Test semantics.
cl_program program;
err = create_single_kernel_helper_create_program(context, &program, 1, src);
CL_EXIT_ERROR(err,"clCreateProgramWithSource failed");
CL_EXIT_BUILD_ERROR(clBuildProgram(program,0,NULL,"",NULL,NULL),program,"Building program from inline src:\t%s",src[0]);
cl_kernel k0 = clCreateKernel(program,"simple_task",&err);
CL_EXIT_ERROR(err,"clCreateKernel failed");
float buffer[1];
cl_mem output = clCreateBuffer(context,CL_MEM_USE_HOST_PTR,sizeof buffer, buffer, &err);
CL_EXIT_ERROR(err,"clCreateBuffer failed.");
CL_EXIT_ERROR(clSetKernelArg(k0,0,sizeof(output),&output),"clSetKernelArg failed");
// Successful case. //////////////////////////////////////////////////////////////////////////////////////
{
cl_event e[4];
cl_uint N = sizeof e / sizeof(cl_event);
log_info("Enqueuing tasks\n");
for (cl_uint i = 0; i != N; ++i)
CL_EXIT_ERROR(clEnqueueTask(queue,k0,1,&u1,&e[i]),"clEnqueueTaskFailed");
log_info("Checking task status before setting user event status\n");
for (cl_uint i = 0; i != N; ++i) {
CL_EXIT_ERROR(clGetEventInfo(e[i],CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof s,&s,0),"clGetEventInfo failed");
CL_EXIT_ERROR((s >= CL_SUBMITTED) ? CL_SUCCESS : -1,"clGetEventInfo %u returned wrong status before user event",i);
}
log_info("Setting user event status to complete\n");
CL_EXIT_ERROR(clSetUserEventStatus(u1,CL_COMPLETE),"clSetUserEventStatus failed");
log_info("Waiting for tasks to finish executing\n");
CL_EXIT_ERROR(clWaitForEvents( 1, &e[N-1] ),"clWaitForEvent failed");
log_info("Checking task status after setting user event status\n");
for (cl_uint i = 0; i != N; ++i) {
CL_EXIT_ERROR(clGetEventInfo(e[i],CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof s,&s,0),"clGetEventInfo failed");
CL_EXIT_ERROR((s != CL_QUEUED) ? CL_SUCCESS : -1,"clGetEventInfo %u returned wrong status %04x after successful user event",i,s);
}
CL_EXIT_ERROR(clReleaseEvent(u1),"clReleaseEvent failed");
for (cl_uint i = 0; i != N; ++i)
CL_EXIT_ERROR(clReleaseEvent(e[i]),"clReleaseEvent failed");
log_info("Successful user event case passed.\n");
}
// Test unsuccessful user event case. ///////////////////////////////////////////////////////////////////
{
cl_event u2 = clCreateUserEvent( context, &err );
CL_EXIT_ERROR(err,"clCreateUserEvent failed");
cl_event e[4];
cl_uint N = sizeof e / sizeof(cl_event);
log_info("Enqueuing tasks\n");
for (cl_uint i = 0; i != N; ++i)
CL_EXIT_ERROR(clEnqueueTask(queue,k0,1,&u2,&e[i]),"clEnqueueTaskFailed");
log_info("Checking task status before setting user event status\n");
for (cl_uint i = 0; i != N; ++i) {
CL_EXIT_ERROR(clGetEventInfo(e[i],CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof s,&s,0),"clGetEventInfo failed");
CL_EXIT_ERROR((s == CL_QUEUED || s == CL_SUBMITTED) ? CL_SUCCESS : -1,"clGetEventInfo %u returned wrong status %d before user event",i, (int) s);
}
log_info("Setting user event status to unsuccessful result\n");
CL_EXIT_ERROR(clSetUserEventStatus(u2,-1),"clSetUserEventStatus failed");
log_info("Waiting for tasks to finish executing\n");
CL_EXIT_ERROR((clWaitForEvents( N, &e[0] )!=CL_SUCCESS) ? CL_SUCCESS : -1,"clWaitForEvent succeeded when it should have failed");
log_info("Checking task status after setting user event status\n");
for (cl_uint i = 0; i != N; ++i) {
CL_EXIT_ERROR(clGetEventInfo(e[i],CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof s,&s,0),"clGetEventInfo failed");
CL_EXIT_ERROR((s != CL_QUEUED) ? CL_SUCCESS : -1,"clGetEventInfo %u returned wrong status %04x after unsuccessful user event",i,s);
}
CL_EXIT_ERROR(clReleaseEvent(u2),"clReleaseEvent failed");
for (cl_uint i = 0; i != N; ++i)
CL_EXIT_ERROR(clReleaseEvent(e[i]),"clReleaseEvent failed");
log_info("Unsuccessful user event case passed.\n");
}
return 0;
}
#if 0
int main(int argc, char** argv)
{
cl_int err;
test_start();
cl_device_type device_type;
CL_DEVICE_TYPE_ENV( device_type );
cl_device_id device_id;
CL_EXIT_ERROR(clGetDeviceIDs(NULL, device_type, 1, &device_id, NULL),"GetDeviceIDs");
// Create a context.
cl_context context = clCreateContext(0, 1, &device_id, NULL, NULL, &err);
CL_EXIT_ERROR(err,"CreateContext");
// Create a command queue.
q = clCreateCommandQueueWithProperties(context,device_id,0,&err);
CL_EXIT_ERROR(err,"clCreateCommandQueue failed");
int ret = test_userevents( device_type, context, queue, 0 );
test_finish();
return ret;
}
#endif

View File

@@ -0,0 +1,82 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "action_classes.h"
#include "../../test_common/harness/conversions.h"
#include "../../test_common/harness/genericThread.h"
#if !defined (_MSC_VER)
#include <unistd.h>
#endif // !_MSC_VER
class releaseEvent_thread : public genericThread
{
public:
releaseEvent_thread( cl_event *event ) : mEvent( event ) {}
cl_event * mEvent;
protected:
virtual void * IRun( void )
{
usleep( 1000000 );
log_info( "\tTriggering gate from separate thread...\n" );
clSetUserEventStatus( *mEvent, CL_COMPLETE );
return NULL;
}
};
int test_userevents_multithreaded( cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements )
{
cl_int error;
// Set up a user event to act as a gate
clEventWrapper gateEvent = clCreateUserEvent( context, &error );
test_error( error, "Unable to create user gate event" );
// Set up a few actions gated on the user event
NDRangeKernelAction action1;
ReadBufferAction action2;
WriteBufferAction action3;
clEventWrapper actionEvents[ 3 ];
Action * actions[] = { &action1, &action2, &action3, NULL };
for( int i = 0; actions[ i ] != NULL; i++ )
{
error = actions[ i ]->Setup( deviceID, context, queue );
test_error( error, "Unable to set up test action" );
error = actions[ i ]->Execute( queue, 1, &gateEvent, &actionEvents[ i ] );
test_error( error, "Unable to execute test action" );
}
// Now, instead of releasing the gate, we spawn a separate thread to do so
releaseEvent_thread thread( &gateEvent );
log_info( "\tStarting trigger thread...\n" );
thread.Start();
log_info( "\tWaiting for actions...\n" );
error = clWaitForEvents( 3, &actionEvents[ 0 ] );
test_error( error, "Unable to wait for action events" );
log_info( "\tActions completed.\n" );
// If we got here without error, we're good
return 0;
}

View File

@@ -0,0 +1,322 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "action_classes.h"
extern const char *IGetStatusString( cl_int status );
#define PRINT_OPS 0
int test_waitlist( cl_device_id device, cl_context context, cl_command_queue queue, Action *actionToTest, bool multiple )
{
NDRangeKernelAction actions[ 2 ];
clEventWrapper events[ 3 ];
cl_int status[ 3 ];
cl_int error;
if (multiple)
log_info("\tExecuting reference event 0, then reference event 1 with reference event 0 in its waitlist, then test event 2 with reference events 0 and 1 in its waitlist.\n");
else
log_info("\tExecuting reference event 0, then test event 2 with reference event 0 in its waitlist.\n");
// Set up the first base action to wait against
error = actions[ 0 ].Setup( device, context, queue );
test_error( error, "Unable to setup base event to wait against" );
if( multiple )
{
// Set up a second event to wait against
error = actions[ 1 ].Setup( device, context, queue );
test_error( error, "Unable to setup second base event to wait against" );
}
// Now set up the actual action to test
error = actionToTest->Setup( device, context, queue );
test_error( error, "Unable to set up test event" );
// Execute all events now
if (PRINT_OPS) log_info("\tExecuting action 0...\n");
error = actions[ 0 ].Execute( queue, 0, NULL, &events[ 0 ] );
test_error( error, "Unable to execute first event" );
if( multiple )
{
if (PRINT_OPS) log_info("\tExecuting action 1...\n");
error = actions[ 1 ].Execute( queue, 1, &events[0], &events[ 1 ] );
test_error( error, "Unable to execute second event" );
}
// Sanity check
if( multiple ) {
if (PRINT_OPS) log_info("\tChecking status of action 1...\n");
error = clGetEventInfo( events[ 1 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 1 ] ), &status[ 1 ], NULL );
test_error( error, "Unable to get event status" );
}
if (PRINT_OPS) log_info("\tChecking status of action 0...\n");
error = clGetEventInfo( events[ 0 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 0 ] ), &status[ 0 ], NULL );
test_error( error, "Unable to get event status" );
log_info("\t\tEvent status after starting reference events: reference event 0: %s, reference event 1: %s, test event 2: %s.\n",
IGetStatusString( status[ 0 ] ), (multiple ? IGetStatusString( status[ 1 ] ) : "N/A"), "N/A");
if( ( status[ 0 ] == CL_COMPLETE ) || ( multiple && status[ 1 ] == CL_COMPLETE ) )
{
log_info( "WARNING: Reference event(s) already completed before we could execute test event! Possible that the reference event blocked (implicitly passing)\n" );
return 0;
}
if (PRINT_OPS) log_info("\tExecuting action to test...\n");
error = actionToTest->Execute( queue, ( multiple ) ? 2 : 1, &events[ 0 ], &events[ 2 ] );
test_error( error, "Unable to execute test event" );
// Hopefully, the first event is still running
if (PRINT_OPS) log_info("\tChecking status of action to test 2...\n");
error = clGetEventInfo( events[ 2 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 2 ] ), &status[ 2 ], NULL );
test_error( error, "Unable to get event status" );
if( multiple ) {
if (PRINT_OPS) log_info("\tChecking status of action 1...\n");
error = clGetEventInfo( events[ 1 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 1 ] ), &status[ 1 ], NULL );
test_error( error, "Unable to get event status" );
}
if (PRINT_OPS) log_info("\tChecking status of action 0...\n");
error = clGetEventInfo( events[ 0 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 0 ] ), &status[ 0 ], NULL );
test_error( error, "Unable to get event status" );
log_info("\t\tEvent status after starting test event: reference event 0: %s, reference event 1: %s, test event 2: %s.\n",
IGetStatusString( status[ 0 ] ), (multiple ? IGetStatusString( status[ 1 ] ) : "N/A"), IGetStatusString( status[ 2 ] ));
if( multiple )
{
if( status[ 0 ] == CL_COMPLETE && status[ 1 ] == CL_COMPLETE )
{
log_info( "WARNING: Both events completed, so unable to test further (implicitly passing).\n" );
clFinish( queue );
return 0;
}
if(status[1] == CL_COMPLETE && status[0] != CL_COMPLETE)
{
log_error("ERROR: Test failed because the second wait event is complete and the first is not.(status: 0: %s and 1: %s)\n", IGetStatusString( status[ 0 ] ), IGetStatusString( status[ 1 ] ) );
clFinish( queue );
return -1;
}
}
else
{
if( status[ 0 ] == CL_COMPLETE )
{
log_info( "WARNING: Reference event completed, so unable to test further (implicitly passing).\n" );
clFinish( queue );
return 0;
}
if( status[ 0 ] != CL_RUNNING && status[ 0 ] != CL_QUEUED && status[ 0 ] != CL_SUBMITTED )
{
log_error( "ERROR: Test failed because first wait event is not currently running, queued, or submitted! (status: 0: %s)\n", IGetStatusString( status[ 0 ] ) );
clFinish( queue );
return -1;
}
}
if( status[ 2 ] != CL_QUEUED && status[ 2 ] != CL_SUBMITTED )
{
log_error( "ERROR: Test event is not waiting to run! (status: 2: %s)\n", IGetStatusString( status[ 2 ] ) );
clFinish( queue );
return -1;
}
// Now wait for the first reference event
if (PRINT_OPS) log_info("\tWaiting for action 1 to finish...\n");
error = clWaitForEvents( 1, &events[ 0 ] );
test_error( error, "Unable to wait for reference event" );
// Grab statuses again
if (PRINT_OPS) log_info("\tChecking status of action to test 2...\n");
error = clGetEventInfo( events[ 2 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 2 ] ), &status[ 2 ], NULL );
test_error( error, "Unable to get event status" );
if( multiple ) {
if (PRINT_OPS) log_info("\tChecking status of action 1...\n");
error = clGetEventInfo( events[ 1 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 1 ] ), &status[ 1 ], NULL );
test_error( error, "Unable to get event status" );
}
if (PRINT_OPS) log_info("\tChecking status of action 0...\n");
error = clGetEventInfo( events[ 0 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 0 ] ), &status[ 0 ], NULL );
test_error( error, "Unable to get event status" );
log_info("\t\tEvent status after waiting for reference event 0: reference event 0: %s, reference event 1: %s, test event 2: %s.\n",
IGetStatusString( status[ 0 ] ), (multiple ? IGetStatusString( status[ 1 ] ) : "N/A"), IGetStatusString( status[ 2 ] ));
// Sanity
if( status[ 0 ] != CL_COMPLETE )
{
log_error( "ERROR: Waited for first event but it's not complete (status: 0: %s)\n", IGetStatusString( status[ 0 ] ) );
clFinish( queue );
return -1;
}
// If we're multiple, and the second event isn't complete, then our test event should still be queued
if( multiple && status[ 1 ] != CL_COMPLETE )
{
if( status[ 1 ] == CL_RUNNING && status[ 2 ] == CL_RUNNING ) {
log_error("ERROR: Test event and second event are both running.\n");
clFinish( queue );
return -1;
}
if( status[ 2 ] != CL_QUEUED && status[ 2 ] != CL_SUBMITTED )
{
log_error( "ERROR: Test event did not wait for second event before starting! (status of ref: 1: %s, of test: 2: %s)\n", IGetStatusString( status[ 1 ] ), IGetStatusString( status[ 2 ] ) );
clFinish( queue );
return -1;
}
// Now wait for second event to complete, too
if (PRINT_OPS) log_info("\tWaiting for action 1 to finish...\n");
error = clWaitForEvents( 1, &events[ 1 ] );
test_error( error, "Unable to wait for second reference event" );
// Grab statuses again
if (PRINT_OPS) log_info("\tChecking status of action to test 2...\n");
error = clGetEventInfo( events[ 2 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 2 ] ), &status[ 2 ], NULL );
test_error( error, "Unable to get event status" );
if( multiple ) {
if (PRINT_OPS) log_info("\tChecking status of action 1...\n");
error = clGetEventInfo( events[ 1 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 1 ] ), &status[ 1 ], NULL );
test_error( error, "Unable to get event status" );
}
if (PRINT_OPS) log_info("\tChecking status of action 0...\n");
error = clGetEventInfo( events[ 0 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 0 ] ), &status[ 0 ], NULL );
test_error( error, "Unable to get event status" );
log_info("\t\tEvent status after waiting for reference event 1: reference event 0: %s, reference event 1: %s, test event 2: %s.\n",
IGetStatusString( status[ 0 ] ), (multiple ? IGetStatusString( status[ 1 ] ) : "N/A"), IGetStatusString( status[ 2 ] ));
// Sanity
if( status[ 1 ] != CL_COMPLETE )
{
log_error( "ERROR: Waited for second reference event but it didn't complete (status: 1: %s)\n", IGetStatusString( status[ 1 ] ) );
clFinish( queue );
return -1;
}
}
// At this point, the test event SHOULD be running, but if it completed, we consider it a pass
if( status[ 2 ] == CL_COMPLETE )
{
log_info( "WARNING: Test event already completed. Assumed valid.\n" );
clFinish( queue );
return 0;
}
if( status[ 2 ] != CL_RUNNING && status[ 2 ] != CL_SUBMITTED && status[ 2 ] != CL_QUEUED)
{
log_error( "ERROR: Second event did not start running after reference event(s) completed! (status: 2: %s)\n", IGetStatusString( status[ 2 ] ) );
clFinish( queue );
return -1;
}
// Wait for the test event, then return
if (PRINT_OPS) log_info("\tWaiting for action 2 to test to finish...\n");
error = clWaitForEvents( 1, &events[ 2 ] );
test_error( error, "Unable to wait for test event" );
error |= clGetEventInfo( events[ 2 ], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof( status[ 2 ] ), &status[ 2 ], NULL );
test_error( error, "Unable to get event status" );
log_info("\t\tEvent status after waiting for test event: reference event 0: %s, reference event 1: %s, test event 2: %s.\n",
IGetStatusString( status[ 0 ] ), (multiple ? IGetStatusString( status[ 1 ] ) : "N/A"), IGetStatusString( status[ 2 ] ));
// Sanity
if( status[ 2 ] != CL_COMPLETE )
{
log_error( "ERROR: Test event didn't complete (status: 2: %s)\n", IGetStatusString( status[ 2 ] ) );
clFinish( queue );
return -1;
}
clFinish(queue);
return 0;
}
#define TEST_ACTION( name ) \
{ \
name##Action action; \
log_info( "-- Testing " #name " (waiting on 1 event)...\n" ); \
if( ( error = test_waitlist( deviceID, context, queue, &action, false ) ) != CL_SUCCESS ) \
retVal++; \
clFinish( queue ); \
} \
if( error == CL_SUCCESS ) /* Only run multiples test if single test passed */ \
{ \
name##Action action; \
log_info( "-- Testing " #name " (waiting on 2 events)...\n" ); \
if( ( error = test_waitlist( deviceID, context, queue, &action, true ) ) != CL_SUCCESS ) \
retVal++; \
clFinish( queue ); \
}
int test_waitlists( cl_device_id deviceID, cl_context context, cl_command_queue oldQueue, int num_elements )
{
cl_int error;
int retVal = 0;
cl_queue_properties props[] = {CL_QUEUE_PROPERTIES, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, 0};
if( !checkDeviceForQueueSupport( deviceID, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) )
{
log_info( "WARNING: Device does not support out-of-order exec mode; skipping test.\n" );
return 0;
}
clCommandQueueWrapper queue = clCreateCommandQueueWithProperties( context, deviceID, &props[0], &error );
test_error(error, "Unable to create out-of-order queue");
log_info( "\n" );
TEST_ACTION( NDRangeKernel )
TEST_ACTION( ReadBuffer )
TEST_ACTION( WriteBuffer )
TEST_ACTION( MapBuffer )
TEST_ACTION( UnmapBuffer )
if( checkForImageSupport( deviceID ) == CL_IMAGE_FORMAT_NOT_SUPPORTED )
{
log_info( "\nNote: device does not support images. Skipping remainder of waitlist tests...\n" );
}
else
{
TEST_ACTION( ReadImage2D )
TEST_ACTION( WriteImage2D )
TEST_ACTION( CopyImage2Dto2D )
TEST_ACTION( Copy2DImageToBuffer )
TEST_ACTION( CopyBufferTo2DImage )
TEST_ACTION( MapImage )
if( checkFor3DImageSupport( deviceID ) == CL_IMAGE_FORMAT_NOT_SUPPORTED )
log_info("Device does not support 3D images. Skipping remainder of waitlist tests...\n");
else
{
TEST_ACTION( ReadImage3D )
TEST_ACTION( WriteImage3D )
TEST_ACTION( CopyImage2Dto3D )
TEST_ACTION( CopyImage3Dto2D )
TEST_ACTION( CopyImage3Dto3D )
TEST_ACTION( Copy3DImageToBuffer )
TEST_ACTION( CopyBufferTo3DImage )
}
}
return retVal;
}