簡體   English   中英

如何像C ++ const / constexpr一樣定義CUDA設備常量?

[英]How to define CUDA device constant like a C++ const/constexpr?

在.cu文件中,我在全局范圍內嘗試了以下內容(即不在函數中):

__device__ static const double cdInf = HUGE_VAL / 4;

並得到nvcc錯誤:

error : dynamic initialization is not supported for __device__, __constant__ and __shared__ variables.

如果可能的話,如何在設備上定義C ++ const / constexpr?

注1: #define不僅僅是出於美學原因,而且因為在實踐中表達式更復雜並且涉及內部數據類型,而不僅僅是雙重。 因此,每次在每個CUDA線程中調用構造函數都會太昂貴。

注2:我懷疑__constant__的性能,因為它不是編譯時常量,而是像用cudaMemcpyToSymbol編寫的變量。

使用constexpr __device__函數:

#include <stdio.h>
__device__ constexpr double cdInf() { return HUGE_VAL / 4; }
__global__ void print_cdinf() { printf("in kernel, cdInf() is %lf\n", cdInf()); }
int main() { print_cdinf<<<1, 1>>>(); return 0; }

PTX應該是這樣的:

.visible .entry print_cdinf()(

)
{
        .reg .b64       %SP;
        .reg .b64       %SPL;
        .reg .b32       %r<2>;
        .reg .b64       %rd<7>;


        mov.u64         %rd6, __local_depot0;
        cvta.local.u64  %SP, %rd6;
        add.u64         %rd1, %SP, 0;
        cvta.to.local.u64       %rd2, %rd1;
        mov.u64         %rd3, 9218868437227405312;
        st.local.u64    [%rd2], %rd3;
        mov.u64         %rd4, $str;
        cvta.global.u64         %rd5, %rd4;
        // Callseq Start 0
        {
        .reg .b32 temp_param_reg;
        // <end>}
        .param .b64 param0;
        st.param.b64    [param0+0], %rd5;
        .param .b64 param1;
        st.param.b64    [param1+0], %rd1;
        .param .b32 retval0;
        call.uni (retval0), 
        vprintf, 
        (
        param0, 
        param1
        );
        ld.param.b32    %r1, [retval0+0];

        //{
        }// Callseq End 0
        ret;
}

沒有constexpr功能的代碼。 您也可以使用constexpr __host__函數,但這在CUDA 7中是實驗性的:使用nvcc命令行選項似乎是--expt-relaxed-constexpr在此處查看更多詳細信息(感謝@harrism)。

要使您顯示的代碼按預期編譯和工作,您需要在運行時初始化變量,而不是編譯時。 要執行此操作,請向cudaMemcpyToSymbol添加主機端調用,例如:

__device__ double cdInf;

// ...

double val = HUGE_VAL / 4
cudaMemcpyToSymbol(cdInf, &val, sizeof(double));

但是,對於單個值,將其作為內核參數傳遞似乎更為合理。 編譯器將自動將參數存儲在所有支持的體系結構的常量內存中,並且存在“自由”常量高速緩存廣播機制,這應該使得在運行時訪問該值的成本可以忽略不計。

要初始化它,您必須使用cudaMemcpyToSymbol 它不是編譯時常量,而是存儲在器件的常量存儲器中,並且與全局存儲器相比具有一些優勢。 來自CUDA blogspot:

對於半warp的所有線程,只要所有線程讀取相同的地址,從常量高速緩存讀取的速度與從寄存器讀取的速度一樣快。 半個warp中的線程對不同地址的訪問被序列化,因此成本與半warp中所有線程讀取的不同地址的數量成線性比例。

您不需要使用const ,也不能使用它。 它不是c ++常量,因為您需要通過cudaMemcpyToSymbol修改它。 因此,至少從c ++的角度來看,它不是一個“真正的”常數。 但它在設備內核中的行為類似於常量,因為您只能通過僅可從主機調用的cudaMemcpyToSymbol來修改它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM