欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCl_CPU加速矩阵运算

程序员文章站 2022-07-12 21:31:32
...

本博文用的是intel的opencl架构,下载链接https://software.intel.com/en-us/intel-opencl/download,默认安装即可

注意:安装完毕后opencl的sdk在路径C:\Program Files (x86)\Intel\OpenCL SDK\6.3下


第一步:检验计算机硬件设备

安装完毕检验硬件设备,查看平台数量,代码如下:

#include <iostream>
#include <malloc.h>
#include <CL/cl.h>//包含CL的头文件

using namespace std;

//根据参数,判断设备类别。是CPU、GPU、ACCELERATOR或其他设备
const char* GetDeviceType(cl_device_type it)
{
	if (it == CL_DEVICE_TYPE_CPU)
		return "CPU";
	else if (it == CL_DEVICE_TYPE_GPU)
		return "GPU";
	else if (it == CL_DEVICE_TYPE_ACCELERATOR)
		return "ACCELERATOR";
	else
		return "DEFAULT";

}

int main()
{
	char dname[512];
	cl_device_id devices[20];
	cl_platform_id* platform_id = NULL;
	cl_uint num_devices;
	cl_device_type int_type;
	cl_ulong long_entries;
	cl_uint num_platform;
	cl_int err;

	//查询系统上可用的计算平台,可以理解为初始化
	err = clGetPlatformIDs(0, NULL, &num_platform);

	if (err != CL_SUCCESS)
	{
		cout << "clGetPlatformIDs error" << endl;
		return 0;
	}

	cout << "PlatForm num:" << num_platform << endl;

	int st = 0;

	platform_id = new cl_platform_id[num_platform];

	err = clGetPlatformIDs(num_platform, platform_id, NULL);

	if (err != CL_SUCCESS)
	{
		cout << "clGetPlatformIDs error" << endl;
		return 0;
	}

	for (st = 0; st<num_platform; st++)
	{
		cout << "----------------------------------" << endl;
		cout << "Platform " << st + 1 << endl;

		//获取可用计算平台的名称
		clGetPlatformInfo(platform_id[st], CL_PLATFORM_NAME, 512, dname, NULL);
		cout << "CL_PLATFORM_NAME:" << dname << endl;

		//获取可用计算平台的版本号,即OpenCL的版本号
		clGetPlatformInfo(platform_id[st], CL_PLATFORM_VENDOR, 512, dname, NULL);
		cout << "CL_PLATFORM_VERSION:" << dname << endl;

		//获取可用计算平台的设备数目
		clGetDeviceIDs(platform_id[st], CL_DEVICE_TYPE_ALL, 20, devices, &num_devices);
		cout << "Device num:" << num_devices << endl;

		unsigned int n = 0;

		//循环两次,检测两个设备的属性
		for (n = 0; n<num_devices; n++)
		{
			cout << endl << "Device " << n + 1 << endl;
			//获取设备名称
			clGetDeviceInfo(devices[n], CL_DEVICE_NAME, 512, dname, NULL);
			cout << "Device :" << dname << endl;

			//获取设备类别
			clGetDeviceInfo(devices[n], CL_DEVICE_TYPE, sizeof(cl_device_type),
				&int_type, NULL);
			cout << "Device Type:" << GetDeviceType(int_type) << endl;

			//获取设备版本号
			clGetDeviceInfo(devices[n], CL_DRIVER_VERSION, 512, dname, NULL);
			cout << "Device version:" << dname << endl;

			//获取设备全局内存大小
			clGetDeviceInfo(devices[n], CL_DEVICE_GLOBAL_MEM_SIZE,
				sizeof(cl_ulong), &long_entries, NULL);
			cout << "Device global mem(MB):" <<
				long_entries / 1024 / 1024 << endl;

			//获取设备CACHE内存大小
			clGetDeviceInfo(devices[n], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,
				sizeof(cl_ulong), &long_entries, NULL);
			cout << "Device global mem cache(KB):" <<
				long_entries / 1024 << endl;

			//获取本地内存大小
			clGetDeviceInfo(devices[n], CL_DEVICE_LOCAL_MEM_SIZE,
				sizeof(cl_ulong), &long_entries, NULL);
			cout << "Device Locale mem(KB) :" << long_entries / 1024 << endl;

			//获取设备频率
			clGetDeviceInfo(devices[n], CL_DEVICE_MAX_CLOCK_FREQUENCY,
				sizeof(cl_ulong), &long_entries, NULL);
			cout << "Device Max clock(MHz) :" << long_entries << endl;

			//获取最大工作组数
			clGetDeviceInfo(devices[n], CL_DEVICE_MAX_WORK_GROUP_SIZE,
				sizeof(cl_ulong), &long_entries, NULL);
			cout << "Device Max Group size :" << long_entries << endl;

			//获取最大计算核心数
			clGetDeviceInfo(devices[n], CL_DEVICE_MAX_COMPUTE_UNITS,
				sizeof(cl_ulong), &long_entries, NULL);
			cout << "Device Max parallel cores:" << long_entries << endl;

		}
	}

	return 0;
}


如果发现cpu的opencl版本为实验版本2.1,需要runtime配置文件,安装即可。

配置文件链接:http://pan.baidu.com/s/1geNnMy3 密码:7n8o

