Memory consistency model optionality (#907)

* Test minimum memory consistency capabilities for a device reporting >= 3.0.

Skip tests where unsupported memory consistency capabilities are being requested.

* Pass nullptr as program build option.

Allows the CTS framework to select an appropriate CL C version.

* Removed redundant braces.
This commit is contained in:
Jeremy Kemp
2020-08-31 23:12:10 +01:00
committed by GitHub
parent 590321d98d
commit 1e411b888f
3 changed files with 184 additions and 2 deletions

View File

@@ -65,6 +65,8 @@ extern bool gUseHostPtr; // use malloc/free instead of clSVMAlloc/clSVMFree
extern bool gDebug; // print OpenCL kernel code extern bool gDebug; // print OpenCL kernel code
extern int gInternalIterations; // internal test iterations for atomic operation, sufficient to verify atomicity extern int gInternalIterations; // internal test iterations for atomic operation, sufficient to verify atomicity
extern int gMaxDeviceThreads; // maximum number of threads executed on OCL device extern int gMaxDeviceThreads; // maximum number of threads executed on OCL device
extern cl_device_atomic_capabilities gAtomicMemCap,
gAtomicFenceCap; // atomic memory and fence capabilities for this device
extern const char *get_memory_order_type_name(TExplicitMemoryOrderType orderType); extern const char *get_memory_order_type_name(TExplicitMemoryOrderType orderType);
extern const char *get_memory_scope_type_name(TExplicitMemoryScopeType scopeType); extern const char *get_memory_scope_type_name(TExplicitMemoryScopeType scopeType);
@@ -281,6 +283,88 @@ public:
else else
return 0; return 0;
} }
int CheckCapabilities(TExplicitMemoryScopeType memoryScope,
TExplicitMemoryOrderType memoryOrder)
{
/*
Differentiation between atomic fence and other atomic operations
does not need to occur here.
The initialisation of this test checks that the minimum required
capabilities are supported by this device.
The following switches allow the test to skip if optional capabilites
are not supported by the device.
*/
switch (memoryScope)
{
case MEMORY_SCOPE_EMPTY: {
break;
}
case MEMORY_SCOPE_WORK_GROUP: {
if ((gAtomicMemCap & CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP) == 0)
{
return TEST_SKIPPED_ITSELF;
}
break;
}
case MEMORY_SCOPE_DEVICE: {
if ((gAtomicMemCap & CL_DEVICE_ATOMIC_SCOPE_DEVICE) == 0)
{
return TEST_SKIPPED_ITSELF;
}
break;
}
case MEMORY_SCOPE_ALL_SVM_DEVICES: {
if ((gAtomicMemCap & CL_DEVICE_ATOMIC_SCOPE_ALL_DEVICES) == 0)
{
return TEST_SKIPPED_ITSELF;
}
break;
}
default: {
log_info("Invalid memory scope\n");
break;
}
}
switch (memoryOrder)
{
case MEMORY_ORDER_EMPTY: {
break;
}
case MEMORY_ORDER_RELAXED: {
if ((gAtomicMemCap & CL_DEVICE_ATOMIC_ORDER_RELAXED) == 0)
{
return TEST_SKIPPED_ITSELF;
}
break;
}
case MEMORY_ORDER_ACQUIRE:
case MEMORY_ORDER_RELEASE:
case MEMORY_ORDER_ACQ_REL: {
if ((gAtomicMemCap & CL_DEVICE_ATOMIC_ORDER_ACQ_REL) == 0)
{
return TEST_SKIPPED_ITSELF;
}
break;
}
case MEMORY_ORDER_SEQ_CST: {
if ((gAtomicMemCap & CL_DEVICE_ATOMIC_ORDER_SEQ_CST) == 0)
{
return TEST_SKIPPED_ITSELF;
}
break;
}
default: {
log_info("Invalid memory order\n");
break;
}
}
return 0;
}
virtual bool SVMDataBufferAllSVMConsistent() {return false;} virtual bool SVMDataBufferAllSVMConsistent() {return false;}
bool UseSVM() {return _useSVM;} bool UseSVM() {return _useSVM;}
void StartValue(HostDataType startValue) {_startValue = startValue;} void StartValue(HostDataType startValue) {_startValue = startValue;}
@@ -339,6 +423,7 @@ class CBasicTestMemOrderScope : public CBasicTest<HostAtomicType, HostDataType>
public: public:
using CBasicTest<HostAtomicType, HostDataType>::LocalMemory; using CBasicTest<HostAtomicType, HostDataType>::LocalMemory;
using CBasicTest<HostAtomicType, HostDataType>::MaxGroupSize; using CBasicTest<HostAtomicType, HostDataType>::MaxGroupSize;
using CBasicTest<HostAtomicType, HostDataType>::CheckCapabilities;
CBasicTestMemOrderScope(TExplicitAtomicType dataType, bool useSVM = false) : CBasicTest<HostAtomicType, HostDataType>(dataType, useSVM) CBasicTestMemOrderScope(TExplicitAtomicType dataType, bool useSVM = false) : CBasicTest<HostAtomicType, HostDataType>(dataType, useSVM)
{ {
} }
@@ -389,6 +474,10 @@ public:
MaxGroupSize(16); // increase number of groups by forcing smaller group size MaxGroupSize(16); // increase number of groups by forcing smaller group size
else else
MaxGroupSize(0); // group size limited by device capabilities MaxGroupSize(0); // group size limited by device capabilities
if (CheckCapabilities(MemoryScope(), MemoryOrder()) == TEST_SKIPPED_ITSELF)
return 0; // skip test - not applicable
return CBasicTest<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue); return CBasicTest<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue);
} }
virtual int ExecuteForEachParameterSet(cl_device_id deviceID, cl_context context, cl_command_queue queue) virtual int ExecuteForEachParameterSet(cl_device_id deviceID, cl_context context, cl_command_queue queue)
@@ -470,6 +559,8 @@ public:
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryScope; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryScope;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrderStr; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrderStr;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryScopeStr; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryScopeStr;
using CBasicTest<HostAtomicType, HostDataType>::CheckCapabilities;
CBasicTestMemOrder2Scope(TExplicitAtomicType dataType, bool useSVM = false) : CBasicTestMemOrderScope<HostAtomicType, HostDataType>(dataType, useSVM) CBasicTestMemOrder2Scope(TExplicitAtomicType dataType, bool useSVM = false) : CBasicTestMemOrderScope<HostAtomicType, HostDataType>(dataType, useSVM)
{ {
} }
@@ -517,6 +608,15 @@ public:
MemoryOrder(memoryOrder[oi]); MemoryOrder(memoryOrder[oi]);
MemoryOrder2(memoryOrder[o2i]); MemoryOrder2(memoryOrder[o2i]);
MemoryScope(memoryScope[si]); MemoryScope(memoryScope[si]);
if (CheckCapabilities(MemoryScope(), MemoryOrder())
== TEST_SKIPPED_ITSELF)
continue; // skip test - not applicable
if (CheckCapabilities(MemoryScope(), MemoryOrder2())
== TEST_SKIPPED_ITSELF)
continue; // skip test - not applicable
EXECUTE_TEST(error, (CBasicTest<HostAtomicType, HostDataType>::ExecuteForEachParameterSet(deviceID, context, queue))); EXECUTE_TEST(error, (CBasicTest<HostAtomicType, HostDataType>::ExecuteForEachParameterSet(deviceID, context, queue)));
} }
} }
@@ -855,8 +955,9 @@ int CBasicTest<HostAtomicType, HostDataType>::ExecuteSingleTest(cl_device_id dev
// Set up the kernel code // Set up the kernel code
programSource = PragmaHeader(deviceID)+ProgramHeader(numDestItems)+FunctionCode()+KernelCode(numDestItems); programSource = PragmaHeader(deviceID)+ProgramHeader(numDestItems)+FunctionCode()+KernelCode(numDestItems);
programLine = programSource.c_str(); programLine = programSource.c_str();
if(create_single_kernel_helper_with_build_options(context, &program, &kernel, 1, &programLine, "test_atomic_kernel", if (create_single_kernel_helper_with_build_options(
gOldAPI ? "" : "-cl-std=CL2.0")) context, &program, &kernel, 1, &programLine, "test_atomic_kernel",
gOldAPI ? "" : nullptr))
{ {
return -1; return -1;
} }

View File

@@ -26,6 +26,8 @@ bool gUseHostPtr = false; // use malloc/free with CL_MEM_USE_HOST_PTR instead of
bool gDebug = false; // always print OpenCL kernel code bool gDebug = false; // always print OpenCL kernel code
int gInternalIterations = 10000; // internal test iterations for atomic operation, sufficient to verify atomicity int gInternalIterations = 10000; // internal test iterations for atomic operation, sufficient to verify atomicity
int gMaxDeviceThreads = 1024; // maximum number of threads executed on OCL device int gMaxDeviceThreads = 1024; // maximum number of threads executed on OCL device
cl_device_atomic_capabilities gAtomicMemCap,
gAtomicFenceCap; // atomic memory and fence capabilities for this device
extern int test_atomic_init(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements); extern int test_atomic_init(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
extern int test_atomic_store(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements); extern int test_atomic_store(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements);
@@ -108,6 +110,7 @@ const int test_num = ARRAY_SIZE( test_list );
test_status InitCL(cl_device_id device) { test_status InitCL(cl_device_id device) {
auto version = get_device_cl_version(device); auto version = get_device_cl_version(device);
auto expected_min_version = Version(2, 0); auto expected_min_version = Version(2, 0);
if (version < expected_min_version) if (version < expected_min_version)
{ {
version_expected_info("Test", "OpenCL", version_expected_info("Test", "OpenCL",
@@ -115,6 +118,63 @@ test_status InitCL(cl_device_id device) {
version.to_string().c_str()); version.to_string().c_str());
return TEST_SKIP; return TEST_SKIP;
} }
if (version >= Version(3, 0))
{
cl_int error;
error = clGetDeviceInfo(device, CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES,
sizeof(gAtomicMemCap), &gAtomicMemCap, NULL);
if (error != CL_SUCCESS)
{
print_error(error, "Unable to get atomic memory capabilities\n");
return TEST_FAIL;
}
error =
clGetDeviceInfo(device, CL_DEVICE_ATOMIC_FENCE_CAPABILITIES,
sizeof(gAtomicFenceCap), &gAtomicFenceCap, NULL);
if (error != CL_SUCCESS)
{
print_error(error, "Unable to get atomic fence capabilities\n");
return TEST_FAIL;
}
if ((gAtomicFenceCap
& (CL_DEVICE_ATOMIC_ORDER_RELAXED | CL_DEVICE_ATOMIC_ORDER_ACQ_REL
| CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP))
== 0)
{
log_info(
"Minimum atomic fence capabilities unsupported by device\n");
return TEST_FAIL;
}
if ((gAtomicMemCap
& (CL_DEVICE_ATOMIC_ORDER_RELAXED
| CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP))
== 0)
{
log_info(
"Minimum atomic memory capabilities unsupported by device\n");
return TEST_FAIL;
}
}
else
{
// OpenCL 2.x device, default to all capabilities
gAtomicMemCap = CL_DEVICE_ATOMIC_ORDER_RELAXED
| CL_DEVICE_ATOMIC_ORDER_ACQ_REL | CL_DEVICE_ATOMIC_ORDER_SEQ_CST
| CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP | CL_DEVICE_ATOMIC_SCOPE_DEVICE
| CL_DEVICE_ATOMIC_SCOPE_ALL_DEVICES;
gAtomicFenceCap = CL_DEVICE_ATOMIC_ORDER_RELAXED
| CL_DEVICE_ATOMIC_ORDER_ACQ_REL | CL_DEVICE_ATOMIC_ORDER_SEQ_CST
| CL_DEVICE_ATOMIC_SCOPE_WORK_ITEM
| CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP | CL_DEVICE_ATOMIC_SCOPE_DEVICE
| CL_DEVICE_ATOMIC_SCOPE_ALL_DEVICES;
}
return TEST_PASS; return TEST_PASS;
} }

View File

@@ -29,7 +29,9 @@ class CBasicTestStore : public CBasicTestMemOrderScope<HostAtomicType, HostDataT
public: public:
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::OldValueCheck; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::OldValueCheck;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrder; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrder;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryScope;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrderScopeStr; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrderScopeStr;
using CBasicTest<HostAtomicType, HostDataType>::CheckCapabilities;
CBasicTestStore(TExplicitAtomicType dataType, bool useSVM) : CBasicTestMemOrderScope<HostAtomicType, HostDataType>(dataType, useSVM) CBasicTestStore(TExplicitAtomicType dataType, bool useSVM) : CBasicTestMemOrderScope<HostAtomicType, HostDataType>(dataType, useSVM)
{ {
OldValueCheck(false); OldValueCheck(false);
@@ -43,6 +45,10 @@ public:
if(MemoryOrder() == MEMORY_ORDER_ACQUIRE || if(MemoryOrder() == MEMORY_ORDER_ACQUIRE ||
MemoryOrder() == MEMORY_ORDER_ACQ_REL) MemoryOrder() == MEMORY_ORDER_ACQ_REL)
return 0; //skip test - not applicable return 0; //skip test - not applicable
if (CheckCapabilities(MemoryScope(), MemoryOrder()) == TEST_SKIPPED_ITSELF)
return 0; // skip test - not applicable
return CBasicTestMemOrderScope<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue); return CBasicTestMemOrderScope<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue);
} }
virtual std::string ProgramCore() virtual std::string ProgramCore()
@@ -198,7 +204,9 @@ class CBasicTestLoad : public CBasicTestMemOrderScope<HostAtomicType, HostDataTy
public: public:
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::OldValueCheck; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::OldValueCheck;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrder; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrder;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryScope;
using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrderScopeStr; using CBasicTestMemOrderScope<HostAtomicType, HostDataType>::MemoryOrderScopeStr;
using CBasicTest<HostAtomicType, HostDataType>::CheckCapabilities;
CBasicTestLoad(TExplicitAtomicType dataType, bool useSVM) : CBasicTestMemOrderScope<HostAtomicType, HostDataType>(dataType, useSVM) CBasicTestLoad(TExplicitAtomicType dataType, bool useSVM) : CBasicTestMemOrderScope<HostAtomicType, HostDataType>(dataType, useSVM)
{ {
OldValueCheck(false); OldValueCheck(false);
@@ -212,6 +220,10 @@ public:
if(MemoryOrder() == MEMORY_ORDER_RELEASE || if(MemoryOrder() == MEMORY_ORDER_RELEASE ||
MemoryOrder() == MEMORY_ORDER_ACQ_REL) MemoryOrder() == MEMORY_ORDER_ACQ_REL)
return 0; //skip test - not applicable return 0; //skip test - not applicable
if (CheckCapabilities(MemoryScope(), MemoryOrder()) == TEST_SKIPPED_ITSELF)
return 0; // skip test - not applicable
return CBasicTestMemOrderScope<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue); return CBasicTestMemOrderScope<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue);
} }
virtual std::string ProgramCore() virtual std::string ProgramCore()
@@ -435,9 +447,11 @@ public:
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryOrder; using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryOrder;
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryOrder2; using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryOrder2;
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryOrderScope; using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryOrderScope;
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::MemoryScope;
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::DataType; using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::DataType;
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::Iterations; using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::Iterations;
using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::IterationsStr; using CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::IterationsStr;
using CBasicTest<HostAtomicType, HostDataType>::CheckCapabilities;
CBasicTestCompareStrong(TExplicitAtomicType dataType, bool useSVM) : CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>(dataType, useSVM) CBasicTestCompareStrong(TExplicitAtomicType dataType, bool useSVM) : CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>(dataType, useSVM)
{ {
StartValue(123456); StartValue(123456);
@@ -451,6 +465,13 @@ public:
if((MemoryOrder() == MEMORY_ORDER_RELAXED && MemoryOrder2() != MEMORY_ORDER_RELAXED) || if((MemoryOrder() == MEMORY_ORDER_RELAXED && MemoryOrder2() != MEMORY_ORDER_RELAXED) ||
(MemoryOrder() != MEMORY_ORDER_SEQ_CST && MemoryOrder2() == MEMORY_ORDER_SEQ_CST)) (MemoryOrder() != MEMORY_ORDER_SEQ_CST && MemoryOrder2() == MEMORY_ORDER_SEQ_CST))
return 0; // failure argument shall be no stronger than the success return 0; // failure argument shall be no stronger than the success
if (CheckCapabilities(MemoryScope(), MemoryOrder()) == TEST_SKIPPED_ITSELF)
return 0; // skip test - not applicable
if (CheckCapabilities(MemoryScope(), MemoryOrder2()) == TEST_SKIPPED_ITSELF)
return 0; // skip test - not applicable
return CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue); return CBasicTestMemOrder2Scope<HostAtomicType, HostDataType>::ExecuteSingleTest(deviceID, context, queue);
} }
virtual std::string ProgramCore() virtual std::string ProgramCore()