OpenCL加速矩阵运算

OpenCl运用并行的方法加速矩阵运算,在业界得到广泛运用,博主也试了一试,挺好玩的。

注意:1、OpenCl针对的数据量越大,加速效果越明显

            2、OpenCl版本测试在nvidia730上,cuda7.5下的OpenCl文件,windows7

            3、OpenCl_SDK位于C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5下

            4、include位于v7.5下的CL文件夹

            5、lib位于v7.5下的OpenCl.lib

 

下列程序经博主测试准确无误!

核函数(test2.cl)文件如下:

 

__kernel void adder(__global const float* a, __global float* result)
{
	int idx = get_global_id(0);
	result[idx] = a[idx] + 1;
}

 

 

 

主文件main.cpp

 

//OpenCl加速向量运算
//作者:samylee
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <CL/cl.h>

cl_program load_program(cl_context context, const char* filename)
{
	std::ifstream in(filename, std::ios_base::binary);
	if (!in.good()) {
		return 0;
	}

	// get file length
	in.seekg(0, std::ios_base::end);
	size_t len​​gth = in.tellg();
	in.seekg(0, std::ios_base::beg);
	// read program source
	std::vector<char> data(len​​gth + 1);
	in.read(&data[0], len​​gth);
	data[len​​gth] = 0;
	// create and build program
	const char* source = &data[0];
	cl_program program = clCreateProgramWithSource(context, 1, &source, 0, 0);
	if (program == 0) {
		return 0;
	}
	if (clBuildProgram(program, 0, 0, 0, 0, 0) != CL_SUCCESS) {
		return 0;
	}
	return program;
}

int main()

{
	cl_int err;

	//调用两次clGetPlatformIDs函数,第一次获取可用的平台数量,第二次获取一个可用的平台。
	cl_uint num;
	err = clGetPlatformIDs(0, 0, &num);
	if (err != CL_SUCCESS) {
		std::cerr << "Unable to get platforms\n";
		return 0;
	}

	std::vector<cl_platform_id> platforms(num);
	err = clGetPlatformIDs(num, &platforms[0], &num);
	if (err != CL_SUCCESS) {
		std::cerr << "Unable to get platform ID\n";
		return 0;
	}

	//上下文context可能会管理多个设备device。
	cl_context_properties prop[] = { CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(platforms[0]), 0 };
	cl_context context = clCreateContextFromType(prop, CL_DEVICE_TYPE_DEFAULT, NULL, NULL, NULL);
	if (context == 0) {
		std::cerr << "Can't create OpenCL context\n";
		return 0;
	}

	size_t cb;
	clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &cb);
	std::vector<cl_device_id> devices(cb / sizeof(cl_device_id));
	clGetContextInfo(context, CL_CONTEXT_DEVICES, cb, &devices[0], 0);

	//调用两次clGetDeviceIDs函数,第一次获取可用的设备数量,第二次获取一个可用的设备。
	clGetDeviceInfo(devices[0], CL_DEVICE_NAME, 0, NULL, &cb);
	std::string devname;
	devname.resize(cb);
	clGetDeviceInfo(devices[0], CL_DEVICE_NAME, cb, &devname[0], 0);

	//输出设备名称
	std::cout << "Device: " << devname.c_str() << "\n";

	//Create a command queue(调用clCreateCommandQueue函数)
	//一个设备device对应一个command queue。
	//上下文conetxt将命令发送到设备对应的command queue,设备就可以执行命令队列里的命令
	cl_command_queue queue = clCreateCommandQueue(context, devices[0], 0, 0);
	if (queue == 0) {
		std::cerr << "Can't create command queue\n";
		clReleaseContext(context);
		return 0;
	}

	//Create device buffers(调用clCreateBuffer函数)
	const int DATA_SIZE = 3;
	std::vector<float> a(DATA_SIZE), res(DATA_SIZE);
	for (int i = 0; i < DATA_SIZE; i++) {
		a[i] = i;
	}

	cl_mem cl_a = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * DATA_SIZE, &a[0], NULL);
	cl_mem cl_res = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_float) * DATA_SIZE, NULL, NULL);

	if (cl_a == 0 || cl_res == 0) {
		std::cerr << "Can't create OpenCL buffer\n";
		clReleaseMemObject(cl_a);
		clReleaseMemObject(cl_res);
		clReleaseCommandQueue(queue);
		clReleaseContext(context);
		return 0;
	}

	//Load kernel function
	cl_program program = load_program(context, "test2.cl");
	if (program == 0) {
		std::cerr << "Can't load or build program\n";
		clReleaseMemObject(cl_a);
		clReleaseMemObject(cl_res);
		clReleaseCommandQueue(queue);
		clReleaseContext(context);
		return 0;
	}

	//Create kernel function
	cl_kernel adder = clCreateKernel(program, "adder", 0);
	if (adder == 0) {
		std::cerr << "Can't load kernel\n";
		clReleaseProgram(program);
		clReleaseMemObject(cl_a);
		clReleaseMemObject(cl_res);
		clReleaseCommandQueue(queue);
		clReleaseContext(context);
		return 0;
	}

	//设定函数参数
	clSetKernelArg(adder, 0, sizeof(cl_mem), &cl_a);
	clSetKernelArg(adder, 1, sizeof(cl_mem), &cl_res);

	//执行函数
	size_t work_size = DATA_SIZE;
	err = clEnqueueNDRangeKernel(queue, adder, 1, 0, &work_size, 0, 0, 0, 0);
	if (err == CL_SUCCESS) {
		err = clEnqueueReadBuffer(queue, cl_res, CL_TRUE, 0, sizeof(float) * DATA_SIZE, &res[0], 0, 0, 0);
	}

	//验证是否正确
	if (err == CL_SUCCESS) {
		std::cout << res[1] << std::endl;
	}
	else {
		std::cerr << "Can't run kernel or read back data\n";
	}

	//release all source
	clReleaseKernel(adder);
	clReleaseProgram(program);
	clReleaseMemObject(cl_a);
	clReleaseMemObject(cl_res);
	clReleaseCommandQueue(queue);
	clReleaseContext(context);
	system("pause");
	return 0;
}

 

 

 

 

 