再次检验硬件设备,查看平台数量,可以发现cpu的opencl版本正确。


第二步:矩阵运算加速

代码如下:

核函数vecadd.cl文件如下:

__kernel void vecAdd(__global int* A,
        __global int* B,
        __global int* C)
{
    //获取当前工作项所在位置(线程索引号)
    //就是向量每一维的位置
    int idx = get_global_id(0);
    C[idx] = A[idx] + B[idx];
}


主函数main.cpp文件如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <CL/cl.h>//包含CL的头文件

//OpenCl 2.1
//Solve problem: error C4996: 'clCreateCommandQueue': 被声明为已否决
#pragma warning( disable : 4996 )

using namespace std;

//100维向量
#define elements 100

//从外部文件获取cl内核代码
bool GetFileData(const char* fname, string& str)
{
	FILE* fp = fopen(fname, "r");
	if (fp == NULL)
	{
		printf("no found filen");
		return false;
	}

	int n = 0;
	while (feof(fp) == 0)
	{
		str += fgetc(fp);
	}

	return true;
}

int main()
{
	//先读外部CL核心代码,如果失败则退出。
	//代码存buf_code里面
	string code_file;

	if (false == GetFileData("vecadd.cl", code_file))
	{
		return 0;
	}

	char* buf_code = new char[code_file.size()];
	strcpy(buf_code, code_file.c_str());
	buf_code[code_file.size() - 1] = NULL;

	//声明CL所需变量。
	cl_device_id device;
	cl_platform_id *platform_id = NULL;
	cl_context context;
	cl_command_queue cmdQueue;
	cl_mem bufferA, bufferB, bufferC;
	cl_program program;
	cl_kernel kernel = NULL;

	//我们使用的是一维向量
	//设定向量大小(维数)
	size_t globalWorkSize[1];
	globalWorkSize[0] = elements;

	cl_int err;

	//定义输入变量和输出变量,并设定初值
	int* buf_A = new int[elements];
	int* buf_B = new int[elements];
	int* buf_C = new int[elements];

	size_t datasize = sizeof(int) * elements;

	for (int i = 0; i < elements; i++)
	{
		buf_A[i] = (float)i;
		buf_B[i] = (float)i + 1.0;
	}

	//step 1:初始化OpenCL
	cl_uint num_platform;
	err = clGetPlatformIDs(0, NULL, &num_platform);

	platform_id = new cl_platform_id[num_platform];
	err = clGetPlatformIDs(num_platform, platform_id, NULL);

	if (err != CL_SUCCESS)
	{
		cout << "clGetPlatformIDs error" << endl;
		return 0;
	}

	//博主计算机三个plantform,platform_id[2]为CPU,根据情况来改
	clGetDeviceIDs(platform_id[2], CL_DEVICE_TYPE_CPU, 1, &device, NULL);

	//step 2:创建上下文
	context = clCreateContext(NULL, 1, &device, NULL, NULL, NULL);

	//step 3:创建命令队列
	cmdQueue = clCreateCommandQueue(context, device, 0, NULL);

	//step 4:创建数据缓冲区
	bufferA = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, NULL);
	bufferB = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, NULL);
	bufferC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, datasize, NULL, NULL);

	//step 5:将数据上传到缓冲区
	clEnqueueWriteBuffer(cmdQueue, bufferA, CL_FALSE, 0, datasize, buf_A, 0, NULL, NULL);
	clEnqueueWriteBuffer(cmdQueue, bufferB, CL_FALSE, 0, datasize, buf_B, 0, NULL, NULL);

	//step 6:加载编译代码,创建内核调用函数
	program = clCreateProgramWithSource(context, 1, (const char**)&buf_code, NULL, NULL);
	clBuildProgram(program, 1, &device, NULL, NULL, NULL);
	kernel = clCreateKernel(program, "vecAdd", NULL);

	//step 7:设置参数,执行内核
	clSetKernelArg(kernel, 0, sizeof(cl_mem), &bufferA);
	clSetKernelArg(kernel, 1, sizeof(cl_mem), &bufferB);
	clSetKernelArg(kernel, 2, sizeof(cl_mem), &bufferC);

	clEnqueueNDRangeKernel(cmdQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);

	//step 8:取回计算结果
	clEnqueueReadBuffer(cmdQueue, bufferC, CL_TRUE, 0, datasize, buf_C, 0, NULL, NULL);

	//输出验证结果
	cout << buf_A[0] << "+" << buf_B[0] << "=" << buf_C[0] << endl;
	cout << buf_A[elements - 1] << "+" << buf_B[elements - 1] << "=" << buf_C[elements - 1] << endl;

	//释放所有调用和内存
	clReleaseKernel(kernel);
	clReleaseProgram(program);
	clReleaseCommandQueue(cmdQueue);
	clReleaseMemObject(bufferA);
	clReleaseMemObject(bufferB);
	clReleaseMemObject(bufferC);
	clReleaseContext(context);

	delete[]platform_id;
	delete[]buf_A;
	delete[]buf_B;
	delete[]buf_C;
	delete[]buf_code;
	system("pause");
	return 0;
}


测试结果显示如下:

OpenCl_CPU加速矩阵运算


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


相关标签: OpenCl