我正在尝试在cuda中编写一个简化函数(这是一个练习,我知道我正在做的事情已被其他人做得更好),它采用二进制关联运算符和数组并减少数组使用运营商。
我在如何传递这个功能方面遇到了困难。我已经将hostOp()编写为基于主机的示例,它可以正常工作。
deviceOp()通过显式调用fminf()来处理第一个语句,但是当我调用function参数时,存在非法的内存访问错误。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std; //for brevity
__device__ float g_d_a = 9, g_d_b = 5;
float g_h_a = 9, g_h_b = 5;
template<typename argT, typename funcT>
__global__
void deviceOp(funcT op){
argT result = fminf(g_d_a, g_d_b); //works fine
printf("static function result: %f\n", result);
result = op(g_d_a,g_d_b); //illegal memory access
printf("template function result: %f\n", result);
}
template<typename argT, typename funcT>
void hostOp(funcT op){
argT result = op(g_h_a, g_h_b);
printf("template function result: %f\n", result);
}
int main(int argc, char* argv[]){
hostOp<float>(min<float>); //works fine
deviceOp<float><<<1,1>>>(fminf);
cudaDeviceSynchronize();
cout<<cudaGetErrorString(cudaGetLastError())<<endl;
}
输出:
host function result: 5.000000
static function result: 5.000000
an illegal memory access was encountered
假设我没有做一些非常愚蠢的事情,我应该如何将fminf传递给deviceOp,以便没有非法的内存访问?
如果我做的事情非常愚蠢,那么更好的方法是什么?
答案 0 :(得分:1)
要在设备上调用的函数必须使用__device__
(或__global__
,如果您希望它是内核)进行修饰。 nvcc
编译器驱动程序将分离主机和设备代码,并在从设备代码调用(即编译)时使用设备编译的函数版本,否则将使用主机版本。
这个结构存在问题:
deviceOp<float><<<1,1>>>(fminf);
虽然可能并不明显,但这基本上都是主机代码。是的,它是启动内核(通过主机代码的库调用的基础序列),但它在技术上是主机代码。因此,fminf
功能地址&#34;已捕获&#34;这里将是fminf
函数的主机版本,即使设备版本可用(通过CUDA math.h
,您实际上并不包括)。
解决这个问题的一种典型虽然笨拙的方法是捕捉&#34;设备代码中的设备地址 ,然后将其作为参数传递给内核。
如果要传递可在编译时推导出的函数地址,您也可以(稍微)将此过程短路,并使用稍微不同的模板技术。 this answer中介绍了这些概念。
以下是使用设备代码中的&#34;捕获功能地址修改的代码的完整工作示例&#34;方法:
$ cat t1176.cu
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std; //for brevity
__device__ float g_d_a = 9, g_d_b = 5;
float g_h_a = 9, g_h_b = 5;
template<typename argT, typename funcT>
__global__
void deviceOp(funcT op){
argT result = fminf(g_d_a, g_d_b); //works fine
printf("static function result: %f\n", result);
result = op(g_d_a,g_d_b); //illegal memory access
printf("template function result: %f\n", result);
}
__device__ float (*my_fminf)(float, float) = fminf; // "capture" device function address
template<typename argT, typename funcT>
void hostOp(funcT op){
argT result = op(g_h_a, g_h_b);
printf("template function result: %f\n", result);
}
int main(int argc, char* argv[]){
hostOp<float>(min<float>); //works fine
float (*h_fminf)(float, float);
cudaMemcpyFromSymbol(&h_fminf, my_fminf, sizeof(void *));
deviceOp<float><<<1,1>>>(h_fminf);
cudaDeviceSynchronize();
cout<<cudaGetErrorString(cudaGetLastError())<<endl;
}
$ nvcc -o t1176 t1176.cu
$ cuda-memcheck ./t1176
========= CUDA-MEMCHECK
template function result: 5.000000
static function result: 5.000000
template function result: 5.000000
no error
========= ERROR SUMMARY: 0 errors
$