#include "common.h"
const char *byte_manipulation_kernels[] = {
"__kernel void write_owned_locations(__global char* a, uint num_id, uint id)\n"
"{\n"
" size_t i = get_global_id(0);\n"
" int owner = i % num_id;\n"
" if(id == owner) \n"
" a[i] = id;\n"
"}\n"
"__kernel void sum_neighbor_locations(__global char* a, uint num_devices, volatile __global uint* error_count)\n"
"{\n"
" size_t i = get_global_id(0);\n"
" uint expected_sum = (num_devices * (num_devices - 1))/2;\n"
" uint sum = 0;\n"
" for(uint j=0; j<num_devices; j++) {\n"
" sum += a[i + j];\n"
" }\n"
" if(sum != expected_sum)\n"
" atomic_inc(error_count);\n"
"}\n"
};
int test_svm_byte_granularity(cl_device_id deviceID, cl_context c, cl_command_queue queue, int num_elements)
{
clContextWrapper context;
clProgramWrapper program;
clKernelWrapper k1,k2;
clCommandQueueWrapper queues[MAXQ];
cl_uint num_devices = 0;
cl_int err = CL_SUCCESS;
cl_int rval = CL_SUCCESS;
err = create_cl_objects(deviceID, &byte_manipulation_kernels[0], &context, &program, &queues[0], &num_devices, CL_DEVICE_SVM_FINE_GRAIN_BUFFER);
if(err == 1) return 0;
if(err < 0) return -1;
cl_uint num_devices_plus_host = num_devices + 1;
k1 = clCreateKernel(program, "write_owned_locations", &err);
test_error(err, "clCreateKernel failed");
k2 = clCreateKernel(program, "sum_neighbor_locations", &err);
test_error(err, "clCreateKernel failed");
cl_char *pA = (cl_char*) clSVMAlloc(context, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, sizeof(cl_char) * num_elements, 0);
cl_uint **error_counts = (cl_uint**) malloc(sizeof(void*) * num_devices);
for(cl_uint i=0; i < num_devices; i++) {
error_counts[i] = (cl_uint*) clSVMAlloc(context, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, sizeof(cl_uint), 0);
*error_counts[i] = 0;
}
for(int i=0; i < num_elements; i++) pA[i] = -1;
err |= clSetKernelArgSVMPointer(k1, 0, pA);
err |= clSetKernelArg(k1, 1, sizeof(cl_uint), &num_devices_plus_host);
test_error(err, "clSetKernelArg failed");
size_t element_num = num_elements;
for(cl_uint d=0; d < num_devices; d++)
{
err = clSetKernelArg(k1, 2, sizeof(cl_uint), &d);
test_error(err, "clSetKernelArg failed");
err = clEnqueueNDRangeKernel(queues[d], k1, 1, NULL, &element_num, NULL, 0, NULL, NULL);
test_error(err,"clEnqueueNDRangeKernel failed");
}
for(cl_uint d=0; d < num_devices; d++) clFlush(queues[d]);
cl_uint host_id = num_devices;
for(int i = (int)num_devices; i < num_elements; i+= num_devices_plus_host) pA[i] = host_id;
for(cl_uint id = 0; id < num_devices; id++) clFinish(queues[id]);
err |= clSetKernelArgSVMPointer(k2, 0, pA);
err |= clSetKernelArg(k2, 1, sizeof(cl_uint), &num_devices_plus_host);
test_error(err, "clSetKernelArg failed");
size_t adjusted_num_elements = num_elements - num_devices;
for(cl_uint id = 0; id < num_devices; id++)
{
err = clSetKernelArgSVMPointer(k2, 2, error_counts[id]);
test_error(err, "clSetKernelArg failed");
err = clEnqueueNDRangeKernel(queues[id], k2, 1, NULL, &adjusted_num_elements, NULL, 0, NULL, NULL);
test_error(err,"clEnqueueNDRangeKernel failed");
}
for(cl_uint id = 0; id < num_devices; id++) clFinish(queues[id]);
bool failed = false;
for(cl_uint i=0; i < num_devices; i++) {
if(*error_counts[i] > 0)
failed = true;
}
cl_uint expected = (num_devices_plus_host * (num_devices_plus_host - 1))/2;
for(cl_uint i = 0; i < num_elements - num_devices_plus_host; i++)
{
int sum = 0;
for(cl_uint j=0; j < num_devices_plus_host; j++) sum += pA[i+j];
if(sum != expected)
failed = true;
}
clSVMFree(context, pA);
for(cl_uint i=0; i < num_devices; i++) clSVMFree(context, error_counts[i]);
if(failed)
return -1;
return 0;
}