// // 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 "testBase.h" #include "../../test_common/harness/typeWrappers.h" #include "../../test_common/harness/testHarness.h" #include "../../test_common/harness/conversions.h" const char *test_kernels[] = { "__kernel void kernelA(__global int *dst)\n" "{\n" "\n" " dst[get_global_id(0)]*=3;\n" "\n" "}\n" "__kernel void kernelB(__global int *dst)\n" "{\n" "\n" " dst[get_global_id(0)]++;\n" "\n" "}\n" }; #define TEST_SIZE 512 #define MAX_QUEUES 1000 const char *printPartition(cl_device_partition_property partition) { switch (partition) { case (0): return ""; case (CL_DEVICE_PARTITION_EQUALLY): return "CL_DEVICE_PARTITION_EQUALLY"; case (CL_DEVICE_PARTITION_BY_COUNTS): return "CL_DEVICE_PARTITION_BY_COUNTS"; case (CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN): return "CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN"; default: return ""; } // switch } const char *printAffinity(cl_device_affinity_domain affinity) { switch (affinity) { case (0): return ""; case (CL_DEVICE_AFFINITY_DOMAIN_NUMA): return "CL_DEVICE_AFFINITY_DOMAIN_NUMA"; case (CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE): return "CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE"; case (CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE): return "CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE"; case (CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE): return "CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE"; case (CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE): return "CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE"; case (CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE): return "CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE"; default: return ""; } // switch } int create_single_kernel_helper( cl_context context, cl_program *outProgram, cl_kernel *outKernel, unsigned int numKernelLines, const char **kernelProgram, const char *kernelName, const cl_device_id *parentDevice ) { int error = CL_SUCCESS; /* Create the program object from source */ *outProgram = clCreateProgramWithSource( context, numKernelLines, kernelProgram, NULL, &error ); if( *outProgram == NULL || error != CL_SUCCESS) { print_error( error, "clCreateProgramWithSource failed" ); return error; } /* Compile the program */ int buildProgramFailed = 0; int printedSource = 0; error = clBuildProgram( *outProgram, ((parentDevice == NULL) ? 0 : 1), parentDevice, NULL, NULL, NULL ); if (error != CL_SUCCESS) { unsigned int i; print_error(error, "clBuildProgram failed"); buildProgramFailed = 1; printedSource = 1; log_error( "Original source is: ------------\n" ); for( i = 0; i < numKernelLines; i++ ) log_error( "%s", kernelProgram[ i ] ); } // Verify the build status on all devices cl_uint deviceCount = 0; error = clGetProgramInfo( *outProgram, CL_PROGRAM_NUM_DEVICES, sizeof( deviceCount ), &deviceCount, NULL ); if (error != CL_SUCCESS) { print_error(error, "clGetProgramInfo CL_PROGRAM_NUM_DEVICES failed"); return error; } if (deviceCount == 0) { log_error("No devices found for program.\n"); return -1; } cl_device_id *devices = (cl_device_id*) malloc( deviceCount * sizeof( cl_device_id ) ); if( NULL == devices ) return -1; memset( devices, 0, deviceCount * sizeof( cl_device_id )); error = clGetProgramInfo( *outProgram, CL_PROGRAM_DEVICES, sizeof( cl_device_id ) * deviceCount, devices, NULL ); if (error != CL_SUCCESS) { print_error(error, "clGetProgramInfo CL_PROGRAM_DEVICES failed"); free( devices ); return error; } cl_uint z; for( z = 0; z < deviceCount; z++ ) { char deviceName[4096] = ""; error = clGetDeviceInfo(devices[z], CL_DEVICE_NAME, sizeof( deviceName), deviceName, NULL); if (error != CL_SUCCESS || deviceName[0] == '\0') { log_error("Device \"%d\" failed to return a name\n", z); print_error(error, "clGetDeviceInfo CL_DEVICE_NAME failed"); } cl_build_status buildStatus; error = clGetProgramBuildInfo(*outProgram, devices[z], CL_PROGRAM_BUILD_STATUS, sizeof(buildStatus), &buildStatus, NULL); if (error != CL_SUCCESS) { print_error(error, "clGetProgramBuildInfo CL_PROGRAM_BUILD_STATUS failed"); free( devices ); return error; } if (buildStatus != CL_BUILD_SUCCESS || buildProgramFailed) { char log[10240] = ""; if (buildStatus == CL_BUILD_SUCCESS && buildProgramFailed) log_error("clBuildProgram returned an error, but buildStatus is marked as CL_BUILD_SUCCESS.\n"); char statusString[64] = ""; if (buildStatus == (cl_build_status)CL_BUILD_SUCCESS) sprintf(statusString, "CL_BUILD_SUCCESS"); else if (buildStatus == (cl_build_status)CL_BUILD_NONE) sprintf(statusString, "CL_BUILD_NONE"); else if (buildStatus == (cl_build_status)CL_BUILD_ERROR) sprintf(statusString, "CL_BUILD_ERROR"); else if (buildStatus == (cl_build_status)CL_BUILD_IN_PROGRESS) sprintf(statusString, "CL_BUILD_IN_PROGRESS"); else sprintf(statusString, "UNKNOWN (%d)", buildStatus); if (buildStatus != CL_BUILD_SUCCESS) log_error("Build not successful for device \"%s\", status: %s\n", deviceName, statusString); error = clGetProgramBuildInfo( *outProgram, devices[z], CL_PROGRAM_BUILD_LOG, sizeof(log), log, NULL ); if (error != CL_SUCCESS || log[0]=='\0'){ log_error("Device %d (%s) failed to return a build log\n", z, deviceName); if (error) { print_error(error, "clGetProgramBuildInfo CL_PROGRAM_BUILD_LOG failed"); free( devices ); return error; } else { log_error("clGetProgramBuildInfo returned an empty log.\n"); free( devices ); return -1; } } // In this case we've already printed out the code above. if (!printedSource) { unsigned int i; log_error( "Original source is: ------------\n" ); for( i = 0; i < numKernelLines; i++ ) log_error( "%s", kernelProgram[ i ] ); printedSource = 1; } log_error( "Build log for device \"%s\" is: ------------\n", deviceName ); log_error( "%s\n", log ); log_error( "\n----------\n" ); free( devices ); return -1; } } /* And create a kernel from it */ *outKernel = clCreateKernel( *outProgram, kernelName, &error ); if( *outKernel == NULL || error != CL_SUCCESS) { print_error( error, "Unable to create kernel" ); free( devices ); return error; } free( devices ); return 0; } template class AutoDestructArray { public: AutoDestructArray(T* arr) : m_arr(arr) {} ~AutoDestructArray() { if (m_arr) delete [] m_arr; } private: T* m_arr; }; int test_device_set(size_t deviceCount, size_t queueCount, cl_device_id *devices, int num_elements, cl_device_id *parentDevice = NULL) { int error; clContextWrapper context; clProgramWrapper program; clKernelWrapper kernels[2]; clMemWrapper stream; clCommandQueueWrapper queues[MAX_QUEUES]; size_t threads[1], localThreads[1]; int data[TEST_SIZE]; int outputData[TEST_SIZE]; int expectedResults[TEST_SIZE]; int *expectedResultsOneDeviceArray = new int[deviceCount * TEST_SIZE]; int **expectedResultsOneDevice = (int**)alloca(sizeof(int**) * deviceCount); size_t i; AutoDestructArray autoDestruct(expectedResultsOneDeviceArray); for (i=0; i MAX_QUEUES) { log_error("Number of queues (%ld) is greater than the number for which the test was written (%d).", queueCount, MAX_QUEUES); return -1; } log_info("Testing with %ld queues on %ld devices, %ld kernel executions.\n", queueCount, deviceCount, queueCount*num_elements/TEST_SIZE); for (i=0; i