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 ...
随机推荐
- Java IO流-Properties
2017-11-05 21:37:50 Properties Properties:Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载.属性列表中每个键及其 ...
- python学习笔记(日志系统实现)
博主今天在自己的接口自动化框架中添加了日志系统 基于python自带的logging库.包括日志主函数.生成日志文件: # -*- coding: utf-8 -*- # 日志系统 # 时间:2017 ...
- C#中json字符串的序列化和反序列化
改文章转自:https://www.cnblogs.com/shang201215019/p/7907655.html 什么是 Json ? Json[javascript对象表示方法] ...
- torch中的多线程threads学习
torch中的多线程threads学习 torch threads threads 包介绍 threads package的优势点: 程序中线程可以随时创建 Jobs被以回调函数的形式提交给线程系统, ...
- Fedora BCM43142 无线网卡驱动安装
OS:Fedora 25 KDE 系统内核:4.10.16-200.fc25.x86_64 #1 网卡:BCM43142 1.识别自己的网卡型号:命令:lspci | grep -i broadcom ...
- 转载-lvs-dr模式+keepalived双机
lvs+keepalived实现高可用群集配置详解 Mon 16 April 2012 来源: https://www.linuxzen.com/lvskeepalivedshi-xian-gao-k ...
- oracle问题集棉
1. 在未安装orcale客户端时,使用pl/sql登录数据库服务器时,报错ORA -12543:TNSdestination host unreachable 2.无法通过ip地址远程连接ORACL ...
- Beta阶段第2周/共2周 Scrum立会报告+燃尽图 10
作业要求[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2411] 版本控制:https://git.coding.net/liuyy08 ...
- 移动端rem布局雪碧图解决方案 以及分享腾讯团队的在线雪碧图工具
先分享一下地址:http://alloyteam.github.io/gopng/ 使用的方法也很简单,将需要的小图标拖进去,全部拖进去后再调位置(每拖一个进去都会帮你排列好,但是没有间隔,所以全部拖 ...
- 1月中旬值得一读的10本技术新书(机器学习、Java、大数据等)!
1月中旬,阿里云云栖社区 联合 博文视点 为大家带来十本技术书籍(机器学习.Java.大数据等).以下为书籍详情,文末还有福利哦! 书籍名称:Oracle数据库问题解决方案和故障排除手册 内容简介 & ...