当前位置: 首页 > java >正文

OpenCL study - code02

在实际工程开发中,我们经常会遇到性能瓶颈的问题,尤其是在图像处理、信号处理或者机器学习前处理等场景中,海量数据的逐元素计算如果全部由 CPU 承担,效率往往无法满足实时需求。此时,利用 GPU 的并行计算能力就成了提升性能的关键手段。
OpenCL(Open Computing Language)是一个开放的、跨平台的并行计算框架,它支持在多种设备(CPU、GPU、DSP 甚至 FPGA)上运行并行程序。相比 CUDA 只支持 NVIDIA 平台,OpenCL 更加通用,适合在多厂商硬件上开发。
本文通过一个最基础的向量加法示例,介绍如何使用 OpenCL 将计算任务从 CPU 下发到 GPU,并进一步封装通用流程,做到后续只需关注**“算子本身”**的开发,大大提高算子迭代效率。无论你是 OpenCL 新手,还是在做异构计算优化的工程师,这篇文章都能为你提供实用的参考。

// opencl_helper.h
#ifndef OPENCL_HELPER_H
#define OPENCL_HELPER_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <OpenCL/opencl.h>#define CHECK_ERROR(err, msg) \if (err != CL_SUCCESS) { \fprintf(stderr, "%s failed with error %d\n", msg, err); \exit(1); \}typedef struct {cl_platform_id platform;cl_device_id device;cl_context context;cl_command_queue queue;cl_program program;cl_kernel kernel;
} OpenCLObjects;// 加载内核源码
char *read_source(const char *filename) {FILE *fp = fopen(filename, "r");if (!fp) {perror("Failed to open kernel file");exit(1);}fseek(fp, 0, SEEK_END);size_t size = ftell(fp);rewind(fp);char *source = (char *)malloc(size + 1);fread(source, 1, size, fp);source[size] = '\0';fclose(fp);return source;
}// 初始化 OpenCL,并构建 kernel
OpenCLObjects init_opencl(const char *source_file, const char *kernel_name) {OpenCLObjects ocl;cl_int err;err = clGetPlatformIDs(1, &ocl.platform, NULL);CHECK_ERROR(err, "clGetPlatformIDs");err = clGetDeviceIDs(ocl.platform, CL_DEVICE_TYPE_DEFAULT, 1, &ocl.device, NULL);CHECK_ERROR(err, "clGetDeviceIDs");ocl.context = clCreateContext(NULL, 1, &ocl.device, NULL, NULL, &err);CHECK_ERROR(err, "clCreateContext");ocl.queue = clCreateCommandQueue(ocl.context, ocl.device, 0, &err);CHECK_ERROR(err, "clCreateCommandQueue");char *source = read_source(source_file);ocl.program = clCreateProgramWithSource(ocl.context, 1, (const char **)&source, NULL, &err);CHECK_ERROR(err, "clCreateProgramWithSource");err = clBuildProgram(ocl.program, 1, &ocl.device, NULL, NULL, NULL);if (err != CL_SUCCESS) {char log[4096];clGetProgramBuildInfo(ocl.program, ocl.device, CL_PROGRAM_BUILD_LOG, sizeof(log), log, NULL);fprintf(stderr, "Build Error:\n%s\n", log);exit(1);}ocl.kernel = clCreateKernel(ocl.program, kernel_name, &err);CHECK_ERROR(err, "clCreateKernel");free(source);return ocl;
}void release_opencl(OpenCLObjects *ocl) {clReleaseKernel(ocl->kernel);clReleaseProgram(ocl->program);clReleaseCommandQueue(ocl->queue);clReleaseContext(ocl->context);
}#endif
__kernel void vector_add(__global const float* A,__global const float* B,__global float* C) {int id = get_global_id(0);C[id] = A[id] + B[id];
}
// main.cpp
// this code compiles with the following command:
// g++ main.cpp -framework OpenCL -o vector_add#include <stdio.h>
#include <stdlib.h>
#include "opencl_helper.h"#define ARRAY_SIZE 1024int main() {float *A = (float *)malloc(sizeof(float) * ARRAY_SIZE);float *B = (float *)malloc(sizeof(float) * ARRAY_SIZE);float *C = (float *)malloc(sizeof(float) * ARRAY_SIZE);for (int i = 0; i < ARRAY_SIZE; i++) {A[i] = (float)i;B[i] = (float)(i * 2);}// 初始化 OpenCLOpenCLObjects ocl = init_opencl("vector_add.cl", "vector_add");cl_int err;// 创建缓冲区cl_mem bufferA = clCreateBuffer(ocl.context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * ARRAY_SIZE, A, &err);CHECK_ERROR(err, "clCreateBuffer A");cl_mem bufferB = clCreateBuffer(ocl.context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * ARRAY_SIZE, B, &err);CHECK_ERROR(err, "clCreateBuffer B");cl_mem bufferC = clCreateBuffer(ocl.context, CL_MEM_WRITE_ONLY,sizeof(float) * ARRAY_SIZE, NULL, &err);CHECK_ERROR(err, "clCreateBuffer C");// 设置参数clSetKernelArg(ocl.kernel, 0, sizeof(cl_mem), &bufferA);clSetKernelArg(ocl.kernel, 1, sizeof(cl_mem), &bufferB);clSetKernelArg(ocl.kernel, 2, sizeof(cl_mem), &bufferC);size_t global_size = ARRAY_SIZE;err = clEnqueueNDRangeKernel(ocl.queue, ocl.kernel, 1, NULL, &global_size, NULL, 0, NULL, NULL);CHECK_ERROR(err, "clEnqueueNDRangeKernel");clFinish(ocl.queue);// 读取结果err = clEnqueueReadBuffer(ocl.queue, bufferC, CL_TRUE, 0, sizeof(float) * ARRAY_SIZE, C, 0, NULL, NULL);CHECK_ERROR(err, "clEnqueueReadBuffer");for (int i = 0; i < 10; i++) {printf("Result[%d]: %.1f + %.1f = %.1f\n", i, A[i], B[i], C[i]);}// 清理clReleaseMemObject(bufferA);clReleaseMemObject(bufferB);clReleaseMemObject(bufferC);release_opencl(&ocl);free(A);free(B);free(C);return 0;
}
  • 代码结构:
    在这里插入图片描述
  • 编译命令:
