▶ 使用函数 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[] = { &para.input_A, &para.input_B, &para.output_C };
// 列表写法
//void *para[6] = { (void *)rowA, (void *)colA, (void *)colB, NULL, NULL, NULL }; // 参数列表,空出缓冲区的位置
//const void *bufferLocation[3] = { &para[3], &para[4], &para[5] }; // 指明参数列表中哪些位置应该是缓冲区 status = clEnqueueNativeKernel(queue, (void(__stdcall *)(void*))multiplyNaive, (void*)&para, , , 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 计算矩阵乘法的更多相关文章

  1. 使用shared memory 计算矩阵乘法 (其实并没有加速多少)

    #include "cuda_runtime.h" #include "device_launch_parameters.h" #include "d ...

  2. 向MapReduce转换:通过部分成绩计算矩阵乘法

    代码共分为四部分: <strong><span style="font-size:18px;">/*** * @author YangXin * @info ...

  3. 蓝桥杯 BASIC_17 矩阵乘法 (矩阵快速幂)

    问题描述 给定一个N阶矩阵A,输出A的M次幂(M是非负整数) 例如: A = 1 2 3 4 A的2次幂 7 10 15 22 输入格式 第一行是一个正整数N.M(1<=N<=30, 0& ...

  4. 有关CUBLAS中的矩阵乘法函数

    关于cuBLAS库中矩阵乘法相关的函数及其输入输出进行详细讨论. ▶ 涨姿势: ● cuBLAS中能用于运算矩阵乘法的函数有4个,分别是 cublasSgemm(单精度实数).cublasDgemm( ...

  5. OpenCL 矩阵乘法

    ▶ 矩阵乘法,按照书里的内容进行了几方面的优化,包括局部内存,矢量数据类型,寄存器,流水线等. ● 最直接的乘法.调用时 main.c 中使用 size_t globalSize[] = { rowA ...

  6. 矩阵乘法的运算量计算(华为OJ)

    题目地址: https://www.nowcoder.com/practice/15e41630514445719a942e004edc0a5b?tpId=37&&tqId=21293 ...

  7. CUDA 矩阵乘法终极优化指南

    作者:马骏 | 旷视 MegEngine 架构师 前言 单精度矩阵乘法(SGEMM)几乎是每一位学习 CUDA 的同学绕不开的案例,这个经典的计算密集型案例可以很好地展示 GPU 编程中常用的优化技巧 ...

  8. *HDU2254 矩阵乘法

    奥运 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submissi ...

  9. *HDU 1757 矩阵乘法

    A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

随机推荐

  1. Linux命令详解-help

    help命令顾名思义就是显示帮助信息的,它是个Bash内建命令,也只是用来显示Bash内建命令的帮助信息的(Display  helpful  information about builtin co ...

  2. UVA-10816 Travel in Desert (最小瓶颈最短路)

    题目大意:给一张无向图,图中的每条边都有两个权值,长度d和热度r.找出从起点到终点的一条最大热度最小的路径,如果这样的路径有多条,选择一个最短的. 题目分析:如果只考虑最小的最大热度,那么本题就是一个 ...

  3. echarta3 北京,上海地图

    1.首先你得到echarts官网下载js,建议下载完整代码,这样你就很容易根据我的路径找到beijing.js 2.把echarts.js和beijingi.js根据你的路径引对,然后就可以copy我 ...

  4. BST树、B树、B+树、B*树

    1. BST树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: ...

  5. 【hive】数据仓库层次设计

    转载 https://www.jianshu.com/p/849db358ec61

  6. 16Aspx源码论坛

    16Aspx源码论坛: http://bbs.16aspx.com/index.aspx

  7. 爱奇艺、腾讯、优酷、搜狐、芒果、乐视、PPTV、音悦台等VIP视频免费观看

    观看地址一:http://www.luoruiyuan.cn/pages/id-62_uid-2_btid-35.html 观看地址二:http://movie.luoruiyuan.cn/vip.h ...

  8. js实现trim()方法

    在面向对象编程里面去除字符串左右空格是很容易的事,可以使用trim().ltrim() 或 rtrim(),在jquery里面使用$.trim()也可以轻松的实现.但是在js中却没有这个方法.下面的实 ...

  9. # 20155214 2016-2017-2 《Java程序设计》第6周学习总结

    20155214 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 1.在Java中,输入/输出串流代表对象为java.io.InputStream,java. ...

  10. Oracle 通过dblink和job方式实现两个数据库表之间数据同步

    需求是需要将Database_A中的dev_test表中的数据同步到Database_B中的dev_test表中. 因为是通过Database_B去同步Database_A库中的数据,所以操作都建立在 ...