[英]CUDA C++ Templating of Kernel Parameter
我试图基于一个布尔变量来模拟一个CUDA内核(如下所示: 我应该用'if'语句统一两个类似的内核,冒着性能损失的风险吗? )但是我不断收到编译错误,说我的函数是不是模板。 我认为我只是遗漏了一些显而易见的东西,所以非常令人沮丧。
以下不起作用:
util.cuh
#include "kernels.cuh"
//Utility functions
kernels.cuh
#ifndef KERNELS
#define KERNELS
template<bool approx>
__global__ void kernel(...params...);
#endif
kernels.cu
template<bool approx>
__global__ void kernel(...params...)
{
if(approx)
{
//Approximate calculation
}
else
{
//Exact calculation
}
}
template __global__ void kernel<false>(...params...); //Error occurs here
main.cu
#include "kernels.cuh"
kernel<false><<<dimGrid,dimBlock>>>(...params...);
以下DOES工作:
util.cuh
#include "kernels.cuh"
//Utility functions
kernels.cuh
#ifndef KERNELS
#define KERNELS
template<bool approx>
__global__ void kernel(...params...);
template<bool approx>
__global__ void kernel(...params...)
{
if(approx)
{
//Approximate calculation
}
else
{
//Exact calculation
}
}
#endif
main.cu
#include "kernels.cuh"
kernel<false><<<dimGrid,dimBlock>>>(...params...);
如果我扔进去
template __global__ void kernel<false>(...params...);
在kernels.cuh结束时它也有效。
我收到以下错误(均指上面标记的行):
kernel is not a template
invalid explicit instantiation declaration
如果它有所不同,我会在一行中编译所有.cu文件,例如:
nvcc -O3 -arch=sm_21 -I. main.cu kernels.cu -o program
在模板实例化时,所有显式特化声明必须是可见的。 您的显式专业化声明仅在kernels.cu转换单元中可见,但在main.cu中不可见。
以下代码确实正常工作(除了在显式实例化指令中添加__global__
限定符)。
#include<cuda.h>
#include<cuda_runtime.h>
#include<stdio.h>
#include<conio.h>
template<bool approx>
__global__ void kernel()
{
if(approx)
{
printf("True branch\n");
}
else
{
printf("False branch\n");
}
}
template __global__ void kernel<false>();
int main(void) {
kernel<false><<<1,1>>>();
getch();
return 0;
}
编辑
在C ++中,在遇到函数的显式实例化之前,不会编译模板化函数。 从这个角度来看,现在完全支持模板的CUDA的行为与C ++完全相同。
举一个具体的例子,当编译器找到类似的东西时
template<class T>
__global__ void kernel(...params...)
{
...
T a;
...
}
它只检查函数语法,但不生成任何对象代码。 因此,如果您使用上面的单个模板化函数编译文件,您将拥有一个“空”对象文件。 这是合理的,因为编译器将不知道哪种类型分配给a
。
只有在遇到函数模板的显式实例化时,编译器才会生成对象代码。 在那一刻,这是模板化函数的编译如何工作,这种行为引入了对多文件项目的限制:模板化函数的实现(定义)必须与其声明在同一个文件中。 所以,你可以不包含在界面分开kernels.cuh
从分离的头文件kernels.cu
,这是最主要的原因,为什么你的代码的第一个版本不编译。 因此,您必须包括接口和实现在使用模板的任何文件,即您必须在main.cu
两者kernels.cuh
和kernels.cu
。
由于没有显式实例化就不会生成代码,因此编译器可以容忍在项目中包含多个声明和定义的同一模板文件不止一次,而不会产生链接错误。
有几个关于在C ++中使用模板的教程。 白痴的C ++模板指南 - 第1部分 ,除了令人讨厌的标题之外,还将为您提供该主题的逐步介绍。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.