[英]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.