OpenCL NativeKernel 计算矩阵乘法
▶ 使用函数 clEnqueueNativeKernel 来调用 C/C++ 本地函数(在 OpenCL 中将其看做回调函数),使用本地编译器(而不是 OpenCL 编译器)来编译和执行内核
● 代码,似乎很难找到有关 native kernal 的例子,感谢 stack exchange(https://stackoverflow.com/questions/18409256/how-do-you-read-arguments-passed-to-a-native-kernel,https://stackoverflow.com/questions/10140494/using-clenqueuenativekernel-in-opencl)
#include <stdio.h>
#include <stdlib.h>
#include <cl.h> #pragma warning(disable : 4996) const int rowA = , colA = , colB = ; struct parameter // 传给native kernel 的参数列表
{
unsigned int row_A;
unsigned int col_A;
unsigned int col_B;
float *input_A;
float *input_B;
float *output_C;
}; void multiplyNaive(void *in)
{
struct parameter *para = (struct parameter *)in;// 传入参数只有 para->col_B 错误(呈现随机数),与内存对齐有关?
float sum; // 因为用不了 para->col_B,代码中使用的全局变量代替 para 中的成员
for (i = ; i < rowA; i++)
{
for (j = ; j < colB; j++)
{
for (k = , sum = 0.0f; k < colA; k++)
sum += para->input_A[i * colA + k] * para->input_B[k * colB + j];
para->output_C[i * colB + j] = sum;
}
}
return;
} int main()
{
int i, j, k, correct;
float *A, *B, *C, tempSum;
cl_int status; A = (float*)malloc(sizeof(float) * rowA * colA);
B = (float*)malloc(sizeof(float) * colA * colB);
C = (float*)malloc(sizeof(float) * rowA * colB);
for (i = ; i < rowA * colA; A[i] = , i++);
for (i = ; i < colA * colB; B[i] = , i++); cl_uint nPlatform;
clGetPlatformIDs(, NULL, &nPlatform);
cl_platform_id *listPlatform = (cl_platform_id*)malloc(nPlatform * sizeof(cl_platform_id));
clGetPlatformIDs(nPlatform, listPlatform, NULL);
cl_uint nDevice = ;
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_CPU, , NULL, &nDevice);// 使用支持 NativeKernel 的 intel OpenCL
cl_device_id *listDevice = (cl_device_id*)malloc(nDevice * sizeof(cl_device_id));
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_CPU, nDevice, listDevice, NULL);
cl_context context = clCreateContext(NULL, nDevice, listDevice, NULL, NULL, &status);
cl_command_queue queue = clCreateCommandQueue(context, listDevice[], , &status); cl_mem bufferA = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * rowA * colA, A, &status);
cl_mem bufferB = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * colA * colB, B, &status);
cl_mem bufferC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * rowA * colB, NULL, &status); // 设置内核参数
cl_mem bufferList[] = { bufferA, bufferB, bufferC };
// 结构体写法
struct parameter para;
para.row_A = rowA;
para.col_A = colA;
para.col_B = colB;
para.input_A = NULL;
para.input_B = NULL;
para.output_C = NULL;
const void *bufferLocation[] = { ¶.input_A, ¶.input_B, ¶.output_C };
// 列表写法
//void *para[6] = { (void *)rowA, (void *)colA, (void *)colB, NULL, NULL, NULL }; // 参数列表,空出缓冲区的位置
//const void *bufferLocation[3] = { ¶[3], ¶[4], ¶[5] }; // 指明参数列表中哪些位置应该是缓冲区 status = clEnqueueNativeKernel(queue, (void(__stdcall *)(void*))multiplyNaive, (void*)¶, , , bufferList, &bufferLocation[], , NULL, NULL);
// 注意第 7 个参数 &bufferLocation[0],需要的是一个 const void**,而不是 void*[3],不能直接传入 bufferLocation // 返回并检查结果
clEnqueueReadBuffer(queue, bufferC, CL_TRUE, , sizeof(float) * rowA * colB, C, , NULL, NULL);
for (i = , correct = ; i < rowA && correct; i++)
{
for (j = ; j < colB && correct; j++)
{
for (k = , tempSum = 0.0f; k < colA; tempSum += A[i * colA + k] * B[k * colB + j], k++);
if (tempSum != C[i * colB + j])
{
printf("Error at [%d, %d], calculation: %f, reference: %f\n", i, j, C[i*colA + j], tempSum);
correct = ;
}
}
}
if (correct)
printf("Result correct.\n"); // 释放资源
free(A);
free(B);
free(C);
free(listPlatform);
free(listDevice);
clReleaseContext(context);
clReleaseMemObject(bufferA);
clReleaseMemObject(bufferB);
clReleaseMemObject(bufferC);
clReleaseCommandQueue(queue);
getchar();
return ;
}
● 输出结果,我的电脑不支持运行本地函数
-
Error at[, ], calculation: 0.000000, reference : 64.000000
● 输出结果,办公室的电脑,正确计算,但代码中注释的问题没有解决
Result correct.
● 检查设备是否支持 native kernel
#include <stdio.h>
#include <stdlib.h>
#include <cl.h> int main()
{
unsigned long long val; cl_uint nPlatform;
clGetPlatformIDs(, NULL, &nPlatform);
cl_platform_id *listPlatform = (cl_platform_id*)malloc(nPlatform * sizeof(cl_platform_id));
clGetPlatformIDs(nPlatform, listPlatform, NULL);
cl_uint nDevice = ;
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, , NULL, &nDevice);
cl_device_id *listDevice = (cl_device_id*)malloc(nDevice * sizeof(cl_device_id));
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, nDevice, listDevice, NULL); if (clGetDeviceInfo(listDevice[], CL_DEVICE_EXECUTION_CAPABILITIES, sizeof(val), &val, NULL) == CL_SUCCESS)// 获取设备信息 CL_DEVICE_EXECUTION_CAPABILITIES
{
printf("\nEXECUTION_CAPABILITIES: ");
if (val & CL_EXEC_KERNEL)
{
val &= ~CL_EXEC_KERNEL;
printf("Kernel ");
}
if (val & CL_EXEC_NATIVE_KERNEL)
{
val &= ~CL_EXEC_NATIVE_KERNEL;
printf("Native ");
}
if (val)
printf("Unknown (0x%llx) ", val);
printf("\n");
}
free(listPlatform);
free(listDevice);
getchar();
return ;
}
● 输出结果,我的电脑仅支持设备执行,而不支持本地执行
EXECUTION_CAPABILITIES: Kernel
● 用到的函数和定义
// cl.h
// 设备是否支持函数 clEnqueueNativeKernel 执行回调函数的值
#define CL_EXEC_KERNEL (1 << 0)
#define CL_EXEC_NATIVE_KERNEL (1 << 1) extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueNativeKernel(
cl_command_queue, // 命令队列
void (CL_CALLBACK * /*user_func*/)(void *), // 回调函数
void *, // 参数列表
size_t, // 参数总个数
cl_uint, // 数据对象(包括 bufer 和 image)个数
const cl_mem *, // 数据对象列表
const void **, // 数据对象在参数列表中的地址
cl_uint, // 等待列表中的事件数
const cl_event *, // 等待列表
cl_event * // 本事件标记
) CL_API_SUFFIX__VERSION_1_0;
OpenCL NativeKernel 计算矩阵乘法的更多相关文章
- 使用shared memory 计算矩阵乘法 (其实并没有加速多少)
#include "cuda_runtime.h" #include "device_launch_parameters.h" #include "d ...
- 向MapReduce转换:通过部分成绩计算矩阵乘法
代码共分为四部分: <strong><span style="font-size:18px;">/*** * @author YangXin * @info ...
- 蓝桥杯 BASIC_17 矩阵乘法 (矩阵快速幂)
问题描述 给定一个N阶矩阵A,输出A的M次幂(M是非负整数) 例如: A = 1 2 3 4 A的2次幂 7 10 15 22 输入格式 第一行是一个正整数N.M(1<=N<=30, 0& ...
- 有关CUBLAS中的矩阵乘法函数
关于cuBLAS库中矩阵乘法相关的函数及其输入输出进行详细讨论. ▶ 涨姿势: ● cuBLAS中能用于运算矩阵乘法的函数有4个,分别是 cublasSgemm(单精度实数).cublasDgemm( ...
- OpenCL 矩阵乘法
▶ 矩阵乘法,按照书里的内容进行了几方面的优化,包括局部内存,矢量数据类型,寄存器,流水线等. ● 最直接的乘法.调用时 main.c 中使用 size_t globalSize[] = { rowA ...
- 矩阵乘法的运算量计算(华为OJ)
题目地址: https://www.nowcoder.com/practice/15e41630514445719a942e004edc0a5b?tpId=37&&tqId=21293 ...
- CUDA 矩阵乘法终极优化指南
作者:马骏 | 旷视 MegEngine 架构师 前言 单精度矩阵乘法(SGEMM)几乎是每一位学习 CUDA 的同学绕不开的案例,这个经典的计算密集型案例可以很好地展示 GPU 编程中常用的优化技巧 ...
- *HDU2254 矩阵乘法
奥运 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submissi ...
- *HDU 1757 矩阵乘法
A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
随机推荐
- 辗转相除法 & 裴蜀定理
2018-03-11 17:39:22 一.辗转相除法 在数学中,辗转相除法,又称欧几里得算法(英语:Euclidean algorithm),是求最大公约数的算法.辗转相除法首次出现于欧几里得的&l ...
- log模块和report模块
这两个模块不需要管,我们生成的log和report直接添加到这里就好
- hdu4965矩阵快速幂
这题不能直接按常规做啊,因为数组根本就开不下,转换思维A(B*A)^(n*n-1)B 这样的话数组B*A就是10*10了,然后快速幂就行了 刚开始数组都开小了,tle,还找了半天bug...还有就是定 ...
- HDU1166 敌兵布阵_线段树
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- UEFI下windows启动过程
引导文件 在UEFI安装完操作系统后,Windows至少使用两个分区,一个叫做ESP分区(EFI SYSTEM PARTITION),用于存放启动文件,另一个则是BIOS下正常的系统分区,不同的是,B ...
- 建造者模式 build
引出建造者模式: package com.disign.build; /** * Created by zhen on 2017-05-19. */ public class BuildPersonT ...
- JDK5的新特性:泛型、可变参数、静态导入
数组可以在创建的时候就指定存放的数据类型,这样放入不同类型的时候就会发生编译错误. 而集合却可以存储多种不同类型,这样的话如果是遍历的时候在集合中装了好多不同的数据类型的时候,十分容易发生类型转换错误 ...
- 理解HTTP之Content-Type
http://homeway.me/2015/07/19/understand-http-about-content-type/
- Unable to connect to any of the specified MySQL hosts.
c#连接Mysql数据建立连接时提示:Unable to connect to any of the specified MySQL hosts. 出现此错误的原因是Server(数据库服务器IP地址 ...
- Nginx 静态资源缓存配置
示例 # Media: images, icons, video, audio, HTC location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|m ...