From 3db1a9b3aad15d272807c5ff6162a8b31515380c Mon Sep 17 00:00:00 2001 From: David Avedissian Date: Thu, 17 Sep 2020 09:42:58 +0100 Subject: [PATCH] Ensure that test_preprocessors checks __OPENCL_C_VERSION__ correctly for CL 3.0 contexts. (#938) --- test_common/harness/kernelHelpers.cpp | 125 ++++++++++++------ test_common/harness/kernelHelpers.h | 9 +- test_conformance/basic/test_preprocessors.cpp | 82 +++++------- 3 files changed, 126 insertions(+), 90 deletions(-) diff --git a/test_common/harness/kernelHelpers.cpp b/test_common/harness/kernelHelpers.cpp index bca058c8..f4a50169 100644 --- a/test_common/harness/kernelHelpers.cpp +++ b/test_common/harness/kernelHelpers.cpp @@ -1584,43 +1584,8 @@ int printDeviceHeader( cl_device_id device ) Version get_device_cl_c_version(cl_device_id device) { - // Get the device OpenCL version. auto device_cl_version = get_device_cl_version(device); - // If the device version >= 3.0 it must support the - // CL_DEVICE_OPENCL_C_ALL_VERSIONS query from which we can extract the most - // recent CL C version supported by the device. - if (device_cl_version >= Version{ 3, 0 }) - { - size_t opencl_c_all_versions_size_in_bytes{}; - auto error = - clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, 0, nullptr, - &opencl_c_all_versions_size_in_bytes); - test_error_ret( - error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", - (Version{ -1, 0 })); - std::vector name_versions( - opencl_c_all_versions_size_in_bytes / sizeof(cl_name_version)); - error = clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, - opencl_c_all_versions_size_in_bytes, - name_versions.data(), nullptr); - test_error_ret( - error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", - (Version{ -1, 0 })); - - Version max_supported_cl_c_version{}; - for (const auto &name_version : name_versions) - { - Version current_version{ CL_VERSION_MAJOR(name_version.version), - CL_VERSION_MINOR(name_version.version) }; - max_supported_cl_c_version = - (current_version > max_supported_cl_c_version) - ? current_version - : max_supported_cl_c_version; - } - return max_supported_cl_c_version; - } - // The second special case is OpenCL-1.0 where CL_DEVICE_OPENCL_C_VERSION // did not exist, but since this is just the first version we can // return 1.0. @@ -1656,6 +1621,47 @@ Version get_device_cl_c_version(cl_device_id device) return Version{ major - '0', minor - '0' }; } +Version get_device_latest_cl_c_version(cl_device_id device) +{ + auto device_cl_version = get_device_cl_version(device); + + // If the device version >= 3.0 it must support the + // CL_DEVICE_OPENCL_C_ALL_VERSIONS query from which we can extract the most + // recent CL C version supported by the device. + if (device_cl_version >= Version{ 3, 0 }) + { + size_t opencl_c_all_versions_size_in_bytes{}; + auto error = + clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, 0, nullptr, + &opencl_c_all_versions_size_in_bytes); + test_error_ret( + error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", + (Version{ -1, 0 })); + std::vector name_versions( + opencl_c_all_versions_size_in_bytes / sizeof(cl_name_version)); + error = clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, + opencl_c_all_versions_size_in_bytes, + name_versions.data(), nullptr); + test_error_ret( + error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", + (Version{ -1, 0 })); + + Version max_supported_cl_c_version{}; + for (const auto &name_version : name_versions) + { + Version current_version{ CL_VERSION_MAJOR(name_version.version), + CL_VERSION_MINOR(name_version.version) }; + max_supported_cl_c_version = + (current_version > max_supported_cl_c_version) + ? current_version + : max_supported_cl_c_version; + } + return max_supported_cl_c_version; + } + + return get_device_cl_c_version(device); +} + Version get_max_OpenCL_C_for_context(cl_context context) { // Get all the devices in the context and find the maximum @@ -1669,10 +1675,11 @@ Version get_max_OpenCL_C_for_context(cl_context context) / sizeof(cl_device_id)); error = clGetContextInfo(context, CL_CONTEXT_DEVICES, devices_size_in_bytes, devices.data(), nullptr); - auto current_version = get_device_cl_c_version(devices[0]); + auto current_version = get_device_latest_cl_c_version(devices[0]); std::for_each(std::next(devices.begin()), devices.end(), [¤t_version](cl_device_id device) { - auto device_version = get_device_cl_c_version(device); + auto device_version = + get_device_latest_cl_c_version(device); // OpenCL 3.0 is not backwards compatible with 2.0. // If we have 3.0 and 2.0 in the same driver we // use 1.2. @@ -1694,6 +1701,50 @@ Version get_max_OpenCL_C_for_context(cl_context context) return current_version; } +bool device_supports_cl_c_version(cl_device_id device, Version version) +{ + auto device_cl_version = get_device_cl_version(device); + + // In general, a device does not support an OpenCL C version if it is <= + // CL_DEVICE_OPENCL_C_VERSION AND it does not appear in the + // CL_DEVICE_OPENCL_C_ALL_VERSIONS query. + + // If the device version >= 3.0 it must support the + // CL_DEVICE_OPENCL_C_ALL_VERSIONS query, and the version of OpenCL C being + // used must appear in the query result if it's <= + // CL_DEVICE_OPENCL_C_VERSION. + if (device_cl_version >= Version{ 3, 0 }) + { + size_t opencl_c_all_versions_size_in_bytes{}; + auto error = + clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, 0, nullptr, + &opencl_c_all_versions_size_in_bytes); + test_error_ret( + error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", + (false)); + std::vector name_versions( + opencl_c_all_versions_size_in_bytes / sizeof(cl_name_version)); + error = clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, + opencl_c_all_versions_size_in_bytes, + name_versions.data(), nullptr); + test_error_ret( + error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", + (false)); + + for (const auto &name_version : name_versions) + { + Version current_version{ CL_VERSION_MAJOR(name_version.version), + CL_VERSION_MINOR(name_version.version) }; + if (current_version == version) + { + return true; + } + } + } + + return version <= get_device_cl_c_version(device); +} + bool poll_until(unsigned timeout_ms, unsigned interval_ms, std::function fn) { diff --git a/test_common/harness/kernelHelpers.h b/test_common/harness/kernelHelpers.h index 7f972070..c5ff5d0d 100644 --- a/test_common/harness/kernelHelpers.h +++ b/test_common/harness/kernelHelpers.h @@ -175,14 +175,21 @@ cl_device_fp_config get_default_rounding_mode( cl_device_id device ); /* Prints out the standard device header for all tests given the device to print for */ extern int printDeviceHeader( cl_device_id device ); +// Execute the CL_DEVICE_OPENCL_C_VERSION query and return the OpenCL C version +// is supported by the device. +Version get_device_cl_c_version(cl_device_id device); + // Gets the latest (potentially non-backward compatible) OpenCL C version // supported by the device. -Version get_device_cl_c_version(cl_device_id device); +Version get_device_latest_cl_c_version(cl_device_id device); // Gets the maximum universally supported OpenCL C version in a context, i.e. // the OpenCL C version supported by all devices in a context. Version get_max_OpenCL_C_for_context(cl_context context); +// Checks whether a particular OpenCL C version is supported by the device. +bool device_supports_cl_c_version(cl_device_id device, Version version); + // Poll fn every interval_ms until timeout_ms or it returns true bool poll_until(unsigned timeout_ms, unsigned interval_ms, std::function fn); diff --git a/test_conformance/basic/test_preprocessors.cpp b/test_conformance/basic/test_preprocessors.cpp index 332f99de..73f75fb0 100644 --- a/test_conformance/basic/test_preprocessors.cpp +++ b/test_conformance/basic/test_preprocessors.cpp @@ -213,33 +213,15 @@ int test_kernel_preprocessor_macros(cl_device_id deviceID, cl_context context, c // The OpenCL version reported by the macro reports the feature level supported by the compiler. Since // this doesn't directly match any property we can query, we just check to see if it's a sane value - char versionBuffer[ 128 ]; - error = clGetDeviceInfo( deviceID, CL_DEVICE_VERSION, sizeof( versionBuffer ), versionBuffer, NULL ); - test_error( error, "Unable to get device's version to validate against" ); - - // We need to parse to get the version number to compare against - char *p1, *p2, *p3; - for( p1 = versionBuffer; ( *p1 != 0 ) && !isdigit( *p1 ); p1++ ) - ; - for( p2 = p1; ( *p2 != 0 ) && ( *p2 != '.' ); p2++ ) - ; - for( p3 = p2; ( *p3 != 0 ) && ( *p3 != ' ' ); p3++ ) - ; - - if( p2 == p3 ) + auto device_cl_version = get_device_cl_version(deviceID); + int device_cl_version_int = device_cl_version.to_int() * 10; + if ((results[2] < 100) || (results[2] > device_cl_version_int)) { - log_error( "ERROR: Unable to verify OpenCL version string (platform string is incorrect format)\n" ); - return -1; - } - *p2 = 0; - *p3 = 0; - int major = atoi( p1 ); - int minor = atoi( p2 + 1 ); - int realVersion = ( major * 100 ) + ( minor * 10 ); - if( ( results[ 2 ] < 100 ) || ( results[ 2 ] > realVersion ) ) - { - log_error( "ERROR: Kernel preprocessor __OPENCL_VERSION__ does not make sense w.r.t. device's version string! " - "(preprocessor states %d, real version is %d (%d.%d))\n", results[ 2 ], realVersion, major, minor ); + log_error("ERROR: Kernel preprocessor __OPENCL_VERSION__ does not make " + "sense w.r.t. device's version string! " + "(preprocessor states %d, CL_DEVICE_VERSION is %d (%s))\n", + results[2], device_cl_version_int, + device_cl_version.to_string().c_str()); return -1; } @@ -250,33 +232,29 @@ int test_kernel_preprocessor_macros(cl_device_id deviceID, cl_context context, c return -1; } - // The OpenCL C version reported by the macro reports the OpenCL C supported by the compiler for this OpenCL device. - char cVersionBuffer[ 128 ]; - error = clGetDeviceInfo( deviceID, CL_DEVICE_OPENCL_C_VERSION, sizeof( cVersionBuffer ), cVersionBuffer, NULL ); - test_error( error, "Unable to get device's OpenCL C version to validate against" ); - - // We need to parse to get the version number to compare against - for( p1 = cVersionBuffer; ( *p1 != 0 ) && !isdigit( *p1 ); p1++ ) - ; - for( p2 = p1; ( *p2 != 0 ) && ( *p2 != '.' ); p2++ ) - ; - for( p3 = p2; ( *p3 != 0 ) && ( *p3 != ' ' ); p3++ ) - ; - - if( p2 == p3 ) + // The OpenCL C version reported by the macro reports the OpenCL C version + // specified to the compiler. We need to see whether it is supported. + int cl_c_major_version = results[3] / 100; + int cl_c_minor_version = (results[3] / 10) % 10; + if ((results[3] < 100) + || (!device_supports_cl_c_version( + deviceID, Version{ cl_c_major_version, cl_c_minor_version }))) { - log_error( "ERROR: Unable to verify OpenCL C version string (platform string is incorrect format)\n" ); - return -1; - } - *p2 = 0; - *p3 = 0; - major = atoi( p1 ); - minor = atoi( p2 + 1 ); - realVersion = ( major * 100 ) + ( minor * 10 ); - if( ( results[ 3 ] < 100 ) || ( results[ 3 ] > realVersion ) ) - { - log_error( "ERROR: Kernel preprocessor __OPENCL_C_VERSION__ does not make sense w.r.t. device's version string! " - "(preprocessor states %d, real version is %d (%d.%d))\n", results[ 2 ], realVersion, major, minor ); + auto device_version = get_device_cl_c_version(deviceID); + log_error( + "ERROR: Kernel preprocessor __OPENCL_C_VERSION__ does not make " + "sense w.r.t. device's version string! " + "(preprocessor states %d, CL_DEVICE_OPENCL_C_VERSION is %d (%s))\n", + results[3], device_version.to_int() * 10, + device_version.to_string().c_str()); + log_error("This means that CL_DEVICE_OPENCL_C_VERSION < " + "__OPENCL_C_VERSION__"); + if (device_cl_version >= Version{ 3, 0 }) + { + log_error(", and __OPENCL_C_VERSION__ does not appear in " + "CL_DEVICE_OPENCL_C_ALL_VERSIONS"); + } + log_error("\n"); return -1; }