1.1 测试框架架构
OpenCL 一致性测试套件(OpenCL-CTS)是由 Khronos Group 维护的官方测试框架,用于验证 OpenCL 实现是否符合规范要求。该框架采用模块化设计,具有以下核心组件:
1.1.1 核心组件架构
OpenCL-CTS/
├── test_conformance/ # 各功能模块测试套件
│ ├── basic/ # 基础功能测试
│ ├── api/ # API 接口测试
│ ├── math_brute_force/ # 数学函数测试
│ └── ... # 其他测试模块
├── test_common/ # 共享测试基础设施
│ ├── harness/ # 测试框架核心
│ ├── gles/ # OpenGL ES 互操作支持
│ └── ...
└── test_runner/ # 测试执行器
1.1.2 测试框架核心类
test_definition 结构体
每个测试用例通过 test_definition 结构定义:
typedef struct test_definition
{
test_function_pointer func; // 测试函数指针
const char *name; // 测试名称
Version min_version; // 最低 OpenCL 版本要求
} test_definition;
test_function_pointer 函数签名
所有测试函数遵循统一接口:
typedef int (*test_function_pointer)(
cl_device_id deviceID, // OpenCL 设备
cl_context context, // OpenCL 上下文
cl_command_queue queue, // 命令队列
int num_elements // 测试元素数量
);
Version 类
用于 OpenCL 版本管理和比较:
class Version {
int m_major; // 主版本号
int m_minor; // 次版本号
// 支持版本比较运算符
bool operator>(const Version &rhs);
bool operator<=(const Version &rhs);
// ...
};
1.1.3 测试注册机制
测试用例通过宏定义注册到测试列表:
// 注册 OpenCL 1.0+ 测试
#define ADD_TEST(fn) { test_##fn, #fn, Version(1, 0) }
// 注册指定版本测试
#define ADD_TEST_VERSION(fn, ver) { test_##fn, #fn, ver }
// 示例:注册测试列表
test_definition test_list[] = {
ADD_TEST(hostptr), // OpenCL 1.0
ADD_TEST(fpmath_float), // OpenCL 1.0
ADD_TEST_VERSION(wg_barrier, Version(2, 0)), // OpenCL 2.0
// ...
};
1.2 测试执行流程
1.2.1 执行流程概览
┌─────────────────┐
│ 解析命令行参数 │
└────────┬────────┘
↓
┌─────────────────┐
│ 初始化 OpenCL │
│ - 平台查询 │
│ - 设备选择 │
│ - 上下文创建 │
└────────┬────────┘
↓
┌─────────────────┐
│ 版本兼容性检查 │
└────────┬────────┘
↓
┌─────────────────┐
│ 执行测试用例 │
│ - 顺序/并行 │
│ - 结果收集 │
└────────┬────────┘
↓
┌─────────────────┐
│ 生成测试报告 │
│ - 统计信息 │
│ - JSON 输出 │
└─────────────────┘
1.2.2 主函数执行逻辑
核心执行函数 runTestHarness 的工作流程:
int runTestHarness(int argc, const char *argv[],
int testNum,
test_definition testList[],
int forceNoContextCreation,
cl_command_queue_properties queueProps)
{
// 1. 解析命令行参数
parseParameters(argc, argv);
// 2. 初始化 OpenCL 环境
cl_platform_id platform;
cl_device_id device;
cl_context context;
cl_command_queue queue;
// 3. 遍历测试列表
for (int i = 0; i < testNum; i++) {
// 版本检查
if (device_version < testList[i].min_version) {
log_info("Test %s skipped (requires %s)\n",
testList[i].name,
testList[i].min_version.to_string());
continue;
}
// 执行测试
int result = testList[i].func(device, context, queue,
num_elements);
// 记录结果
if (result == TEST_PASS) {
gTestsPassed++;
} else if (result == TEST_FAIL) {
gTestsFailed++;
}
}
// 4. 生成报告
saveResultsToJson(suiteName, testList, ...);
return (gTestsFailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
1.2.3 单个测试用例执行流程
典型测试函数的标准结构:
int test_example(cl_device_id device, cl_context context,
cl_command_queue queue, int num_elements)
{
// 1. 创建内核程序
const char *kernel_source = "...";
cl_program program;
cl_kernel kernel;
// 2. 分配内存对象
cl_mem input_buffer = clCreateBuffer(context, ...);
cl_mem output_buffer = clCreateBuffer(context, ...);
// 3. 设置内核参数
clSetKernelArg(kernel, 0, sizeof(cl_mem), &input_buffer);
clSetKernelArg(kernel, 1, sizeof(cl_mem), &output_buffer);
// 4. 执行内核
clEnqueueNDRangeKernel(queue, kernel, ...);
// 5. 读取结果
clEnqueueReadBuffer(queue, output_buffer, ...);
// 6. 验证结果
for (int i = 0; i < num_elements; i++) {
if (output[i] != expected[i]) {
log_error("Mismatch at index %d\n", i);
return TEST_FAIL;
}
}
// 7. 清理资源
clReleaseMemObject(input_buffer);
clReleaseMemObject(output_buffer);
clReleaseKernel(kernel);
clReleaseProgram(program);
return TEST_PASS;
}
1.3 测试结果判定标准
1.3.1 测试状态定义
typedef enum test_status
{
TEST_PASS = 0, // 测试通过
TEST_FAIL = 1, // 测试失败
TEST_SKIP = 2, // 测试跳过
TEST_SKIPPED_ITSELF = -100, // 测试自身选择跳过
} test_status;
1.3.2 判定规则
TEST_PASS(通过)
- 所有功能性验证点均通过
- 数值结果在允许误差范围内(ULP 精度)
- 无内存泄漏或资源泄漏
- API 返回值符合规范要求
TEST_FAIL(失败)
- 功能性错误(结果不正确)
- API 调用返回错误代码
- 精度超出允许范围
- 内存访问越界
- 资源泄漏检测到异常
TEST_SKIP(跳过)
- OpenCL 版本不满足要求
- 设备不支持必需特性(如图像、双精度浮点)
- 扩展功能未启用
- 测试配置不适用当前环境
1.3.3 精度判定标准
浮点运算精度
不同函数类别有不同的 ULP(Unit in the Last Place)误差容忍度:
| 函数类别 | ULP 误差限制 | 示例 |
|---|---|---|
| 基本运算 | ≤ 0.5 ULP | +, -, *, / |
| 数学函数 | ≤ 4 ULP | exp, log, pow |
| 快速数学 | ≤ 8192 ULP | native_, half_ |
| 几何函数 | ≤ 4 ULP | dot, distance |
整数运算精度
- 整数运算要求精确匹配
- 溢出行为需符合规范定义(环绕或饱和)
1.3.4 结果输出格式
终端输出
PASSED 245 of 300 tests.
FAILED 5 of 300 tests.
SKIPPED 50 of 300 tests.
Failed tests:
- test_fpmath_float: ULP error exceeded (got 5.2, expected <= 4.0)
- test_atomic_add: Race condition detected
JSON 输出
通过环境变量 CL_CONFORMANCE_RESULTS_FILENAME 配置:
{
"cmd": "test_basic",
"results": {
"hostptr": "pass",
"fpmath_float": "fail",
"barrier": "skip"
}
}
1.4 测试环境配置与依赖
1.4.1 编译依赖
必需依赖
- CMake 3.7+
- C++14 编译器(GCC 5+, Clang 3.9+, MSVC 2015+)
- OpenCL SDK(头文件和 ICD 加载器)
- Python 3.6+(用于自动化脚本)
可选依赖
- OpenGL/OpenGL ES 开发库(互操作测试)
- Vulkan SDK(Vulkan 互操作测试)
- GLM 数学库
1.4.2 CMake 构建配置
# 基本配置
cmake_minimum_required(VERSION 3.7)
project(OpenCL-CTS)
# 查找 OpenCL
find_package(OpenCL REQUIRED)
# 添加测试套件
add_subdirectory(test_conformance/basic)
add_subdirectory(test_conformance/api)
# ...
# 编译选项
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1.4.3 环境变量配置
| 环境变量 | 说明 | 示例 |
|---|---|---|
CL_CONFORMANCE_RESULTS_FILENAME | JSON 结果输出路径 | results.json |
OCL_ICD_FILENAMES | 手动指定 ICD 文件 | /opt/rocm/lib/libamdocl64.so |
CL_CONFORMANCE_DEVICE | 选择测试设备 | AMD |
CL_CONFORMANCE_NUM_ELEMENTS | 测试数据量 | 0x10000 |
1.4.4 命令行参数
# 运行所有测试
./test_basic
# 运行特定测试
./test_basic hostptr fpmath_float
# 指定设备类型
./test_basic --device cpu
# 详细输出
./test_basic --verbose
# 指定元素数量
./test_basic --num-elements 65536
# 设置随机种子(可重现)
./test_basic --seed 12345
1.4.5 典型构建流程
# 1. 克隆仓库
git clone https://github.com/KhronosGroup/OpenCL-CTS.git
cd OpenCL-CTS
# 2. 创建构建目录
mkdir build && cd build
# 3. 配置
cmake .. \
-DCL_INCLUDE_DIR=/opt/rocm-7.1.0/include \
-DCL_LIB_DIR=/opt/rocm-7.1.0/lib
# 4. 编译
cmake --build . -j$(nproc)
# 5. 运行测试
cd test_conformance/basic
./test_basic
1.4.6 配置 OpenCL ICD
OpenCL ICD(Installable Client Driver)加载机制:
Linux 配置
# 创建 ICD 配置文件
sudo mkdir -p /etc/OpenCL/vendors
sudo bash -c 'echo "/opt/rocm-7.1.0/lib/libamdocl64.so" > /etc/OpenCL/vendors/amdocl64.icd'
# 验证设备可见
clinfo
Windows 配置
注册表路径:
HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenCL\Vendors
添加值:
C:\Program Files\AMD\OpenCL\amdocl64.dll = 0
1.4.7 常见配置问题
问题 1:找不到 OpenCL 设备
# 检查 ICD 加载器
OCL_ICD_ENABLE_TRACE=1 ./test_basic
# 手动指定 ICD 文件
OCL_ICD_FILENAMES=/opt/rocm-7.1.0/lib/libamdocl64.so ./test_basic
问题 2:内存不足
# 减少测试数据量
./test_basic --num-elements 4096
问题 3:测试超时
# 增加超时时间(修改源码或使用环境变量)
export CL_CONFORMANCE_TIMEOUT=300 # 秒
1.4.8 调试配置
启用调试输出
# 编译 Debug 版本
cmake .. -DCMAKE_BUILD_TYPE=Debug
# 启用详细日志
./test_basic --verbose --list-tests
使用 GDB 调试
gdb --args ./test_basic fpmath_float
(gdb) break test_fpmath_float
(gdb) run
内存检查
# 使用 Valgrind 检测内存泄漏
valgrind --leak-check=full ./test_basic hostptr
本章小结
第1章介绍了 OpenCL-CTS 测试框架的核心架构:
- 框架组成:测试定义、执行器、结果收集
- 执行流程:从初始化到结果输出的完整生命周期
- 判定标准:通过/失败/跳过的明确规则
- 环境配置:编译、ICD 配置、调试技巧
理解这些基础概念是深入学习各测试模块的前提。下一章将详细介绍测试工具与脚本的使用方法。
1014

被折叠的 条评论
为什么被折叠?



