340 lines
12 KiB
C++
340 lines
12 KiB
C++
//
|
|
// Copyright (c) 2020 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 <iostream>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <algorithm>
|
|
#include "procs.h"
|
|
#include "harness/errorHelpers.h"
|
|
#include "harness/typeWrappers.h"
|
|
#include "harness/parseParameters.h"
|
|
|
|
using KernelAttributes = std::vector<std::string>;
|
|
|
|
static std::string generate_kernel_source(const KernelAttributes& attributes)
|
|
{
|
|
std::string kernel;
|
|
for (auto attribute : attributes)
|
|
{
|
|
kernel += "__attribute__((" + attribute + "))\n";
|
|
}
|
|
kernel += "__kernel void test_kernel(){}";
|
|
return kernel;
|
|
}
|
|
|
|
|
|
using AttributePermutations = std::vector<KernelAttributes>;
|
|
|
|
// The following combinations have been chosen as they place each of the
|
|
// attribute types in the different orders that they can occur. While distinct
|
|
// permutations would provide a complete overview of the API the sheer number of
|
|
// combinations increases the runtime of this test by an unreasonable amount
|
|
AttributePermutations vect_tests;
|
|
AttributePermutations work_tests;
|
|
AttributePermutations reqd_tests;
|
|
|
|
AttributePermutations vect_reqd_tests;
|
|
AttributePermutations work_vect_tests;
|
|
AttributePermutations reqd_work_tests;
|
|
|
|
AttributePermutations vect_work_reqd_tests;
|
|
AttributePermutations work_reqd_vect_tests;
|
|
AttributePermutations reqd_vect_work_tests;
|
|
|
|
|
|
// Generate a vector with vec_type_hint(<data_type>) so that it can be used to
|
|
// generate different kernels
|
|
static KernelAttributes generate_vec_type_hint_data(cl_device_id deviceID)
|
|
{
|
|
KernelAttributes vec_type_hint_data;
|
|
// TODO Test for signed vectors (char/short/int/etc)
|
|
std::vector<std::string> vector_types = { "uchar", "ushort", "uint",
|
|
"float" };
|
|
if (gHasLong)
|
|
{
|
|
vector_types.push_back("ulong");
|
|
}
|
|
if (device_supports_half(deviceID))
|
|
{
|
|
vector_types.push_back("half");
|
|
}
|
|
if (device_supports_double(deviceID))
|
|
{
|
|
vector_types.push_back("double");
|
|
}
|
|
|
|
const auto vector_sizes = { "2", "3", "4", "8", "16" };
|
|
for (auto type : vector_types)
|
|
{
|
|
for (auto size : vector_sizes)
|
|
{
|
|
vec_type_hint_data.push_back("vec_type_hint(" + type + size + ")");
|
|
}
|
|
}
|
|
return vec_type_hint_data;
|
|
}
|
|
|
|
|
|
struct WorkGroupDimensions
|
|
{
|
|
int x;
|
|
int y;
|
|
int z;
|
|
};
|
|
|
|
// Generate vectors to store reqd_work_group_size(<dimensions>) and
|
|
// work_group_size_hint(<dimensions>) so that they can be used to generate
|
|
// different kernels
|
|
static KernelAttributes generate_reqd_work_group_size_data(
|
|
const std::vector<WorkGroupDimensions>& work_group_dimensions)
|
|
{
|
|
KernelAttributes reqd_work_group_size_data;
|
|
for (auto dimension : work_group_dimensions)
|
|
{
|
|
reqd_work_group_size_data.push_back(
|
|
"reqd_work_group_size(" + std::to_string(dimension.x) + ","
|
|
+ std::to_string(dimension.y) + "," + std::to_string(dimension.z)
|
|
+ ")");
|
|
}
|
|
return reqd_work_group_size_data;
|
|
}
|
|
|
|
static KernelAttributes generate_work_group_size_data(
|
|
const std::vector<WorkGroupDimensions>& work_group_dimensions)
|
|
{
|
|
KernelAttributes work_group_size_hint_data;
|
|
for (auto dimension : work_group_dimensions)
|
|
{
|
|
work_group_size_hint_data.push_back(
|
|
"work_group_size_hint(" + std::to_string(dimension.x) + ","
|
|
+ std::to_string(dimension.y) + "," + std::to_string(dimension.z)
|
|
+ ")");
|
|
}
|
|
return work_group_size_hint_data;
|
|
}
|
|
|
|
// Populate the Global Vectors which store individual Kernel Attributes
|
|
static void populate_single_attribute_tests(
|
|
// Vectors to store the different data that fill the attributes
|
|
const KernelAttributes& vec_type_hint_data,
|
|
const KernelAttributes& work_group_size_hint_data,
|
|
const KernelAttributes& reqd_work_group_size_data)
|
|
{
|
|
for (auto vector_test : vec_type_hint_data)
|
|
{
|
|
// Initialise vec_type_hint attribute tests
|
|
vect_tests.push_back({ vector_test });
|
|
}
|
|
for (auto work_group_test : work_group_size_hint_data)
|
|
{
|
|
|
|
// Initialise work_group_size_hint attribute test
|
|
work_tests.push_back({ work_group_test });
|
|
}
|
|
for (auto reqd_work_group_test : reqd_work_group_size_data)
|
|
{
|
|
|
|
// Initialise reqd_work_group_size attribute tests
|
|
reqd_tests.push_back({ reqd_work_group_test });
|
|
}
|
|
}
|
|
|
|
// Populate the Global Vectors which store the different permutations of 2
|
|
// Kernel Attributes
|
|
static void populate_double_attribute_tests(
|
|
const KernelAttributes& vec_type_hint_data,
|
|
const KernelAttributes& work_group_size_hint_data,
|
|
const KernelAttributes& reqd_work_group_size_data)
|
|
{
|
|
for (auto vector_test : vec_type_hint_data)
|
|
{
|
|
for (auto work_group_test : work_group_size_hint_data)
|
|
{
|
|
// Initialise the tests for the permutation of work_group_size_hint
|
|
// combined with vec_type_hint
|
|
work_vect_tests.push_back({ work_group_test, vector_test });
|
|
}
|
|
for (auto reqd_work_group_test : reqd_work_group_size_data)
|
|
{
|
|
// Initialise the tests for the permutation of vec_type_hint and
|
|
// reqd_work_group_size
|
|
vect_reqd_tests.push_back({ vector_test, reqd_work_group_test });
|
|
}
|
|
}
|
|
for (auto work_group_test : work_group_size_hint_data)
|
|
{
|
|
|
|
for (auto reqd_work_group_test : reqd_work_group_size_data)
|
|
{
|
|
// Initialse the tests for the permutation of reqd_work_group_size
|
|
// and work_group_size_hint
|
|
reqd_work_tests.push_back(
|
|
{ reqd_work_group_test, work_group_test });
|
|
}
|
|
}
|
|
}
|
|
|
|
// Populate the Global Vectors which store the different permutations of 3
|
|
// Kernel Attributes
|
|
static void populate_triple_attribute_tests(
|
|
const KernelAttributes& vec_type_hint_data,
|
|
const KernelAttributes& work_group_size_hint_data,
|
|
const KernelAttributes& reqd_work_group_size_data)
|
|
{
|
|
for (auto vector_test : vec_type_hint_data)
|
|
{
|
|
for (auto work_group_test : work_group_size_hint_data)
|
|
{
|
|
for (auto reqd_work_group_test : reqd_work_group_size_data)
|
|
{
|
|
// Initialise the chosen permutations of 3 attributes
|
|
vect_work_reqd_tests.push_back(
|
|
{ vector_test, work_group_test, reqd_work_group_test });
|
|
work_reqd_vect_tests.push_back(
|
|
{ work_group_test, reqd_work_group_test, vector_test });
|
|
reqd_vect_work_tests.push_back(
|
|
{ reqd_work_group_test, vector_test, work_group_test });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static const std::vector<AttributePermutations*>
|
|
generate_attribute_tests(const KernelAttributes& vec_type_hint_data,
|
|
const KernelAttributes& work_group_size_hint_data,
|
|
const KernelAttributes& reqd_work_group_size_data)
|
|
{
|
|
populate_single_attribute_tests(vec_type_hint_data,
|
|
work_group_size_hint_data,
|
|
reqd_work_group_size_data);
|
|
populate_double_attribute_tests(vec_type_hint_data,
|
|
work_group_size_hint_data,
|
|
reqd_work_group_size_data);
|
|
populate_triple_attribute_tests(vec_type_hint_data,
|
|
work_group_size_hint_data,
|
|
reqd_work_group_size_data);
|
|
|
|
// Store all of the filled vectors in a single structure
|
|
const std::vector<AttributePermutations*> all_tests = {
|
|
&vect_tests, &work_tests, &reqd_tests,
|
|
|
|
&work_vect_tests, &vect_reqd_tests, &reqd_work_tests,
|
|
|
|
&vect_work_reqd_tests, &work_reqd_vect_tests, &reqd_vect_work_tests
|
|
};
|
|
return all_tests;
|
|
}
|
|
|
|
static const std::vector<AttributePermutations*>
|
|
initialise_attribute_data(cl_device_id deviceID)
|
|
{
|
|
// This vector stores different work group dimensions that can be used by
|
|
// the reqd_work_group_size and work_group_size_hint attributes. It
|
|
// currently only has a single value to minimise time complexity of the
|
|
// overall test but can be easily changed.
|
|
static const std::vector<WorkGroupDimensions> work_group_dimensions = {
|
|
{ 1, 1, 1 }
|
|
};
|
|
KernelAttributes vec_type_hint_data = generate_vec_type_hint_data(deviceID);
|
|
KernelAttributes work_group_size_hint_data =
|
|
generate_work_group_size_data(work_group_dimensions);
|
|
KernelAttributes reqd_work_group_size_data =
|
|
generate_reqd_work_group_size_data(work_group_dimensions);
|
|
|
|
// Generate all the permutations of attributes to create different test
|
|
// suites
|
|
return generate_attribute_tests(vec_type_hint_data,
|
|
work_group_size_hint_data,
|
|
reqd_work_group_size_data);
|
|
}
|
|
|
|
static bool run_test(cl_context context, cl_device_id deviceID,
|
|
const AttributePermutations& permutations)
|
|
{
|
|
bool success = true;
|
|
for (auto attribute_permutation : permutations)
|
|
{
|
|
|
|
std::string kernel_source_string =
|
|
generate_kernel_source(attribute_permutation);
|
|
const char* kernel_src = kernel_source_string.c_str();
|
|
clProgramWrapper program;
|
|
clKernelWrapper kernel;
|
|
cl_int err = create_single_kernel_helper(context, &program, &kernel, 1,
|
|
&kernel_src, "test_kernel");
|
|
test_error(err, "create_single_kernel_helper");
|
|
|
|
// Get the size of the kernel attribute string returned
|
|
size_t size = 0;
|
|
err = clGetKernelInfo(kernel, CL_KERNEL_ATTRIBUTES, 0, nullptr, &size);
|
|
test_error(err, "clGetKernelInfo");
|
|
std::vector<char> attributes(size);
|
|
err = clGetKernelInfo(kernel, CL_KERNEL_ATTRIBUTES, attributes.size(),
|
|
attributes.data(), nullptr);
|
|
test_error(err, "clGetKernelInfo");
|
|
std::string attribute_string(attributes.data());
|
|
attribute_string.erase(
|
|
std::remove(attribute_string.begin(), attribute_string.end(), ' '),
|
|
attribute_string.end());
|
|
if (gCompilationMode != kOnline)
|
|
{
|
|
if (!attribute_string.empty())
|
|
{
|
|
success = false;
|
|
log_error("Error: Expected an empty string\n");
|
|
log_error("Attribute string reported as: %s\n",
|
|
attribute_string.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool permutation_success = true;
|
|
for (auto attribute : attribute_permutation)
|
|
{
|
|
if (attribute_string.find(attribute) == std::string::npos)
|
|
{
|
|
success = false;
|
|
permutation_success = false;
|
|
log_error("ERROR: did not find expected attribute: '%s'\n",
|
|
attribute.c_str());
|
|
}
|
|
}
|
|
if (!permutation_success)
|
|
{
|
|
log_error("Attribute string reported as: %s\n",
|
|
attribute_string.c_str());
|
|
}
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
int test_kernel_attributes(cl_device_id deviceID, cl_context context,
|
|
cl_command_queue queue, int num_elements)
|
|
{
|
|
bool success = true;
|
|
|
|
// Vector to store all of the tests
|
|
const std::vector<AttributePermutations*> all_tests =
|
|
initialise_attribute_data(deviceID);
|
|
|
|
for (auto permutations : all_tests)
|
|
{
|
|
success = success && run_test(context, deviceID, *permutations);
|
|
}
|
|
return success ? TEST_PASS : TEST_FAIL;
|
|
}
|