效果如下:

 

 

任何问题请加唯一QQ2258205918(名称samylee)!

唯一VX:samylee_csdn

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中进行矩阵运算的优化有几种方法。首先,可以使用专门的矩阵计算库来提高运算效率。例如,Armadillo是一个C++下的矩阵计算库,它提供了许多矩阵操作函数,支持矩阵逐元素操作、矩阵分块操作以及对整体矩阵的操作等等。它还可以自动检测并使用更快的基本运算实现,如BLAS、OpenBLAS、IntelMKL和AMDACML。此外,ViennaCL是一个并行矩阵计算库,可以在C语言中进行并行矩阵计算,提高运算速度。 另外,还可以使用OpenCV的矩阵计算功能来进行优化。OpenCV提供了类Matlab的矩阵C接口,可以方便地进行计算机视觉和机器学习相关的矩阵操作。它还提供了cv::gpu模块和cv::ocl模块,分别支持CUDA和OpenCL的并行矩阵计算功能,可以进一步提高运算效率。 除了使用专门的矩阵计算库,还可以使用一些优化技术来提高矩阵运算的效率。例如,可以使用多线程或并行计算来加速矩阵运算。还可以使用SIMD指令集来进行向量化计算,提高运算速度。此外,还可以使用矩阵分块技术来减少内存访问次数,提高缓存命中率,从而提高运算效率。 总之,对于C语言中的矩阵运算优化,可以选择使用专门的矩阵计算库,如Armadillo和ViennaCL,也可以使用OpenCV的矩阵计算功能。此外,还可以使用多线程、并行计算、SIMD指令集和矩阵分块等技术来提高运算效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值