▶ 使用函数 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. JavaScript返回上一页和返回上一级页面并刷新

    JavaScript返回上一页和刷新当前页 window.history.go(-1); //返回上一页 window.history.back(); //返回上一页 //如果要强行刷新的话就是:wi ...

  2. AppCrawler自动化遍历使用详解(版本2.1.0 )

    AppCrawle是自动遍历的app爬虫工具,最大的特点是灵活性,实现:对整个APP的所有可点击元素进行遍历点击.   优点: 1.支持android和iOS, 支持真机和模拟器 2.可通过配置来设定 ...

  3. bzoj3862

    题解: 这一道题目和模板有不同的地方就是在于可以修改只有一条边和i相邻 于是我们还要记录与这个点相邻的点有没有改变 代码: #pragma GCC optimize(2) #include<bi ...

  4. 关于java的讲座有感

    今天晚上闲着看了下李兴华老师的java + 大数据 讲座.做一个屌爆的全能型技术人才,感觉有点收获,有兴趣的可以看看 链接地址:https://study.163.com/course/introdu ...

  5. SpringMvc中的Interceptor拦截器的学习

    拦截器是SpringMvc框架中常用的一个东东,它跟Filter相似,但是也有区别,以前也没用过,今天看到就顺便学习了一下. SpirngMvc中的Interceptor主要是通过HandlerInt ...

  6. Leetcode 1021. Remove Outermost Parentheses

    括号匹配想到用栈来做: class Solution: def removeOuterParentheses(self, S: str) -> str: size=len(S) if size= ...

  7. iOS-----使用GCD实现多线程

    使用GCD实现多线程 GCD的两个核心概念如下: 队列 队列负责管理开发者提交的任务,GCD队列始终以FIFO(先进先出)的方式来处理任务---但 由于任务的执行时间并不相同,因此先处理的任务并一定先 ...

  8. 开始yaf之旅

    目录结构 + public //网站根目录 - index.php //入口文件 - .htaccess //重写规则 + conf |- application.ini //配置文件 applica ...

  9. I.MX6 Linux U-boot 环境变量解析

    /********************************************************************************** * I.MX6 Linux U- ...

  10. ScrollView的基本用法丶代理方法

    属性: - (void)viewDidLoad { [super viewDidLoad]; _scrollView.backgroundColor = [UIColor redColor]; //设 ...