g++ main.cpp -framework OpenCL -o vector_add
  • 运行
./vector_add

在这里插入图片描述

http://www.xdnf.cn/news/15154.html

相关文章:

  • docker网络与数据持久化
  • 大数据时代UI前端的智能化服务升级:基于用户情境的主动服务设计
  • Elasticsearch 的 `modules` 目录
  • 使用Matlab整车模型进行电动汽车能耗仿真测试方法
  • 【飞算JavaAI】一站式智能开发,驱动Java开发全流程革新
  • 鸿蒙的NDK开发初级入门篇
  • Apache Iceberg数据湖高级特性及性能调优
  • 如何使用postman做接口测试?
  • 《Spring 中上下文传递的那些事儿》Part 8:构建统一上下文框架设计与实现(实战篇)
  • 安全初级作业1
  • Linux中的git命令
  • 【LeetCode 热题 100】24. 两两交换链表中的节点——(解法一)迭代+哨兵
  • 设计模式 - 面向对象原则:SOLID最佳实践
  • vscode 中的 mermaid
  • 【高等数学】第三章 微分中值定理与导数的应用——第三节 泰勒公式
  • Python 【技术面试题和HR面试题】➕ 循环结构、控制语句及综合应用问答
  • C++编程基础
  • 端口到底是个什么鬼?回答我!
  • pyQt基础4(对话框)
  • softmax回归的从零开始实现
  • php的原生类
  • 《棒球规则介绍》领队和主教练谁说了算·棒球1号位
  • Express实现定时任务
  • PBR渲染
  • 软件开发那些基础事儿:需求、模型与生命周期
  • 大模型在卵巢癌预测及诊疗方案制定中的应用研究
  • 河南专升本2026年练习题、真题和2000题每日一节
  • 分割网络Segformer
  • 【B题解题思路】2025APMCM亚太杯中文赛B题解题思路+可运行代码参考(无偿分享)
  • 设计模式(结构型)-适配器模式