// // 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 "harness/os_helpers.h" #include "harness/typeWrappers.h" #include "harness/stringHelpers.h" #include "harness/conversions.h" #include #include #include #include #include #include #include #include #if ! defined( _WIN32) #if defined(__APPLE__) #include #endif #include #define streamDup(fd1) dup(fd1) #define streamDup2(fd1,fd2) dup2(fd1,fd2) #endif #include #include #include "test_printf.h" #if defined(_WIN32) #include #define streamDup(fd1) _dup(fd1) #define streamDup2(fd1,fd2) _dup2(fd1,fd2) #endif #include "harness/testHarness.h" #include "harness/errorHelpers.h" #include "harness/kernelHelpers.h" #include "harness/parseParameters.h" #include "harness/rounding_mode.h" #include typedef unsigned int uint32_t; test_status InitCL( cl_device_id device ); namespace { //----------------------------------------- // helper functions declaration //----------------------------------------- //Stream helper functions //Associate stdout stream with the file(gFileName):i.e redirect stdout stream to the specific files (gFileName) int acquireOutputStream(int* error); //Close the file(gFileName) associated with the stdout stream and disassociates it. void releaseOutputStream(int fd); //Get analysis buffer to verify the correctess of printed data void getAnalysisBuffer(char* analysisBuffer); //Kernel builder helper functions //Check if the test case is for kernel that has argument int isKernelArgument(testCase* pTestCase, size_t testId); //Check if the test case treats %p format for void* int isKernelPFormat(testCase* pTestCase, size_t testId); //----------------------------------------- // Static functions declarations //----------------------------------------- // Make a program that uses printf for the given type/format, cl_program makePrintfProgram(cl_kernel* kernel_ptr, const cl_context context, cl_device_id device, const unsigned int testId, const unsigned int testNum, const unsigned int formatNum); // Creates and execute the printf test for the given device, context, type/format int doTest(cl_command_queue queue, cl_context context, const unsigned int testId, cl_device_id device); // Check if device supports long bool isLongSupported(cl_device_id device_id); // Check if device address space is 64 bits bool is64bAddressSpace(cl_device_id device_id); //Wait until event status is CL_COMPLETE int waitForEvent(cl_event* event); //----------------------------------------- // Definitions and initializations //----------------------------------------- // Tests are broken into the major test which is based on the // src and cmp type and their corresponding vector types and // sub tests which is for each individual test. The following // tracks the subtests int s_test_cnt = 0; int s_test_fail = 0; int s_test_skip = 0; cl_context gContext; cl_command_queue gQueue; int gFd; char gFileName[256]; MTdataHolder gMTdata; // For the sake of proper logging of negative results std::string gLatestKernelSource; //----------------------------------------- // helper functions definition //----------------------------------------- //----------------------------------------- // acquireOutputStream //----------------------------------------- int acquireOutputStream(int* error) { int fd = streamDup(fileno(stdout)); *error = 0; if (!freopen(gFileName, "w", stdout)) { releaseOutputStream(fd); *error = -1; } return fd; } //----------------------------------------- // releaseOutputStream //----------------------------------------- void releaseOutputStream(int fd) { fflush(stdout); streamDup2(fd,fileno(stdout)); close(fd); } //----------------------------------------- // printfCallBack //----------------------------------------- void CL_CALLBACK printfCallBack(const char* printf_data, size_t len, size_t final, void* user_data) { fwrite(printf_data, 1, len, stdout); } //----------------------------------------- // getAnalysisBuffer //----------------------------------------- void getAnalysisBuffer(char* analysisBuffer) { FILE *fp; memset(analysisBuffer,0,ANALYSIS_BUFFER_SIZE); fp = fopen(gFileName, "r"); if (NULL == fp) log_error("Failed to open analysis buffer ('%s')\n", strerror(errno)); else if (0 == std::fread(analysisBuffer, sizeof(analysisBuffer[0]), ANALYSIS_BUFFER_SIZE, fp)) log_error("No data read from analysis buffer\n"); fclose(fp); } //----------------------------------------- // isKernelArgument //----------------------------------------- int isKernelArgument(testCase* pTestCase, size_t testId) { return strcmp(pTestCase->_genParameters[testId].addrSpaceArgumentTypeQualifier,""); } //----------------------------------------- // isKernelPFormat //----------------------------------------- int isKernelPFormat(testCase* pTestCase, size_t testId) { return strcmp(pTestCase->_genParameters[testId].addrSpacePAdd,""); } //----------------------------------------- // waitForEvent //----------------------------------------- int waitForEvent(cl_event* event) { cl_int status = clWaitForEvents(1, event); if(status != CL_SUCCESS) { log_error("clWaitForEvents failed"); return status; } status = clReleaseEvent(*event); if(status != CL_SUCCESS) { log_error("clReleaseEvent failed. (*event)"); return status; } return CL_SUCCESS; } //----------------------------------------- // makeMixedFormatPrintfProgram // Generates in-flight printf kernel with format string including: // -data before conversion flags (randomly generated ascii string) // -randomly generated conversion flags (integer or floating point) // -data after conversion flags (randomly generated ascii string). // Moreover it generates suitable arguments. // example: printf("zH, %u, %a, D+{gy\n", -929240879, 24295.671875f) //----------------------------------------- cl_program makeMixedFormatPrintfProgram(cl_kernel* kernel_ptr, const cl_context context, const cl_device_id device, const unsigned int testId, const unsigned int testNum, const std::string& testname) { auto gen_char = [&]() { static const char dict[] = { " \t!#$&()*+,-./" "123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`" "abcdefghijklmnopqrstuvwxyz{|}~" }; return dict[genrand_int32(gMTdata) % ((int)sizeof(dict) - 1)]; }; std::array, 2> formats = { { { "%f", "%e", "%g", "%a", "%F", "%E", "%G", "%A" }, { "%d", "%i", "%u", "%x", "%o", "%X" } } }; std::vector data_before(2 + genrand_int32(gMTdata) % 8); std::vector data_after(2 + genrand_int32(gMTdata) % 8); std::generate(data_before.begin(), data_before.end(), gen_char); std::generate(data_after.begin(), data_after.end(), gen_char); cl_uint num_args = 2 + genrand_int32(gMTdata) % 4; // Map device rounding to CTS rounding type // get_default_rounding_mode supports RNE and RTZ auto get_rounding = [](const cl_device_fp_config& fpConfig) { if (fpConfig == CL_FP_ROUND_TO_NEAREST) { return kRoundToNearestEven; } else if (fpConfig == CL_FP_ROUND_TO_ZERO) { return kRoundTowardZero; } else { assert(false && "Unreachable"); } return kDefaultRoundingMode; }; const RoundingMode hostRound = get_round(); RoundingMode deviceRound = get_rounding(get_default_rounding_mode(device)); std::ostringstream format_str; std::ostringstream ref_str; std::ostringstream source_gen; std::ostringstream args_str; source_gen << "__kernel void " << testname << "(void)\n" "{\n" " printf(\""; for (auto it : data_before) { format_str << it; ref_str << it; } format_str << ", "; ref_str << ", "; for (cl_uint i = 0; i < num_args; i++) { std::uint8_t is_int = genrand_int32(gMTdata) % 2; // Set CPU rounding mode to match that of the device set_round(deviceRound, is_int != 0 ? kint : kfloat); std::string format = formats[is_int][genrand_int32(gMTdata) % formats[is_int].size()]; format_str << format << ", "; if (is_int) { int arg = genrand_int32(gMTdata); args_str << str_sprintf("%d", arg) << ", "; ref_str << str_sprintf(format, arg) << ", "; } else { const float max_range = 100000.f; float arg = get_random_float(-max_range, max_range, gMTdata); args_str << str_sprintf("%f", arg) << "f, "; ref_str << str_sprintf(format, arg) << ", "; } } // Restore the original CPU rounding mode set_round(hostRound, kfloat); for (auto it : data_after) { format_str << it; ref_str << it; } { std::ostringstream args_cpy; args_cpy << args_str.str(); args_cpy.seekp(-2, std::ios_base::end); args_cpy << ")\n"; log_info("%d) testing printf(\"%s\\n\", %s", testNum, format_str.str().c_str(), args_cpy.str().c_str()); } args_str.seekp(-2, std::ios_base::end); args_str << ");\n}\n"; source_gen << format_str.str() << "\\n\"" << ", " << args_str.str(); std::string kernel_source = source_gen.str(); const char* ptr = kernel_source.c_str(); cl_program program; cl_int err = create_single_kernel_helper(context, &program, kernel_ptr, 1, &ptr, testname.c_str()); gLatestKernelSource = kernel_source.c_str(); // Save the reference result allTestCase[testId]->_correctBuffer.push_back(ref_str.str()); if (!program || err) { log_error("create_single_kernel_helper failed\n"); return NULL; } return program; } //----------------------------------------- // makePrintfProgram //----------------------------------------- cl_program makePrintfProgram(cl_kernel* kernel_ptr, const cl_context context, const cl_device_id device, const unsigned int testId, const unsigned int testNum, const unsigned int formatNum) { int err; cl_program program; char testname[256] = {0}; char addrSpaceArgument[256] = {0}; char addrSpacePAddArgument[256] = {0}; char extension[128] = { 0 }; //Update testname std::snprintf(testname, sizeof(testname), "%s%d", "test", testId); if (allTestCase[testId]->_type == TYPE_HALF || allTestCase[testId]->_type == TYPE_HALF_LIMITS) strcpy(extension, "#pragma OPENCL EXTENSION cl_khr_fp16 : enable\n"); //Update addrSpaceArgument and addrSpacePAddArgument types, based on FULL_PROFILE/EMBEDDED_PROFILE if(allTestCase[testId]->_type == TYPE_ADDRESS_SPACE) { std::snprintf(addrSpaceArgument, sizeof(addrSpaceArgument), "%s", allTestCase[testId] ->_genParameters[testNum] .addrSpaceArgumentTypeQualifier); std::snprintf( addrSpacePAddArgument, sizeof(addrSpacePAddArgument), "%s", allTestCase[testId]->_genParameters[testNum].addrSpacePAdd); } if (strlen(addrSpaceArgument) == 0) std::snprintf(addrSpaceArgument, sizeof(addrSpaceArgument), "void"); // create program based on its type if(allTestCase[testId]->_type == TYPE_VECTOR) { if (strcmp(allTestCase[testId]->_genParameters[testNum].dataType, "half") == 0) strcpy(extension, "#pragma OPENCL EXTENSION cl_khr_fp16 : enable\n"); // Program Source code for vector const char* sourceVec[] = { extension, "__kernel void ", testname, "(void)\n", "{\n", allTestCase[testId]->_genParameters[testNum].dataType, allTestCase[testId]->_genParameters[testNum].vectorSize, " tmp = (", allTestCase[testId]->_genParameters[testNum].dataType, allTestCase[testId]->_genParameters[testNum].vectorSize, ")", allTestCase[testId]->_genParameters[testNum].dataRepresentation, ";", " printf(\"", allTestCase[testId]->_genParameters[testNum].vectorFormatFlag, "v", allTestCase[testId]->_genParameters[testNum].vectorSize, allTestCase[testId]->_genParameters[testNum].vectorFormatSpecifier, "\\n\",", "tmp);", "}\n" }; err = create_single_kernel_helper( context, &program, kernel_ptr, sizeof(sourceVec) / sizeof(sourceVec[0]), sourceVec, testname); gLatestKernelSource = concat_kernel(sourceVec, sizeof(sourceVec) / sizeof(sourceVec[0])); } else if(allTestCase[testId]->_type == TYPE_ADDRESS_SPACE) { // Program Source code for address space const char* sourceAddrSpace[] = { "__kernel void ", testname, "(", addrSpaceArgument, ")\n{\n", allTestCase[testId] ->_genParameters[testNum] .addrSpaceVariableTypeQualifier, "printf(", allTestCase[testId] ->_genParameters[testNum] .genericFormats[formatNum] .c_str(), ",", allTestCase[testId]->_genParameters[testNum].addrSpaceParameter, "); ", addrSpacePAddArgument, "\n}\n" }; err = create_single_kernel_helper(context, &program, kernel_ptr, sizeof(sourceAddrSpace) / sizeof(sourceAddrSpace[0]), sourceAddrSpace, testname); gLatestKernelSource = concat_kernel(sourceAddrSpace, sizeof(sourceAddrSpace) / sizeof(sourceAddrSpace[0])); } else if (allTestCase[testId]->_type == TYPE_MIXED_FORMAT_RANDOM) { return makeMixedFormatPrintfProgram(kernel_ptr, context, device, testId, testNum, testname); } else { // Program Source code for int,float,octal,hexadecimal,char,string std::ostringstream sourceGen; sourceGen << extension << "__kernel void " << testname << "(void)\n" "{\n" " printf(\"" << allTestCase[testId] ->_genParameters[testNum] .genericFormats[formatNum] .c_str() << "\\n\""; if (allTestCase[testId]->_genParameters[testNum].dataRepresentation) { sourceGen << "," << allTestCase[testId] ->_genParameters[testNum] .dataRepresentation; } sourceGen << ");\n}\n"; std::string kernel_source = sourceGen.str(); const char* ptr = kernel_source.c_str(); err = create_single_kernel_helper(context, &program, kernel_ptr, 1, &ptr, testname); gLatestKernelSource = kernel_source.c_str(); } if (!program || err) { log_error("create_single_kernel_helper failed\n"); return NULL; } return program; } //----------------------------------------- // isLongSupported //----------------------------------------- bool isLongSupported(cl_device_id device_id) { size_t tempSize = 0; cl_int status; bool extSupport = true; // Device profile status = clGetDeviceInfo( device_id, CL_DEVICE_PROFILE, 0, NULL, &tempSize); if(status != CL_SUCCESS) { log_error("*** clGetDeviceInfo FAILED ***\n\n"); return false; } std::unique_ptr profileType(new char[tempSize]); if(profileType == NULL) { log_error("Failed to allocate memory(profileType)"); return false; } status = clGetDeviceInfo( device_id, CL_DEVICE_PROFILE, sizeof(char) * tempSize, profileType.get(), NULL); if(!strcmp("EMBEDDED_PROFILE",profileType.get())) { extSupport = is_extension_available(device_id, "cles_khr_int64"); } return extSupport; } //----------------------------------------- // is64bAddressSpace //----------------------------------------- bool is64bAddressSpace(cl_device_id device_id) { cl_int status; cl_uint addrSpaceB; // Device profile status = clGetDeviceInfo( device_id, CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint), &addrSpaceB, NULL); if(status != CL_SUCCESS) { log_error("*** clGetDeviceInfo FAILED ***\n\n"); return false; } if(addrSpaceB == 64) return true; else return false; } //----------------------------------------- // subtest_fail //----------------------------------------- void subtest_fail(const char* msg, ...) { if (msg) { va_list argptr; va_start(argptr, msg); vfprintf(stderr, msg, argptr); va_end(argptr); } ++s_test_fail; ++s_test_cnt; } //----------------------------------------- // logTestType - printout test details //----------------------------------------- void logTestType(const unsigned testId, const unsigned testNum, unsigned formatNum) { if (allTestCase[testId]->_type == TYPE_VECTOR) { log_info( "%d)testing printf(\"%sv%s%s\",%s)\n", testNum, allTestCase[testId]->_genParameters[testNum].vectorFormatFlag, allTestCase[testId]->_genParameters[testNum].vectorSize, allTestCase[testId]->_genParameters[testNum].vectorFormatSpecifier, allTestCase[testId]->_genParameters[testNum].dataRepresentation); } else if (allTestCase[testId]->_type == TYPE_ADDRESS_SPACE) { if (isKernelArgument(allTestCase[testId], testNum)) { log_info("%d)testing kernel //argument %s \n printf(%s,%s)\n", testNum, allTestCase[testId] ->_genParameters[testNum] .addrSpaceArgumentTypeQualifier, allTestCase[testId] ->_genParameters[testNum] .genericFormats[formatNum] .c_str(), allTestCase[testId] ->_genParameters[testNum] .addrSpaceParameter); } else { log_info("%d)testing kernel //variable %s \n printf(%s,%s)\n", testNum, allTestCase[testId] ->_genParameters[testNum] .addrSpaceVariableTypeQualifier, allTestCase[testId] ->_genParameters[testNum] .genericFormats[formatNum] .c_str(), allTestCase[testId] ->_genParameters[testNum] .addrSpaceParameter); } } else if (allTestCase[testId]->_type != TYPE_MIXED_FORMAT_RANDOM) { log_info("%d)testing printf(\"%s\"", testNum, allTestCase[testId] ->_genParameters[testNum] .genericFormats[formatNum] .c_str()); if (allTestCase[testId]->_genParameters[testNum].dataRepresentation) log_info(",%s", allTestCase[testId] ->_genParameters[testNum] .dataRepresentation); log_info(")\n"); } fflush(stdout); } //----------------------------------------- // doTest //----------------------------------------- int doTest(cl_command_queue queue, cl_context context, const unsigned int testId, cl_device_id device) { int err = TEST_FAIL; if ((allTestCase[testId]->_type == TYPE_HALF || allTestCase[testId]->_type == TYPE_HALF_LIMITS) && !is_extension_available(device, "cl_khr_fp16")) { log_info("Skipping half because cl_khr_fp16 extension is not " "supported.\n"); return TEST_SKIPPED_ITSELF; } if ((allTestCase[testId]->_type == TYPE_LONG) && !isLongSupported(device)) { log_info("Skipping long because long is not supported.\n"); return TEST_SKIPPED_ITSELF; } if ((allTestCase[testId]->_type == TYPE_DOUBLE || allTestCase[testId]->_type == TYPE_DOUBLE_LIMITS) && !is_extension_available(device, "cl_khr_fp64")) { log_info("Skipping double because cl_khr_fp64 extension is not " "supported.\n"); return TEST_SKIPPED_ITSELF; } auto& genParams = allTestCase[testId]->_genParameters; auto fail_count = s_test_fail; auto pass_count = s_test_cnt; auto skip_count = s_test_skip; for (unsigned testNum = 0; testNum < genParams.size(); testNum++) { if (allTestCase[testId]->_type == TYPE_VECTOR) { auto is_vector_type_supported = [&](const char* type_name, const char* ext_name) { if ((strcmp(genParams[testNum].dataType, type_name) == 0) && !is_extension_available(device, ext_name)) { log_info("Skipping %s because %s extension " "is not supported.\n", type_name, ext_name); s_test_skip++; s_test_cnt++; return false; } return true; }; if (!is_vector_type_supported("half", "cl_khr_fp16")) continue; if (!is_vector_type_supported("double", "cl_khr_fp64")) continue; // Long support for varible type if (!strcmp(allTestCase[testId]->_genParameters[testNum].dataType, "long") && !isLongSupported(device)) { log_info("Long is not supported, test not run.\n"); s_test_skip++; s_test_cnt++; continue; } } auto genParamsVec = allTestCase[testId]->_genParameters; auto genFormatVec = genParamsVec[testNum].genericFormats; for (unsigned formatNum = 0; formatNum < genFormatVec.size(); formatNum++) { logTestType(testId, testNum, formatNum); clProgramWrapper program; clKernelWrapper kernel; clMemWrapper d_out; clMemWrapper d_a; char _analysisBuffer[ANALYSIS_BUFFER_SIZE]; cl_uint out32 = 0; cl_ulong out64 = 0; int fd = -1; // Define an index space (global work size) of threads for // execution. size_t globalWorkSize[1]; program = makePrintfProgram(&kernel, context, device, testId, testNum, formatNum); if (!program || !kernel) { subtest_fail(nullptr); continue; } // For address space test if there is kernel argument - set it if (allTestCase[testId]->_type == TYPE_ADDRESS_SPACE) { if (isKernelArgument(allTestCase[testId], testNum)) { int a = 2; d_a = clCreateBuffer( context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(int), &a, &err); if (err != CL_SUCCESS || d_a == NULL) { subtest_fail("clCreateBuffer failed\n"); continue; } err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_a); if (err != CL_SUCCESS) { subtest_fail("clSetKernelArg failed\n"); continue; } } // For address space test if %p is tested if (isKernelPFormat(allTestCase[testId], testNum)) { d_out = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_ulong), NULL, &err); if (err != CL_SUCCESS || d_out == NULL) { subtest_fail("clCreateBuffer failed\n"); continue; } err = clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_out); if (err != CL_SUCCESS) { subtest_fail("clSetKernelArg failed\n"); continue; } } } fd = acquireOutputStream(&err); if (err != 0) { subtest_fail("Error while redirection stdout to file"); continue; } globalWorkSize[0] = 1; cl_event ndrEvt; err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, &ndrEvt); if (err != CL_SUCCESS) { releaseOutputStream(fd); subtest_fail("\n clEnqueueNDRangeKernel failed errcode:%d\n", err); continue; } fflush(stdout); err = clFlush(queue); if (err != CL_SUCCESS) { releaseOutputStream(fd); subtest_fail("clFlush failed : %d\n", err); continue; } // Wait until kernel finishes its execution and (thus) the output // printed from the kernel is immediately printed err = waitForEvent(&ndrEvt); releaseOutputStream(fd); if (err != CL_SUCCESS) { subtest_fail("waitforEvent failed : %d\n", err); continue; } fflush(stdout); if (allTestCase[testId]->_type == TYPE_ADDRESS_SPACE && isKernelPFormat(allTestCase[testId], testNum)) { // Read the OpenCL output buffer (d_out) to the host output // array (out) if (!is64bAddressSpace(device)) // 32-bit address space { clEnqueueReadBuffer(queue, d_out, CL_TRUE, 0, sizeof(cl_int), &out32, 0, NULL, NULL); } else // 64-bit address space { clEnqueueReadBuffer(queue, d_out, CL_TRUE, 0, sizeof(cl_ulong), &out64, 0, NULL, NULL); } } // // Get the output printed from the kernel to _analysisBuffer // and verify its correctness getAnalysisBuffer(_analysisBuffer); if (!is64bAddressSpace(device)) // 32-bit address space { if (0 != verifyOutputBuffer(_analysisBuffer, allTestCase[testId], testNum, (cl_ulong)out32)) { subtest_fail( "verifyOutputBuffer failed with kernel: " "\n%s\n expected: %s\n got: %s\n", gLatestKernelSource.c_str(), allTestCase[testId]->_correctBuffer[testNum].c_str(), _analysisBuffer); continue; } } else // 64-bit address space { if (0 != verifyOutputBuffer(_analysisBuffer, allTestCase[testId], testNum, out64)) { subtest_fail( "verifyOutputBuffer failed with kernel: " "\n%s\n expected: %s\n got: %s\n", gLatestKernelSource.c_str(), allTestCase[testId]->_correctBuffer[testNum].c_str(), _analysisBuffer); continue; } } } ++s_test_cnt; } // all subtests skipped ? if (s_test_skip - skip_count == s_test_cnt - pass_count) return TEST_SKIPPED_ITSELF; return s_test_fail - fail_count; } } int test_int(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_INT, deviceID); } int test_long(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_LONG, deviceID); } int test_half(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_HALF, deviceID); } int test_half_limits(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_HALF_LIMITS, deviceID); } int test_float(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_FLOAT, deviceID); } int test_float_limits(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_FLOAT_LIMITS, deviceID); } int test_double(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_DOUBLE, deviceID); } int test_double_limits(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_DOUBLE_LIMITS, deviceID); } int test_octal(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_OCTAL, deviceID); } int test_unsigned(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_UNSIGNED, deviceID); } int test_hexadecimal(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_HEXADEC, deviceID); } int test_char(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_CHAR, deviceID); } int test_string(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_STRING, deviceID); } int test_format_string(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_FORMAT_STRING, deviceID); } int test_vector(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_VECTOR, deviceID); } int test_address_space(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_ADDRESS_SPACE, deviceID); } int test_mixed_format_random(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_MIXED_FORMAT_RANDOM, deviceID); } int test_length_specifier(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { return doTest(gQueue, gContext, TYPE_LENGTH_SPECIFIER, deviceID); } int test_buffer_size(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { size_t printf_buff_size = 0; const size_t printf_buff_size_req = !gIsEmbedded ? (1024 * 1024UL) : 1024UL; const size_t config_size = sizeof(printf_buff_size); cl_int err = CL_SUCCESS; err = clGetDeviceInfo(deviceID, CL_DEVICE_PRINTF_BUFFER_SIZE, config_size, &printf_buff_size, NULL); if (err != CL_SUCCESS) { log_error("Unable to query CL_DEVICE_PRINTF_BUFFER_SIZE"); return TEST_FAIL; } if (printf_buff_size < printf_buff_size_req) { log_error("CL_DEVICE_PRINTF_BUFFER_SIZE does not meet requirements"); return TEST_FAIL; } return TEST_PASS; } test_definition test_list[] = { ADD_TEST(int), ADD_TEST(long), ADD_TEST(half), ADD_TEST(half_limits), ADD_TEST(float), ADD_TEST(float_limits), ADD_TEST(double), ADD_TEST(double_limits), ADD_TEST(octal), ADD_TEST(unsigned), ADD_TEST(hexadecimal), ADD_TEST(char), ADD_TEST(string), ADD_TEST(format_string), ADD_TEST(vector), ADD_TEST(address_space), ADD_TEST(buffer_size), ADD_TEST(mixed_format_random), ADD_TEST(length_specifier), }; const int test_num = ARRAY_SIZE( test_list ); //----------------------------------------- // printUsage //----------------------------------------- static void printUsage(void) { log_info("test_printf: \n"); log_info("\tdefault is to run the full test on the default device\n"); log_info("\n"); for (int i = 0; i < test_num; i++) { log_info("\t%s\n", test_list[i].name); } } //----------------------------------------- // main //----------------------------------------- int main(int argc, const char* argv[]) { argc = parseCustomParam(argc, argv); if (argc == -1) { return -1; } const char ** argList = (const char **)calloc( argc, sizeof( char*) ); if( NULL == argList ) { log_error( "Failed to allocate memory for argList array.\n" ); return 1; } argList[0] = argv[0]; size_t argCount = 1; for (int i=1; i < argc; ++i) { const char *arg = argv[i]; if (arg == NULL) break; if (arg[0] == '-') { arg++; while(*arg != '\0') { switch(*arg) { case 'h': printUsage(); return 0; default: log_error( " <-- unknown flag: %c (0x%2.2x)\n)", *arg, *arg ); printUsage(); return 0; } arg++; } } else { argList[argCount] = arg; argCount++; } } char* pcTempFname = get_temp_filename(); if (pcTempFname != nullptr) { strncpy(gFileName, pcTempFname, sizeof(gFileName)); } free(pcTempFname); if (strlen(gFileName) == 0) { log_error("get_temp_filename failed\n"); return -1; } gMTdata = MTdataHolder(gRandomSeed); int err = runTestHarnessWithCheck( argCount, argList, test_num, test_list, true, 0, InitCL ); if(gQueue) { int error = clFinish(gQueue); if (error) { log_error("clFinish failed: %d\n", error); } } if(clReleaseCommandQueue(gQueue)!=CL_SUCCESS) log_error("clReleaseCommandQueue\n"); if(clReleaseContext(gContext)!= CL_SUCCESS) log_error("clReleaseContext\n"); free(argList); remove(gFileName); return err; } test_status InitCL( cl_device_id device ) { uint32_t device_frequency = 0; uint32_t compute_devices = 0; int err; gFd = acquireOutputStream(&err); if (err != 0) { log_error("Error while redirection stdout to file"); return TEST_FAIL; } size_t config_size = sizeof( device_frequency ); #if MULTITHREAD if( (err = clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, config_size, &compute_devices, NULL )) ) #endif compute_devices = 1; config_size = sizeof(device_frequency); if((err = clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, config_size, &device_frequency, NULL ))) device_frequency = 1; releaseOutputStream(gFd); log_info( "\nCompute Device info:\n" ); log_info( "\tProcessing with %d devices\n", compute_devices ); log_info( "\tDevice Frequency: %d MHz\n", device_frequency ); printDeviceHeader( device ); PrintArch(); auto version = get_device_cl_version(device); auto expected_min_version = Version(1, 2); if (version < expected_min_version) { version_expected_info("Test", "OpenCL", expected_min_version.to_string().c_str(), version.to_string().c_str()); return TEST_SKIP; } gFd = acquireOutputStream(&err); if (err != 0) { log_error("Error while redirection stdout to file"); return TEST_FAIL; } cl_context_properties printf_properties[] = { CL_PRINTF_CALLBACK_ARM, (cl_context_properties)printfCallBack, CL_PRINTF_BUFFERSIZE_ARM, ANALYSIS_BUFFER_SIZE, 0 }; cl_context_properties* props = NULL; if(is_extension_available(device, "cl_arm_printf")) { props = printf_properties; } gContext = clCreateContext(props, 1, &device, notify_callback, NULL, NULL); checkNull(gContext, "clCreateContext"); gQueue = clCreateCommandQueue(gContext, device, 0, NULL); checkNull(gQueue, "clCreateCommandQueue"); releaseOutputStream(gFd); if (is_extension_available(device, "cl_khr_fp16")) { const cl_device_fp_config fpConfigHalf = get_default_rounding_mode(device, CL_DEVICE_HALF_FP_CONFIG); if (fpConfigHalf == CL_FP_ROUND_TO_NEAREST) { half_rounding_mode = CL_HALF_RTE; } else if (fpConfigHalf == CL_FP_ROUND_TO_ZERO) { half_rounding_mode = CL_HALF_RTZ; } else { log_error("Error while acquiring half rounding mode"); } } // Generate reference results generateRef(device); return TEST_PASS; }