mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-19 22:19:02 +00:00
Initial open source release of OpenCL 2.0 CTS.
This commit is contained in:
374
test_conformance/device_execution/nested_blocks.cpp
Normal file
374
test_conformance/device_execution/nested_blocks.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../../test_common/harness/testHarness.h"
|
||||
#include "../../test_common/harness/typeWrappers.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "procs.h"
|
||||
#include "utils.h"
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#ifdef CL_VERSION_2_0
|
||||
|
||||
static int gNestingLevel = 4;
|
||||
extern int gWimpyMode;
|
||||
|
||||
static const char* enqueue_nested_blocks_single[] =
|
||||
{
|
||||
NL, "void block_fn(__global int* res, int level)"
|
||||
NL, "{"
|
||||
NL, " size_t tid = get_global_id(0);"
|
||||
NL, " queue_t def_q = get_default_queue();"
|
||||
NL, " ndrange_t ndrange = ndrange_1D(3);"
|
||||
NL, " if(--level < 0) return;"
|
||||
NL, ""
|
||||
NL, " void (^kernelBlock)(void) = ^{ block_fn(res, level); };"
|
||||
NL, ""
|
||||
NL, " // Only 1 work-item enqueues block"
|
||||
NL, " if(tid == 1)"
|
||||
NL, " {"
|
||||
NL, " res[tid]++;"
|
||||
NL, " int enq_res = enqueue_kernel(def_q, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange, kernelBlock);"
|
||||
NL, " if(enq_res != CLK_SUCCESS) { res[tid] = -1; return; }"
|
||||
NL, " }"
|
||||
NL, "}"
|
||||
NL, ""
|
||||
NL, "kernel void enqueue_nested_blocks_single(__global int* res, int level)"
|
||||
NL, "{"
|
||||
NL, " block_fn(res, level);"
|
||||
NL, "}"
|
||||
NL
|
||||
};
|
||||
|
||||
static const char* enqueue_nested_blocks_some_eq[] =
|
||||
{
|
||||
NL, "void block_fn(int level, __global int* res)"
|
||||
NL, "{"
|
||||
NL, " size_t tid = get_global_id(0);"
|
||||
NL, " queue_t def_q = get_default_queue();"
|
||||
NL, " ndrange_t ndrange = ndrange_1D(10);"
|
||||
NL, " if(--level < 0) return;"
|
||||
NL, ""
|
||||
NL, " void (^kernelBlock)(void) = ^{ block_fn(level, res); };"
|
||||
NL, ""
|
||||
NL, " // Some work-items enqueues nested blocks with the same level"
|
||||
NL, " if(tid < (get_global_size(0) >> 1))"
|
||||
NL, " {"
|
||||
NL, " atomic_inc(&res[tid]);"
|
||||
NL, " int enq_res = enqueue_kernel(def_q, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange, kernelBlock);"
|
||||
NL, " if(enq_res != CLK_SUCCESS) { res[tid] = -1; return; }"
|
||||
NL, " }"
|
||||
NL, "}"
|
||||
NL, ""
|
||||
NL, "kernel void enqueue_nested_blocks_some_eq(__global int* res, int level)"
|
||||
NL, "{"
|
||||
NL, " block_fn(level, res);"
|
||||
NL, "}"
|
||||
NL
|
||||
};
|
||||
|
||||
static const char* enqueue_nested_blocks_some_diff[] =
|
||||
{
|
||||
NL, "void block_fn(int level, __global int* res)"
|
||||
NL, "{"
|
||||
NL, " size_t tid = get_global_id(0);"
|
||||
NL, " queue_t def_q = get_default_queue();"
|
||||
NL, " ndrange_t ndrange = ndrange_1D(10);"
|
||||
NL, " if(--level < 0) return;"
|
||||
NL, ""
|
||||
NL, " void (^kernelBlock)(void) = ^{ block_fn(level, res); };"
|
||||
NL, ""
|
||||
NL, " // Some work-items enqueues nested blocks with different levels"
|
||||
NL, " if(tid % 2)"
|
||||
NL, " {"
|
||||
NL, " atomic_inc(&res[tid]);"
|
||||
NL, " if(level >= tid)"
|
||||
NL, " {"
|
||||
NL, " int enq_res = enqueue_kernel(def_q, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange, kernelBlock);"
|
||||
NL, " if(enq_res != CLK_SUCCESS) { res[tid] = -1; return; }"
|
||||
NL, " }"
|
||||
NL, " }"
|
||||
NL, "}"
|
||||
NL, ""
|
||||
NL, "kernel void enqueue_nested_blocks_some_diff(__global int* res, int level)"
|
||||
NL, "{"
|
||||
NL, " block_fn(level, res);"
|
||||
NL, "}"
|
||||
NL
|
||||
};
|
||||
|
||||
static const char* enqueue_nested_blocks_all_eq[] =
|
||||
{
|
||||
NL, "void block_fn(int level, __global int* res)"
|
||||
NL, "{"
|
||||
NL, " size_t tid = get_global_id(0);"
|
||||
NL, " queue_t def_q = get_default_queue();"
|
||||
NL, " ndrange_t ndrange = ndrange_1D(4);"
|
||||
NL, " if(--level < 0) return;"
|
||||
NL, ""
|
||||
NL, " void (^kernelBlock)(void) = ^{ block_fn(level, res); };"
|
||||
NL, ""
|
||||
NL, " // All work-items enqueues nested blocks with the same level"
|
||||
NL, " atomic_inc(&res[tid]);"
|
||||
NL, " int enq_res = enqueue_kernel(def_q, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange, kernelBlock);"
|
||||
NL, " if(enq_res != CLK_SUCCESS) { res[tid] = -1; return; }"
|
||||
NL, "}"
|
||||
NL, ""
|
||||
NL, "kernel void enqueue_nested_blocks_all_eq(__global int* res, int level)"
|
||||
NL, "{"
|
||||
NL, " block_fn(level, res);"
|
||||
NL, "}"
|
||||
NL
|
||||
};
|
||||
|
||||
static const char* enqueue_nested_blocks_all_diff[] =
|
||||
{
|
||||
NL, "void block_fn(int level, __global int* res)"
|
||||
NL, "{"
|
||||
NL, " size_t tid = get_global_id(0);"
|
||||
NL, " queue_t def_q = get_default_queue();"
|
||||
NL, " ndrange_t ndrange = ndrange_1D(10);"
|
||||
NL, " if(--level < 0) return;"
|
||||
NL, ""
|
||||
NL, " void (^kernelBlock)(void) = ^{ block_fn(level, res); };"
|
||||
NL, ""
|
||||
NL, " // All work-items enqueues nested blocks with different levels"
|
||||
NL, " atomic_inc(&res[tid]);"
|
||||
NL, " if(level >= tid)"
|
||||
NL, " {"
|
||||
NL, " int enq_res = enqueue_kernel(def_q, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange, kernelBlock);"
|
||||
NL, " if(enq_res != CLK_SUCCESS) { res[tid] = -1; return; }"
|
||||
NL, " }"
|
||||
NL, "}"
|
||||
NL, ""
|
||||
NL, "kernel void enqueue_nested_blocks_all_diff(__global int* res, int level)"
|
||||
NL, "{"
|
||||
NL, " block_fn(level, res);"
|
||||
NL, "}"
|
||||
NL
|
||||
};
|
||||
|
||||
static int check_single(cl_int* results, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
int i, fail = -1;
|
||||
const cl_uint tid = 1;
|
||||
|
||||
for(i = 0; i < len; ++i)
|
||||
{
|
||||
if(i != tid && results[i] != 0) { fail = i; break; }
|
||||
if(i == tid && results[i] != nesting_level) { fail = i; break; }
|
||||
}
|
||||
return fail;
|
||||
}
|
||||
|
||||
void generate_reference_some_eq(std::vector<cl_int> &referenceResults, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
size_t globalWorkSize = (nesting_level == gNestingLevel)? len: 10;
|
||||
if(--nesting_level < 0) return;
|
||||
|
||||
for (size_t tid = 0; tid < globalWorkSize; ++tid)
|
||||
{
|
||||
if (tid < (globalWorkSize >> 1))
|
||||
{
|
||||
++referenceResults[tid];
|
||||
generate_reference_some_eq(referenceResults, len, nesting_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_some_eq(cl_int* results, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
int i, fail = -1;
|
||||
std::vector<cl_int> referenceResults(len, 0);
|
||||
generate_reference_some_eq(referenceResults, len, nesting_level);
|
||||
|
||||
for(i = 0; i < len; ++i)
|
||||
{
|
||||
if (results[i] != referenceResults[i]) { fail = i; break; }
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
void generate_reference_some_diff(std::vector<cl_int> &referenceResults, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
size_t globalWorkSize = (nesting_level == gNestingLevel)? len: 10;
|
||||
if(--nesting_level < 0) return;
|
||||
|
||||
for (size_t tid = 0; tid < globalWorkSize; ++tid)
|
||||
{
|
||||
if (tid % 2)
|
||||
{
|
||||
++referenceResults[tid];
|
||||
if (nesting_level >= tid)
|
||||
{
|
||||
generate_reference_some_diff(referenceResults, len, nesting_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_some_diff(cl_int* results, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
int i, fail = -1;
|
||||
std::vector<cl_int> referenceResults(len, 0);
|
||||
generate_reference_some_diff(referenceResults, len, nesting_level);
|
||||
|
||||
for(i = 0; i < len; ++i)
|
||||
{
|
||||
if (results[i] != referenceResults[i]) { fail = i; break; }
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
void generate_reference_all_eq(std::vector<cl_int> &referenceResults, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
size_t globalWorkSize = (nesting_level == gNestingLevel)? len: 4;
|
||||
if(--nesting_level < 0) return;
|
||||
|
||||
for (size_t tid = 0; tid < globalWorkSize; ++tid)
|
||||
{
|
||||
++referenceResults[tid];
|
||||
generate_reference_all_eq(referenceResults, len, nesting_level);
|
||||
}
|
||||
}
|
||||
|
||||
static int check_all_eq(cl_int* results, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
int i, fail = -1;
|
||||
std::vector<cl_int> referenceResults(len, 0);
|
||||
generate_reference_all_eq(referenceResults, len, nesting_level);
|
||||
|
||||
for(i = 0; i < len; ++i)
|
||||
{
|
||||
if (results[i] != referenceResults[i]) { fail = i; break; }
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
void generate_reference_all_diff(std::vector<cl_int> &referenceResults, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
size_t globalWorkSize = (nesting_level == gNestingLevel)? len: 10;
|
||||
if(--nesting_level < 0) return;
|
||||
|
||||
for (size_t tid = 0; tid < globalWorkSize; ++tid)
|
||||
{
|
||||
++referenceResults[tid];
|
||||
if (nesting_level >= tid)
|
||||
{
|
||||
generate_reference_all_diff(referenceResults, len, nesting_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_all_diff(cl_int* results, cl_int len, cl_int nesting_level)
|
||||
{
|
||||
int i, fail = -1;
|
||||
std::vector<cl_int> referenceResults(len, 0);
|
||||
generate_reference_all_diff(referenceResults, len, nesting_level);
|
||||
|
||||
for(i = 0; i < len; ++i)
|
||||
{
|
||||
if (results[i] != referenceResults[i]) { fail = i; break; }
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
static const kernel_src_check sources_nested_blocks[] =
|
||||
{
|
||||
{ KERNEL(enqueue_nested_blocks_single), check_single },
|
||||
{ KERNEL(enqueue_nested_blocks_some_eq), check_some_eq },
|
||||
{ KERNEL(enqueue_nested_blocks_some_diff), check_some_diff },
|
||||
{ KERNEL(enqueue_nested_blocks_all_eq), check_all_eq },
|
||||
{ KERNEL(enqueue_nested_blocks_all_diff), check_all_diff }
|
||||
};
|
||||
|
||||
int test_enqueue_nested_blocks(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
|
||||
{
|
||||
cl_uint i, k;
|
||||
cl_int err_ret, res = 0;
|
||||
clCommandQueueWrapper dev_queue;
|
||||
const size_t MAX_GLOBAL_WORK_SIZE = MAX_GWS / 4;
|
||||
cl_int kernel_results[MAX_GLOBAL_WORK_SIZE] = {0};
|
||||
|
||||
if(gWimpyMode)
|
||||
{
|
||||
gNestingLevel = 2;
|
||||
vlog( "*** WARNING: Testing in Wimpy mode! ***\n" );
|
||||
vlog( "*** Wimpy mode is not sufficient to verify correctness. ***\n" );
|
||||
}
|
||||
|
||||
size_t ret_len;
|
||||
cl_uint max_queues = 1;
|
||||
cl_uint maxQueueSize = 0;
|
||||
err_ret = clGetDeviceInfo(device, CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, sizeof(maxQueueSize), &maxQueueSize, 0);
|
||||
test_error(err_ret, "clGetDeviceInfo(CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE) failed");
|
||||
|
||||
err_ret = clGetDeviceInfo(device, CL_DEVICE_MAX_ON_DEVICE_QUEUES, sizeof(max_queues), &max_queues, &ret_len);
|
||||
test_error(err_ret, "clGetDeviceInfo(CL_DEVICE_MAX_ON_DEVICE_QUEUES) failed");
|
||||
|
||||
cl_queue_properties queue_prop_def[] =
|
||||
{
|
||||
CL_QUEUE_PROPERTIES, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE|CL_QUEUE_ON_DEVICE|CL_QUEUE_ON_DEVICE_DEFAULT,
|
||||
CL_QUEUE_SIZE, maxQueueSize,
|
||||
0
|
||||
};
|
||||
|
||||
dev_queue = clCreateCommandQueueWithProperties(context, device, queue_prop_def, &err_ret);
|
||||
test_error(err_ret, "clCreateCommandQueueWithProperties(CL_QUEUE_DEVICE|CL_QUEUE_DEFAULT) failed");
|
||||
|
||||
kernel_arg args[] =
|
||||
{
|
||||
{ sizeof(cl_int), &gNestingLevel }
|
||||
};
|
||||
|
||||
size_t failCnt = 0;
|
||||
for(k = 0; k < arr_size(sources_nested_blocks); ++k)
|
||||
{
|
||||
if (!gKernelName.empty() && gKernelName != sources_nested_blocks[k].src.kernel_name)
|
||||
continue;
|
||||
|
||||
log_info("Running '%s' kernel (%d of %d) ...\n", sources_nested_blocks[k].src.kernel_name, k + 1, arr_size(sources_nested_blocks));
|
||||
for(i = 0; i < MAX_GLOBAL_WORK_SIZE; ++i) kernel_results[i] = 0;
|
||||
|
||||
err_ret = run_n_kernel_args(context, queue, sources_nested_blocks[k].src.lines, sources_nested_blocks[k].src.num_lines, sources_nested_blocks[k].src.kernel_name, 0, MAX_GLOBAL_WORK_SIZE, kernel_results, sizeof(kernel_results), arr_size(args), args);
|
||||
if(check_error(err_ret, "'%s' kernel execution failed", sources_nested_blocks[k].src.kernel_name)) { res = -1; continue ; }
|
||||
|
||||
//check results
|
||||
int fail = sources_nested_blocks[k].check(kernel_results, MAX_GLOBAL_WORK_SIZE, gNestingLevel);
|
||||
|
||||
if(check_error(err_ret, "'%s' kernel execution failed", sources_nested_blocks[k].src.kernel_name)) { ++failCnt; res = -1; continue; }
|
||||
else if(fail >= 0 && check_error(-1, "'%s' kernel results validation failed: [%d] returned %d expected 0", sources_nested_blocks[k].src.kernel_name, fail, kernel_results[fail])) { ++failCnt; res = -1; continue; }
|
||||
else log_info("'%s' kernel is OK.\n", sources_nested_blocks[k].src.kernel_name);
|
||||
}
|
||||
|
||||
if (failCnt > 0)
|
||||
{
|
||||
log_error("ERROR: %d of %d kernels failed.\n", failCnt, arr_size(sources_nested_blocks));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user