mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-22 07:09:03 +00:00
Initial open source release of OpenCL 2.2 CTS.
This commit is contained in:
12
test_conformance/clcpp/attributes/CMakeLists.txt
Normal file
12
test_conformance/clcpp/attributes/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
set(MODULE_NAME CPP_ATTRIBUTES)
|
||||
|
||||
set(${MODULE_NAME}_SOURCES
|
||||
main.cpp
|
||||
../../../test_common/harness/errorHelpers.c
|
||||
../../../test_common/harness/testHarness.c
|
||||
../../../test_common/harness/kernelHelpers.c
|
||||
../../../test_common/harness/msvc9.c
|
||||
../../../test_common/harness/parseParameters.cpp
|
||||
)
|
||||
|
||||
include(../../CMakeCommon.txt)
|
||||
32
test_conformance/clcpp/attributes/main.cpp
Normal file
32
test_conformance/clcpp/attributes/main.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// 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 "../common.hpp"
|
||||
|
||||
#include "test_ivdep.hpp"
|
||||
#include "test_max_size.hpp"
|
||||
#include "test_required_num_sub_groups.hpp"
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// Get list to all test functions
|
||||
std::vector<basefn> testfn_list = autotest::test_suite::get_test_functions();
|
||||
// Get names of all test functions
|
||||
std::vector<std::string> testfn_names = autotest::test_suite::get_test_names();
|
||||
// Create a vector of pointers to the names test functions
|
||||
std::vector<const char *> testfn_names_c_str = autotest::get_strings_ptrs(testfn_names);
|
||||
return runTestHarness(argc, argv, testfn_list.size(), testfn_list.data(), testfn_names_c_str.data(), false, false, 0);
|
||||
}
|
||||
418
test_conformance/clcpp/attributes/test_ivdep.hpp
Normal file
418
test_conformance/clcpp/attributes/test_ivdep.hpp
Normal file
@@ -0,0 +1,418 @@
|
||||
//
|
||||
// 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 TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_IVDEP_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_IVDEP_HPP
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
// Common for all OpenCL C++ tests
|
||||
#include "../common.hpp"
|
||||
|
||||
|
||||
namespace test_ivdep {
|
||||
|
||||
enum class loop_kind
|
||||
{
|
||||
for_loop,
|
||||
while_loop,
|
||||
do_loop
|
||||
};
|
||||
|
||||
struct test_options
|
||||
{
|
||||
loop_kind loop;
|
||||
int ivdep_length;
|
||||
int offset1;
|
||||
int offset2;
|
||||
int iter_count;
|
||||
bool offset1_param;
|
||||
bool offset2_param;
|
||||
bool iter_count_param;
|
||||
bool cond_in_header;
|
||||
bool init_in_header;
|
||||
bool incr_in_header;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
std::string generate_source(test_options options)
|
||||
{
|
||||
std::string offset1s = options.offset1_param ? "offset1" : std::to_string(options.offset1);
|
||||
std::string offset2s = options.offset2_param ? "offset2" : std::to_string(options.offset2);
|
||||
|
||||
std::string init = "i = 0";
|
||||
std::string cond = std::string("i < ") + (options.iter_count_param ? "iter_count" : std::to_string(options.iter_count));
|
||||
std::string incr = "i += 2";
|
||||
|
||||
std::stringstream s;
|
||||
s << R"(
|
||||
kernel void test(global int *a, global int *b, global int *c, int offset1, int offset2, int iter_count)
|
||||
{
|
||||
int i;
|
||||
)";
|
||||
|
||||
// Loop #1
|
||||
if (!options.init_in_header) s << init << ";" << std::endl;
|
||||
if (options.loop == loop_kind::for_loop)
|
||||
s << "for (" <<
|
||||
(options.init_in_header ? init : "") << ";" <<
|
||||
(options.cond_in_header ? cond : "") << ";" <<
|
||||
(options.incr_in_header ? incr : "") << ")";
|
||||
else if (options.loop == loop_kind::while_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ")";
|
||||
else if (options.loop == loop_kind::do_loop)
|
||||
s << "do";
|
||||
s << "{" << std::endl;
|
||||
if (!options.cond_in_header) s << "if (!(" << cond << ")) break;" << std::endl;
|
||||
s << "a[i + " << offset1s << "] = b[i + " << offset1s << "] * c[i + " << offset1s << "];" << std::endl;
|
||||
if (!options.incr_in_header) s << incr << ";" << std::endl;
|
||||
s << "}" << std::endl;
|
||||
if (options.loop == loop_kind::do_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ");" << std::endl;
|
||||
|
||||
// Loop #2
|
||||
if (!options.init_in_header) s << init << ";" << std::endl;
|
||||
if (options.loop == loop_kind::for_loop)
|
||||
s << "for (" <<
|
||||
(options.init_in_header ? init : "") << ";" <<
|
||||
(options.cond_in_header ? cond : "") << ";" <<
|
||||
(options.incr_in_header ? incr : "") << ")";
|
||||
else if (options.loop == loop_kind::while_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ")";
|
||||
else if (options.loop == loop_kind::do_loop)
|
||||
s << "do";
|
||||
s << "{" << std::endl;
|
||||
if (!options.cond_in_header) s << "if (!(" << cond << ")) break;" << std::endl;
|
||||
s << "a[i + " << offset2s << "] = a[i] + b[i];" << std::endl;
|
||||
if (!options.incr_in_header) s << incr << ";" << std::endl;
|
||||
s << "}" << std::endl;
|
||||
if (options.loop == loop_kind::do_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ");" << std::endl;
|
||||
|
||||
s << "}" << std::endl;
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#else
|
||||
std::string generate_source(test_options options)
|
||||
{
|
||||
std::string offset1s = options.offset1_param ? "offset1" : std::to_string(options.offset1);
|
||||
std::string offset2s = options.offset2_param ? "offset2" : std::to_string(options.offset2);
|
||||
|
||||
std::string init = "i = 0";
|
||||
std::string cond = std::string("i < ") + (options.iter_count_param ? "iter_count" : std::to_string(options.iter_count));
|
||||
std::string incr = "i += 2";
|
||||
|
||||
std::stringstream s;
|
||||
s << R"(
|
||||
#include <opencl_memory>
|
||||
#include <opencl_work_item>
|
||||
|
||||
using namespace cl;
|
||||
)";
|
||||
s << R"(
|
||||
kernel void test(global_ptr<int[]> a, global_ptr<int[]> b, global_ptr<int[]> c, int offset1, int offset2, int iter_count)
|
||||
{
|
||||
int i;
|
||||
)";
|
||||
|
||||
// Loop #1
|
||||
if (!options.init_in_header) s << init << ";" << std::endl;
|
||||
if (options.ivdep_length > 0) s << "[[cl::ivdep]]" << std::endl;
|
||||
if (options.loop == loop_kind::for_loop)
|
||||
s << "for (" <<
|
||||
(options.init_in_header ? init : "") << ";" <<
|
||||
(options.cond_in_header ? cond : "") << ";" <<
|
||||
(options.incr_in_header ? incr : "") << ")";
|
||||
else if (options.loop == loop_kind::while_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ")";
|
||||
else if (options.loop == loop_kind::do_loop)
|
||||
s << "do";
|
||||
s << "{" << std::endl;
|
||||
if (!options.cond_in_header) s << "if (!(" << cond << ")) break;" << std::endl;
|
||||
s << "a[i + " << offset1s << "] = b[i + " << offset1s << "] * c[i + " << offset1s << "];" << std::endl;
|
||||
if (!options.incr_in_header) s << incr << ";" << std::endl;
|
||||
s << "}" << std::endl;
|
||||
if (options.loop == loop_kind::do_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ");" << std::endl;
|
||||
|
||||
// Loop #2
|
||||
if (!options.init_in_header) s << init << ";" << std::endl;
|
||||
if (options.ivdep_length > 0) s << "[[cl::ivdep(" << options.ivdep_length << ")]]" << std::endl;
|
||||
if (options.loop == loop_kind::for_loop)
|
||||
s << "for (" <<
|
||||
(options.init_in_header ? init : "") << ";" <<
|
||||
(options.cond_in_header ? cond : "") << ";" <<
|
||||
(options.incr_in_header ? incr : "") << ")";
|
||||
else if (options.loop == loop_kind::while_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ")";
|
||||
else if (options.loop == loop_kind::do_loop)
|
||||
s << "do";
|
||||
s << "{" << std::endl;
|
||||
if (!options.cond_in_header) s << "if (!(" << cond << ")) break;" << std::endl;
|
||||
s << "a[i + " << offset2s << "] = a[i] + b[i];" << std::endl;
|
||||
if (!options.incr_in_header) s << incr << ";" << std::endl;
|
||||
s << "}" << std::endl;
|
||||
if (options.loop == loop_kind::do_loop)
|
||||
s << "while (" << (options.cond_in_header ? cond : "true") << ");" << std::endl;
|
||||
|
||||
s << "}" << std::endl;
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
int test(cl_device_id device, cl_context context, cl_command_queue queue, test_options options)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
cl_program program;
|
||||
cl_kernel kernel;
|
||||
|
||||
std::string kernel_name = "test";
|
||||
std::string source = generate_source(options);
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Only OpenCL C++ to SPIR-V compilation
|
||||
#if defined(DEVELOPMENT) && defined(ONLY_SPIRV_COMPILATION)
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
return error;
|
||||
// Use OpenCL C kernels instead of OpenCL C++ kernels (test C++ host code)
|
||||
#elif defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name, "", false
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
// Normal run
|
||||
#else
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
#endif
|
||||
|
||||
const size_t count = 100;
|
||||
const size_t global_size = 1;
|
||||
|
||||
std::vector<int> a(count);
|
||||
std::vector<int> b(count);
|
||||
std::vector<int> c(count);
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
a[i] = 0;
|
||||
b[i] = i;
|
||||
c[i] = 1;
|
||||
}
|
||||
|
||||
cl_mem a_buffer;
|
||||
a_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
|
||||
sizeof(int) * count, static_cast<void *>(a.data()), &error
|
||||
);
|
||||
RETURN_ON_CL_ERROR(error, "clCreateBuffer")
|
||||
|
||||
cl_mem b_buffer;
|
||||
b_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
|
||||
sizeof(int) * count, static_cast<void *>(b.data()), &error
|
||||
);
|
||||
RETURN_ON_CL_ERROR(error, "clCreateBuffer")
|
||||
|
||||
cl_mem c_buffer;
|
||||
c_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
|
||||
sizeof(int) * count, static_cast<void *>(c.data()),&error
|
||||
);
|
||||
RETURN_ON_CL_ERROR(error, "clCreateBuffer")
|
||||
|
||||
error = clSetKernelArg(kernel, 0, sizeof(cl_mem), &a_buffer);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
error = clSetKernelArg(kernel, 1, sizeof(cl_mem), &b_buffer);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
error = clSetKernelArg(kernel, 2, sizeof(cl_mem), &c_buffer);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
error = clSetKernelArg(kernel, 3, sizeof(cl_int), &options.offset1);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
error = clSetKernelArg(kernel, 4, sizeof(cl_int), &options.offset2);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
error = clSetKernelArg(kernel, 5, sizeof(cl_int), &options.iter_count);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
|
||||
error = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global_size, NULL, 0, NULL, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clEnqueueNDRangeKernel")
|
||||
|
||||
std::vector<int> a_output(count);
|
||||
error = clEnqueueReadBuffer(
|
||||
queue, a_buffer, CL_TRUE,
|
||||
0, sizeof(int) * count,
|
||||
static_cast<void *>(a_output.data()),
|
||||
0, NULL, NULL
|
||||
);
|
||||
RETURN_ON_CL_ERROR(error, "clEnqueueReadBuffer")
|
||||
|
||||
for (int i = 0; i < options.iter_count; i += 2)
|
||||
{
|
||||
a[i + options.offset1] = b[i + options.offset1] * c[i + options.offset1];
|
||||
}
|
||||
|
||||
for (int i = 0; i < options.iter_count; i += 2)
|
||||
{
|
||||
a[i + options.offset2] = a[i] + b[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
const int value = a_output[i];
|
||||
const int expected = a[i];
|
||||
if (value != expected)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1,
|
||||
"Test failed. Element %lu: %d should be: %d",
|
||||
i, value, expected
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clReleaseMemObject(a_buffer);
|
||||
clReleaseMemObject(b_buffer);
|
||||
clReleaseMemObject(c_buffer);
|
||||
clReleaseKernel(kernel);
|
||||
clReleaseProgram(program);
|
||||
return error;
|
||||
}
|
||||
|
||||
const std::vector<std::tuple<int, int, int>> params{
|
||||
std::make_tuple<int, int, int>( -1, 0, 0 ),
|
||||
std::make_tuple<int, int, int>( -1, 3, 4 ),
|
||||
std::make_tuple<int, int, int>( 1, 1, 1 ),
|
||||
std::make_tuple<int, int, int>( 3, 4, 2 ),
|
||||
std::make_tuple<int, int, int>( 3, 4, 3 ),
|
||||
std::make_tuple<int, int, int>( 8, 10, 7 ),
|
||||
std::make_tuple<int, int, int>( 16, 16, 16 )
|
||||
};
|
||||
const std::vector<int> iter_counts{ { 1, 4, 12, 40 } };
|
||||
|
||||
AUTO_TEST_CASE(test_ivdep_for)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
for (auto param : params)
|
||||
for (auto iter_count : iter_counts)
|
||||
for (bool offset1_param : { false, true })
|
||||
for (bool offset2_param : { false, true })
|
||||
for (bool iter_count_param : { false, true })
|
||||
for (bool cond_in_header : { false, true })
|
||||
for (bool init_in_header : { false, true })
|
||||
for (bool incr_in_header : { false, true })
|
||||
{
|
||||
test_options options;
|
||||
options.loop = loop_kind::for_loop;
|
||||
options.ivdep_length = std::get<0>(param);
|
||||
options.offset1 = std::get<1>(param);
|
||||
options.offset2 = std::get<2>(param);
|
||||
options.iter_count = iter_count;
|
||||
options.offset1_param = offset1_param;
|
||||
options.offset2_param = offset2_param;
|
||||
options.iter_count_param = iter_count_param;
|
||||
options.cond_in_header = cond_in_header;
|
||||
options.init_in_header = init_in_header;
|
||||
options.incr_in_header = incr_in_header;
|
||||
|
||||
error = test(device, context, queue, options);
|
||||
RETURN_ON_ERROR(error)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
AUTO_TEST_CASE(test_ivdep_while)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
for (auto param : params)
|
||||
for (auto iter_count : iter_counts)
|
||||
for (bool offset1_param : { false, true })
|
||||
for (bool offset2_param : { false, true })
|
||||
for (bool iter_count_param : { false, true })
|
||||
for (bool cond_in_header : { false, true })
|
||||
{
|
||||
test_options options;
|
||||
options.loop = loop_kind::while_loop;
|
||||
options.ivdep_length = std::get<0>(param);
|
||||
options.offset1 = std::get<1>(param);
|
||||
options.offset2 = std::get<2>(param);
|
||||
options.iter_count = iter_count;
|
||||
options.offset1_param = offset1_param;
|
||||
options.offset2_param = offset2_param;
|
||||
options.iter_count_param = iter_count_param;
|
||||
options.cond_in_header = cond_in_header;
|
||||
options.init_in_header = false;
|
||||
options.incr_in_header = false;
|
||||
|
||||
error = test(device, context, queue, options);
|
||||
RETURN_ON_ERROR(error)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
AUTO_TEST_CASE(test_ivdep_do)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
for (auto param : params)
|
||||
for (auto iter_count : iter_counts)
|
||||
for (bool offset1_param : { false, true })
|
||||
for (bool offset2_param : { false, true })
|
||||
for (bool iter_count_param : { false, true })
|
||||
for (bool cond_in_header : { false, true })
|
||||
{
|
||||
test_options options;
|
||||
options.loop = loop_kind::do_loop;
|
||||
options.ivdep_length = std::get<0>(param);
|
||||
options.offset1 = std::get<1>(param);
|
||||
options.offset2 = std::get<2>(param);
|
||||
options.iter_count = iter_count;
|
||||
options.offset1_param = offset1_param;
|
||||
options.offset2_param = offset2_param;
|
||||
options.iter_count_param = iter_count_param;
|
||||
options.cond_in_header = cond_in_header;
|
||||
options.init_in_header = false;
|
||||
options.incr_in_header = false;
|
||||
|
||||
error = test(device, context, queue, options);
|
||||
RETURN_ON_ERROR(error)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_IVDEP_HPP
|
||||
266
test_conformance/clcpp/attributes/test_max_size.hpp
Normal file
266
test_conformance/clcpp/attributes/test_max_size.hpp
Normal file
@@ -0,0 +1,266 @@
|
||||
//
|
||||
// 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 TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_MAX_SIZE_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_MAX_SIZE_HPP
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Common for all OpenCL C++ tests
|
||||
#include "../common.hpp"
|
||||
|
||||
|
||||
namespace test_max_size {
|
||||
|
||||
enum class address_space
|
||||
{
|
||||
constant,
|
||||
local
|
||||
};
|
||||
|
||||
enum class param_kind
|
||||
{
|
||||
ptr_type, // constant_ptr<T>
|
||||
ptr, // constant<T>*
|
||||
ref // constant<T>&
|
||||
};
|
||||
|
||||
const param_kind param_kinds[] =
|
||||
{
|
||||
param_kind::ptr_type,
|
||||
param_kind::ptr,
|
||||
param_kind::ref
|
||||
};
|
||||
|
||||
struct test_options
|
||||
{
|
||||
address_space space;
|
||||
int max_size;
|
||||
bool spec_const;
|
||||
param_kind kind;
|
||||
bool array;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
std::string generate_source(test_options options)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "kernel void test(";
|
||||
s << (options.space == address_space::constant ? "constant" : "local");
|
||||
s << " int2 *input) { }" << std::endl;
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#else
|
||||
std::string generate_source(test_options options)
|
||||
{
|
||||
std::string type_str = "int2";
|
||||
if (options.array)
|
||||
type_str += "[]";
|
||||
|
||||
std::stringstream s;
|
||||
s << "#include <opencl_memory>" << std::endl;
|
||||
|
||||
if (options.spec_const)
|
||||
{
|
||||
s << "#include <opencl_spec_constant>" << std::endl;
|
||||
s << "cl::spec_constant<int, 1> max_size_spec{ 1234567890 };" << std::endl;
|
||||
}
|
||||
|
||||
s << "kernel void test(";
|
||||
s << "[[cl::max_size(" << (options.spec_const ? "max_size_spec" : std::to_string(options.max_size)) << ")]] ";
|
||||
s << (options.space == address_space::constant ? "cl::constant" : "cl::local");
|
||||
if (options.kind == param_kind::ptr_type)
|
||||
s << "_ptr<" << type_str << ">";
|
||||
else if (options.kind == param_kind::ptr)
|
||||
s << "<" << type_str << ">*";
|
||||
else if (options.kind == param_kind::ref)
|
||||
s << "<" << type_str << ">&";
|
||||
s << " input) { }" << std::endl;
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
int test(cl_device_id device, cl_context context, cl_command_queue queue, test_options options)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
cl_program program;
|
||||
cl_kernel kernel;
|
||||
|
||||
std::string kernel_name = "test";
|
||||
std::string source = generate_source(options);
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Only OpenCL C++ to SPIR-V compilation
|
||||
#if defined(DEVELOPMENT) && defined(ONLY_SPIRV_COMPILATION)
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
return error;
|
||||
// Use OpenCL C kernels instead of OpenCL C++ kernels (test C++ host code)
|
||||
#elif defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name, "", false
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
// Normal run
|
||||
#else
|
||||
const char *source_c_str = source.c_str();
|
||||
error = create_openclcpp_program(context, &program, 1, &source_c_str, "");
|
||||
RETURN_ON_ERROR(error)
|
||||
|
||||
if (options.spec_const)
|
||||
{
|
||||
error = clSetProgramSpecializationConstant(program, 1, sizeof(cl_int), &options.max_size);
|
||||
RETURN_ON_CL_ERROR(error, "clSetProgramSpecializationConstant")
|
||||
}
|
||||
|
||||
error = build_program_create_kernel_helper(
|
||||
context, &program, &kernel, 1, &source_c_str, kernel_name.c_str()
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
#endif
|
||||
|
||||
const int max_size = options.max_size;
|
||||
const int sizes[] = {
|
||||
1,
|
||||
max_size / 2,
|
||||
max_size,
|
||||
max_size + 1,
|
||||
max_size * 2
|
||||
};
|
||||
|
||||
for (int size : sizes)
|
||||
{
|
||||
cl_mem const_buffer;
|
||||
if (options.space == address_space::constant)
|
||||
{
|
||||
const_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY, size, NULL, &error);
|
||||
RETURN_ON_CL_ERROR(error, "clCreateBuffer")
|
||||
|
||||
error = clSetKernelArg(kernel, 0, sizeof(cl_mem), &const_buffer);
|
||||
// Check the status later (depending on size and max_size values)
|
||||
}
|
||||
else if (options.space == address_space::local)
|
||||
{
|
||||
error = clSetKernelArg(kernel, 0, size, NULL);
|
||||
// Check the status later (depending on size and max_size values)
|
||||
}
|
||||
|
||||
if (size <= max_size)
|
||||
{
|
||||
// Correct value, must not fail
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
|
||||
const size_t global_size = 123;
|
||||
error = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global_size, NULL, 0, NULL, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clEnqueueNDRangeKernel")
|
||||
|
||||
error = clFinish(queue);
|
||||
RETURN_ON_CL_ERROR(error, "clFinish")
|
||||
}
|
||||
else
|
||||
{
|
||||
// Incorrect value, must fail
|
||||
if (error != CL_MAX_SIZE_RESTRICTION_EXCEEDED)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1,
|
||||
"clSetKernelArg must fail with CL_MAX_SIZE_RESTRICTION_EXCEEDED,"
|
||||
" but returned %s (%d)", get_cl_error_string(error).c_str(), error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.space == address_space::constant)
|
||||
{
|
||||
error = clReleaseMemObject(const_buffer);
|
||||
RETURN_ON_CL_ERROR(error, "clReleaseMemObject")
|
||||
}
|
||||
}
|
||||
|
||||
clReleaseKernel(kernel);
|
||||
clReleaseProgram(program);
|
||||
return error;
|
||||
}
|
||||
|
||||
AUTO_TEST_CASE(test_max_size_constant)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
cl_ulong max_size;
|
||||
error = clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(max_size), &max_size, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clGetDeviceInfo")
|
||||
|
||||
for (bool spec_const : { false, true })
|
||||
for (auto kind : param_kinds)
|
||||
for (bool array : { false, true })
|
||||
{
|
||||
test_options options;
|
||||
options.space = address_space::constant;
|
||||
options.max_size = max_size / 2;
|
||||
options.spec_const = spec_const;
|
||||
options.kind = kind;
|
||||
options.array = array;
|
||||
|
||||
error = test(device, context, queue, options);
|
||||
RETURN_ON_ERROR(error)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
AUTO_TEST_CASE(test_max_size_local)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
cl_ulong max_size;
|
||||
error = clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(max_size), &max_size, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clGetDeviceInfo")
|
||||
|
||||
for (bool spec_const : { false, true })
|
||||
for (auto kind : param_kinds)
|
||||
for (bool array : { false, true })
|
||||
{
|
||||
test_options options;
|
||||
options.space = address_space::local;
|
||||
options.max_size = max_size / 2;
|
||||
options.spec_const = spec_const;
|
||||
options.kind = kind;
|
||||
options.array = array;
|
||||
|
||||
error = test(device, context, queue, options);
|
||||
RETURN_ON_ERROR(error)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_MAX_SIZE_HPP
|
||||
@@ -0,0 +1,285 @@
|
||||
//
|
||||
// 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 TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_REQUIRED_NUM_SUB_GROUPS_HPP
|
||||
#define TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_REQUIRED_NUM_SUB_GROUPS_HPP
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
|
||||
// Common for all OpenCL C++ tests
|
||||
#include "../common.hpp"
|
||||
|
||||
|
||||
namespace test_required_num_sub_groups {
|
||||
|
||||
struct test_options
|
||||
{
|
||||
size_t num_sub_groups;
|
||||
bool spec_const;
|
||||
size_t max_count;
|
||||
size_t num_tests;
|
||||
};
|
||||
|
||||
struct output_type
|
||||
{
|
||||
cl_ulong num_sub_groups;
|
||||
cl_ulong enqueued_num_sub_groups;
|
||||
};
|
||||
|
||||
const std::string source_common = R"(
|
||||
struct output_type
|
||||
{
|
||||
ulong num_sub_groups;
|
||||
ulong enqueued_num_sub_groups;
|
||||
};
|
||||
)";
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
std::string generate_source(test_options options)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << source_common;
|
||||
s << R"(
|
||||
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
||||
|
||||
kernel void test(global struct output_type *output)
|
||||
{
|
||||
const ulong gid = get_global_linear_id();
|
||||
output[gid].num_sub_groups = get_num_sub_groups();
|
||||
output[gid].enqueued_num_sub_groups = get_enqueued_num_sub_groups();
|
||||
}
|
||||
)";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#else
|
||||
std::string generate_source(test_options options)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << R"(
|
||||
#include <opencl_memory>
|
||||
#include <opencl_work_item>
|
||||
using namespace cl;
|
||||
)";
|
||||
|
||||
if (options.spec_const)
|
||||
{
|
||||
s << "#include <opencl_spec_constant>" << std::endl;
|
||||
s << "cl::spec_constant<uint, 1> num_sub_groups_spec{ 1234567890 };" << std::endl;
|
||||
}
|
||||
|
||||
s << source_common << std::endl;
|
||||
s << "[[cl::required_num_sub_groups(" << (options.spec_const ? "num_sub_groups_spec" : std::to_string(options.num_sub_groups)) << ")]]";
|
||||
s << R"(
|
||||
kernel void test(global_ptr<output_type[]> output)
|
||||
{
|
||||
const ulong gid = get_global_linear_id();
|
||||
output[gid].num_sub_groups = get_num_sub_groups();
|
||||
output[gid].enqueued_num_sub_groups = get_enqueued_num_sub_groups();
|
||||
}
|
||||
)";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
int test(cl_device_id device, cl_context context, cl_command_queue queue, test_options options)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
#if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
if (!is_extension_available(device, "cl_khr_subgroups"))
|
||||
{
|
||||
log_info("SKIPPED: Extension `cl_khr_subgroups` is not supported. Skipping tests.\n");
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
cl_program program;
|
||||
cl_kernel kernel;
|
||||
|
||||
std::string kernel_name = "test";
|
||||
std::string source = generate_source(options);
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Only OpenCL C++ to SPIR-V compilation
|
||||
#if defined(DEVELOPMENT) && defined(ONLY_SPIRV_COMPILATION)
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
return error;
|
||||
// Use OpenCL C kernels instead of OpenCL C++ kernels (test C++ host code)
|
||||
#elif defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
|
||||
error = create_opencl_kernel(
|
||||
context, &program, &kernel,
|
||||
source, kernel_name, "-cl-std=CL2.0", false
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
// Normal run
|
||||
#else
|
||||
const char *source_c_str = source.c_str();
|
||||
error = create_openclcpp_program(context, &program, 1, &source_c_str, "");
|
||||
RETURN_ON_ERROR(error)
|
||||
|
||||
if (options.spec_const)
|
||||
{
|
||||
cl_uint spec_num_sub_groups = static_cast<cl_uint>(options.num_sub_groups);
|
||||
error = clSetProgramSpecializationConstant(program, 1, sizeof(cl_uint), &spec_num_sub_groups);
|
||||
RETURN_ON_CL_ERROR(error, "clSetProgramSpecializationConstant")
|
||||
}
|
||||
|
||||
error = build_program_create_kernel_helper(
|
||||
context, &program, &kernel, 1, &source_c_str, kernel_name.c_str()
|
||||
);
|
||||
RETURN_ON_ERROR(error)
|
||||
#endif
|
||||
|
||||
size_t compile_num_sub_groups;
|
||||
error = clGetKernelSubGroupInfo(kernel, device, CL_KERNEL_COMPILE_NUM_SUB_GROUPS,
|
||||
0, NULL,
|
||||
sizeof(size_t), &compile_num_sub_groups, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clGetKernelSubGroupInfo")
|
||||
if (compile_num_sub_groups != options.num_sub_groups)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1,
|
||||
"CL_KERNEL_COMPILE_NUM_SUB_GROUPS did not return correct value (expected %lu, got %lu)",
|
||||
options.num_sub_groups, compile_num_sub_groups
|
||||
)
|
||||
}
|
||||
|
||||
cl_mem output_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(output_type) * options.max_count, NULL, &error);
|
||||
RETURN_ON_CL_ERROR(error, "clCreateBuffer")
|
||||
|
||||
error = clSetKernelArg(kernel, 0, sizeof(output_buffer), &output_buffer);
|
||||
RETURN_ON_CL_ERROR(error, "clSetKernelArg")
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<size_t> count_dis(1, options.max_count);
|
||||
|
||||
for (size_t test = 0; test < options.num_tests; test++)
|
||||
{
|
||||
for (size_t dim = 1; dim <= 3; dim++)
|
||||
{
|
||||
size_t global_size[3] = { 1, 1, 1 };
|
||||
size_t count = count_dis(gen);
|
||||
std::uniform_int_distribution<size_t> global_size_dis(1, static_cast<size_t>(pow(count, 1.0 / dim)));
|
||||
for (size_t d = 0; d < dim; d++)
|
||||
{
|
||||
global_size[d] = global_size_dis(gen);
|
||||
}
|
||||
count = global_size[0] * global_size[1] * global_size[2];
|
||||
|
||||
size_t local_size[3] = { 1, 1, 1 };
|
||||
error = clGetKernelSubGroupInfo(kernel, device, CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT,
|
||||
sizeof(size_t), &options.num_sub_groups,
|
||||
sizeof(size_t) * dim, local_size, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clGetKernelSubGroupInfo")
|
||||
if (local_size[0] == 0 || local_size[1] != 1 || local_size[2] != 1)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1,
|
||||
"CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT did not return correct value"
|
||||
)
|
||||
}
|
||||
|
||||
size_t sub_group_count_for_ndrange;
|
||||
error = clGetKernelSubGroupInfo(kernel, device, CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE,
|
||||
sizeof(size_t) * dim, local_size,
|
||||
sizeof(size_t), &sub_group_count_for_ndrange, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clGetKernelSubGroupInfo")
|
||||
if (sub_group_count_for_ndrange != options.num_sub_groups)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1,
|
||||
"CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE did not return correct value (expected %lu, got %lu)",
|
||||
options.num_sub_groups, sub_group_count_for_ndrange
|
||||
)
|
||||
}
|
||||
|
||||
const char pattern = 0;
|
||||
error = clEnqueueFillBuffer(queue, output_buffer, &pattern, sizeof(pattern), 0, sizeof(output_type) * count, 0, NULL, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clEnqueueFillBuffer")
|
||||
|
||||
error = clEnqueueNDRangeKernel(queue, kernel, dim, NULL, global_size, local_size, 0, NULL, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clEnqueueNDRangeKernel")
|
||||
|
||||
std::vector<output_type> output(count);
|
||||
error = clEnqueueReadBuffer(
|
||||
queue, output_buffer, CL_TRUE,
|
||||
0, sizeof(output_type) * count,
|
||||
static_cast<void *>(output.data()),
|
||||
0, NULL, NULL
|
||||
);
|
||||
RETURN_ON_CL_ERROR(error, "clEnqueueReadBuffer")
|
||||
|
||||
for (size_t gid = 0; gid < count; gid++)
|
||||
{
|
||||
const output_type &o = output[gid];
|
||||
|
||||
if (o.enqueued_num_sub_groups != options.num_sub_groups)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1, "get_enqueued_num_sub_groups does not equal to required_num_sub_groups")
|
||||
}
|
||||
if (o.num_sub_groups > options.num_sub_groups)
|
||||
{
|
||||
RETURN_ON_ERROR_MSG(-1, "get_num_sub_groups did not return correct value")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clReleaseMemObject(output_buffer);
|
||||
clReleaseKernel(kernel);
|
||||
clReleaseProgram(program);
|
||||
return error;
|
||||
}
|
||||
|
||||
AUTO_TEST_CASE(test_required_num_sub_groups)
|
||||
(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
int error = CL_SUCCESS;
|
||||
|
||||
cl_uint max_num_sub_groups;
|
||||
error = clGetDeviceInfo(device, CL_DEVICE_MAX_NUM_SUB_GROUPS, sizeof(max_num_sub_groups), &max_num_sub_groups, NULL);
|
||||
RETURN_ON_CL_ERROR(error, "clGetDeviceInfo")
|
||||
|
||||
for (bool spec_const : { false, true })
|
||||
for (size_t num_sub_groups = 1; num_sub_groups <= max_num_sub_groups; num_sub_groups++)
|
||||
{
|
||||
test_options options;
|
||||
options.spec_const = spec_const;
|
||||
options.num_sub_groups = num_sub_groups;
|
||||
options.num_tests = 100;
|
||||
options.max_count = num_elements;
|
||||
|
||||
error = test(device, context, queue, options);
|
||||
RETURN_ON_ERROR(error)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // TEST_CONFORMANCE_CLCPP_ATTRIBUTES_TEST_REQUIRED_NUM_SUB_GROUPS_HPP
|
||||
Reference in New Issue
Block a user