4. 内存对象与缓冲区管理
任务说明
本案例在ARM Mali GPU平台上,使用OpenCL C API完成以下闭环:创建设备端缓冲区、主机端写入数据、设备端读取并校验、最后释放资源。目标是通过最小可运行代码,演示OpenCL内存对象从创建到销毁的完整生命周期,并验证主机与设备间的数据传输正确性。
核心实现
// cl_buffer_demo.c
// 编译: gcc -o cl_buffer_demo cl_buffer_demo.c -lOpenCL
// 运行: ./cl_buffer_demo
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <CL/cl.h>
#define ARRAY_SIZE 16
int main(void) {
cl_int err;
cl_platform_id platform;
cl_device_id device;
cl_context context;
cl_command_queue queue;
cl_mem buffer;
cl_event event;
// 1. 获取平台与设备
err = clGetPlatformIDs(1, &platform, NULL);
if (err != CL_SUCCESS) { printf("平台获取失败: %d\n", err); return -1; }
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);
if (err != CL_SUCCESS) { printf("设备获取失败: %d\n", err); return -1; }
// 2. 创建上下文与命令队列
context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
if (err != CL_SUCCESS) { printf("上下文创建失败: %d\n", err); return -1; }
queue = clCreateCommandQueue(context, device, 0, &err);
if (err != CL_SUCCESS) { printf("命令队列创建失败: %d\n", err); return -1; }
// 3. 创建设备端缓冲区 (16个int, 64字节)
buffer = clCreateBuffer(context, CL_MEM_READ_WRITE,
ARRAY_SIZE * sizeof(int), NULL, &err);
if (err != CL_SUCCESS) { printf("缓冲区创建失败: %d\n", err); return -1; }
// 4. 主机端数据准备
int *host_data = (int*)malloc(ARRAY_SIZE * sizeof(int));
int *read_back = (int*)malloc(ARRAY_SIZE * sizeof(int));
for (int i = 0; i < ARRAY_SIZE; i++) {
host_data[i] = i * 3; // 0, 3, 6, ..., 45
}
// 5. 主机→设备写入 (阻塞模式)
err = clEnqueueWriteBuffer(queue, buffer, CL_TRUE, 0,
ARRAY_SIZE * sizeof(int),
host_data, 0, NULL, &event);
if (err != CL_SUCCESS) { printf("写入失败: %d\n", err); return -1; }
clWaitForEvents(1, &event);
clReleaseEvent(event);
// 6. 设备→主机读取 (阻塞模式)
err = clEnqueueReadBuffer(queue, buffer, CL_TRUE, 0,
ARRAY_SIZE * sizeof(int),
read_back, 0, NULL, &event);
if (err != CL_SUCCESS) { printf("读取失败: %d\n", err); return -1; }
clWaitForEvents(1, &event);
clReleaseEvent(event);
// 7. 校验数据一致性
int match = 1;
for (int i = 0; i < ARRAY_SIZE; i++) {
if (host_data[i] != read_back[i]) {
match = 0;
printf("位置 %d 不匹配: 期望 %d, 实际 %d\n",
i, host_data[i], read_back[i]);
}
}
if (match) {
printf("校验通过: 16个int数据全部一致\n");
} else {
printf("校验失败\n");
}
// 8. 释放资源
free(host_data);
free(read_back);
clReleaseMemObject(buffer);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return 0;
}
关键机制说明
上述代码使用clCreateBuffer在设备端分配64字节连续内存,CL_MEM_READ_WRITE标志允许后续读写操作。数据传输通过clEnqueueWriteBuffer和clEnqueueReadBuffer完成,两个调用均使用CL_TRUE阻塞模式,确保数据到达目的地后才继续执行。事件对象event用于同步,clWaitForEvents保证传输完成后再释放事件。
SVG:缓冲区生命周期与数据流
编译与运行
# 安装OpenCL开发库(若未安装)
sudo apt-get install ocl-icd-opencl-dev
# 编译
gcc -o cl_buffer_demo cl_buffer_demo.c -lOpenCL
# 运行
./cl_buffer_demo
验证方法与判定标准
运行程序后,观察终端输出。若显示校验通过: 16个int数据全部一致,说明缓冲区创建成功、数据经设备端往返后保持完整,任务闭环达成。若输出校验失败或错误码,则需检查设备端内存访问权限或驱动状态。预期输出为:
校验通过: 16个int数据全部一致
该输出由代码中match标志直接决定,当且仅当所有16个元素完全一致时打印此信息。