opencl学习二

矩阵乘法

  • 普通实现
  • 7.46346s
#include <iostream>
#include <sys/time.h>

using namespace std;

float a[1000][2000], b[2000][1500], c[1000][1500] = {0.0};

int main() {
    for(int i = 0; i < 1000; ++i) {
        for(int j = 0; j < 2000; ++j) {
            a[i][j] = 1.1 + i / 1000.0;
        }
    }
    for(int i = 0; i < 2000; ++i) {
        for(int j = 0; j < 1500; ++j) {
            a[i][j] = 1.11 + j / 1000.0;
        }
    }
    struct timeval start, end;
    gettimeofday(&start, NULL);
    for(int i = 0; i < 1000; ++i) {
        for(int j = 0; j < 2000; ++j) {
            for(int k = 0; k < 1500; ++k) {
                c[i][k] += a[i][j]*b[j][k];
            }
        }
    }
    gettimeofday(&end, NULL);
    float cost_time = (end.tv_usec-start.tv_usec)/1000000.0 + end.tv_sec-start.tv_sec;
    cout << cost_time << endl;

    return 0;
}
  • opencl实现
  • 0.303606 seconds
  • Host代码
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <CL/cl.h>
#include <sys/time.h>
 
#define MAX_SOURCE_SIZE (0x100000)
//data parallel
int main()
{ 
	int i, j;
	float *A;
	float *B;
	float *C;
	const int row = 1000, mid = 2000, col = 1500;
 
	A = (float *)malloc(row * mid * sizeof(float));
	B = (float *)malloc(mid * col * sizeof(float));
	C = (float *)malloc(row * col * sizeof(float));
 
	/* Initialize input data */
	printf("Initialize input data");
	for (i = 0; i < row; i++) {
		for (j = 0; j < mid; j++) {
			A[i * mid + j] = 1.1 + i / 1000.0;
		}
	}
	for(i = 0; i < mid; ++i) {
		for(j = 0; j < col; ++j) {
			B[i*col+j] = 1.11 + j / 1000.0;
		}
	}
	printf("\n");
 
	struct timeval start, end;
    gettimeofday(&start, NULL);
    
    cl_int ret;
	/* 1.Get Platform Information */
	cl_platform_id platform_id = NULL;
	cl_uint ret_num_platforms;
	// 查询的最大数量,返回的平台列表,实际平台数
	ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);

	/* 2.Device Information */
	cl_device_id device_id = NULL;
	cl_uint ret_num_devices;
	// 平台列表,查询的设备类型,查询的最大数量,返回的设备列表,实际设备数
	ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &ret_num_devices);

	/* 3.Create OpenCL Context */
	cl_context context = NULL;
	// properties,设备数,设备列表,pfn_notify,user_data,返回码
	context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret);

	/* 4.Create command queue */
	cl_command_queue command_queue = NULL;
	// context,device_id,properties,返回码
	command_queue = clCreateCommandQueue(context, device_id, 0, &ret);

	/* 5.Create Buffer Object */
	cl_mem Amobj = NULL;
	cl_mem Bmobj = NULL;
	cl_mem Cmobj = NULL;
	// context,flag,大小,host指针,返回码
	Amobj = clCreateBuffer(context, CL_MEM_READ_WRITE, row * mid * sizeof(float), NULL, &ret);
	Bmobj = clCreateBuffer(context, CL_MEM_READ_WRITE, mid * col * sizeof(float), NULL, &ret);
	Cmobj = clCreateBuffer(context, CL_MEM_READ_WRITE, row * col * sizeof(float), NULL, &ret);

	/* 6.Copy input data to the memory buffer */
	// command_queue,buffer,是否阻塞,偏移,大小,主机数据,等待事件数,等待事件列表,事件命令
	ret = clEnqueueWriteBuffer(command_queue, Amobj, CL_TRUE, 0, row * mid * sizeof(float), A, 0, NULL, NULL);
	ret = clEnqueueWriteBuffer(command_queue, Bmobj, CL_TRUE, 0, mid * col * sizeof(float), B, 0, NULL, NULL);

	/* 7.Load kernel source file */
	FILE *fp;
	const char fileName[] = "../src/kernel.cl";
	size_t source_size;
	char *source_str;
	fp = fopen(fileName, "r");
	if (!fp) {
		fprintf(stderr, "Failed to load kernel.cl");
		exit(1);
	}
	source_str = (char *)malloc(MAX_SOURCE_SIZE);
	source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
	fclose(fp);

	/* 8.Create kernel program from source file*/
	cl_program program = NULL;
	// context,count,kernel代码,代码长度,返回码
	program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);

	/*  9. build program*/
	// program,设备数,device_id,options,pfn_notify,user_data
	ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);

	/* 10.Create data parallel OpenCL kernel */
	cl_kernel kernel = NULL;
	// program, 名字, 返回码
	kernel = clCreateKernel(program, "dataParallel", &ret);

	/* 11.Set OpenCL kernel arguments */
	// kernel, 参数索引,参数大小,参数
	ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&Amobj);
	ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&Bmobj);
	ret = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&Cmobj);
	ret = clSetKernelArg(kernel, 3, sizeof(int), &row);
	ret = clSetKernelArg(kernel, 4, sizeof(int), &mid);
	ret = clSetKernelArg(kernel, 5, sizeof(int), &col);
	
	/* 12.Execute OpenCL kernel as data parallel */
	size_t global_item_size[2] = {row, col};
	size_t local_item_size = 1;
	// command_queue,kernel,数据维度,global_work_offset,global_item_size,local_item_size,等待事件数,等待事件列表,事件命令
	ret = clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, global_item_size, NULL, 0, NULL, NULL);

	/* 13.wait for the commands to complete before reading back results */
	ret = clFlush(command_queue);
	ret = clFinish(command_queue);
 
	/* 14.Transfer result to host */
	// command_queue,buffer,是否阻塞,偏移,大小,主机数据,等待事件数,等待事件列表,事件命令
	ret = clEnqueueReadBuffer(command_queue, Cmobj, CL_TRUE, 0, row * col * sizeof(float), C, 0, NULL, NULL);
	// cost
	gettimeofday(&end, NULL);
    float cost_time = (end.tv_usec-start.tv_usec)/1000000.0 + end.tv_sec-start.tv_sec;
	printf("cost : %f seconds\n", cost_time);
	
	/* 15.Finalization */
	ret = clReleaseKernel(kernel);
	ret = clReleaseProgram(program);
	ret = clReleaseMemObject(Amobj);
	ret = clReleaseMemObject(Bmobj);
	ret = clReleaseMemObject(Cmobj);
	ret = clReleaseCommandQueue(command_queue);
	ret = clReleaseContext(context);
 
	free(source_str);
 
	free(A);
	free(B);
	free(C);
	return 0;
 }

  • kernel.cl
  • 其实row用不着
__kernel void dataParallel(__global float* A, __global float* B, __global float* C,int row, int mid, int col)
{
	int i = get_global_id(0), j = get_global_id(1);
	//printf("%d, %d\n", i, j);
	float sum = 0;
	for(int m = 0; m < mid; ++m) {
	    sum += A[i*mid+m] * B[m*col+j];
	}
	C[i*col+j] = sum;
}

20220824补充

  • 安装opencl:sudo apt install ocl-icd-* opencl-headerssudo apt install clinfoclinfo |grep "Device Type"
  • CMakeLists:

    cmake_minimum_required(VERSION 2.8.3)
    project(cl)
    add_compile_options(-std=c++11 -g)
    include_directories(
    #/usr/local/cuda-10.0/include
    )
    add_executable( P R O J E C T N A M E s r c / m a i n . c c ) t a r g e t l i n k l i b r a r i e s ( {PROJECT_NAME} src/main.cc) target_link_libraries( PROJECTNAMEsrc/main.cc)targetlinklibraries({PROJECT_NAME}
    OpenCL
    )
    add_executable(slow src/slow.cc)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340