簡體   English   中英

無法從靜態初始化代碼啟動CUDA內核

[英]Trouble launching CUDA kernels from static initialization code

我有一個在其構造函數中調用內核的類,如下所示:

“ ScalarField.h”

#include <iostream>

    void ERROR_CHECK(cudaError_t err,const char * msg) {
        if(err!=cudaSuccess) {
            std::cout << msg << " : " << cudaGetErrorString(err) << std::endl;
            std::exit(-1);
        }
    }

    class ScalarField {
    public:
        float* array;
        int dimension;

        ScalarField(int dim): dimension(dim) {
            std::cout << "Scalar Field" << std::endl;
            ERROR_CHECK(cudaMalloc(&array, dim*sizeof(float)),"cudaMalloc");
        }
    };

“ classA.h”

#include "ScalarField.h"


static __global__ void KernelSetScalarField(ScalarField v) {
    int index = threadIdx.x + blockIdx.x * blockDim.x;
    if (index < v.dimension) v.array[index] = 0.0f;
}

class A {
public:
    ScalarField v;

    A(): v(ScalarField(3)) {
        std::cout << "Class A" << std::endl;
        KernelSetScalarField<<<1, 32>>>(v);
        ERROR_CHECK(cudaGetLastError(),"Kernel");
    }
};

“ main.cu”

#include "classA.h"

A a_object;

int main() {
    std::cout << "Main" << std::endl;
    return 0;
}

如果我在main( A a_object; )上實例化此類,則不會出錯。 但是,如果我在main外部實例化它,則在定義它之后( class A {...} a_object; ),當內核啟動時,我會收到“無效的設備函數”錯誤。 為什么會這樣呢?

編輯

更新了代碼以提供更完整的示例。

編輯2

遵循Raxvan在評論中的建議,我想說的是,我在ScalarField構造函數中使用的dimensions變量也在main之外(在其他所有類中)定義了(在另一個類中)。 可能是解釋嗎? 調試器雖然顯示了正確的dimensions值。

簡短版本:

在主class A之外實例化class A時出現問題的根本原因是,在調用class A的構造函數之前,沒有運行用內核初始化CUDA運行時庫所需的特定掛鈎例程。 發生這種情況是因為無法保證在C ++執行模型中實例化和初始化靜態對象的順序。 在初始化進行CUDA設置的全局范圍對象之前,將實例化全局范圍類。 您的內核代碼永遠不會在調用之前加載到上下文中,並且會導致運行時錯誤。

據我所知,這是CUDA運行時API的真正限制,而不是用戶代碼中容易修復的問題。 在簡單的示例中,您可以將內核調用替換為對cudaMemset的調用或基於非符號的運行時API memset函數之一,它將起作用。 此問題完全限於通過運行時API在運行時加載的用戶內核或設備符號。 因此,空的默認構造函數也可以解決您的問題。 從設計的角度來看,我會懷疑在構造函數中調用內核的任何模式。 為類GPU設置/拆卸添加一種不依賴默認構造函數或析構函數的特定方法,恕我直言,這將是一種更加整潔且不易出錯的設計。

詳細:

有一個內部生成的例程( __cudaRegisterFatBinary ),必須運行該例程才能使用CUDA驅動程序API加載和注冊任何運行時API程序的fatbin有效負載中包含的內核,紋理和靜態定義的設備符號,然后才能正確調用內核。 這是運行時API的“惰性”上下文初始化功能的一部分。 您可以自己確認以下內容:

這是您發布的修訂示例的gdb跟蹤。 注意,我在__cudaRegisterFatBinary插入了一個斷點,在您的靜態A構造函數被調用且內核啟動失敗之前,還沒有達到斷點:

talonmies@box:~$ gdb a.out 
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/talonmies/a.out...done.
(gdb) break '__cudaRegisterFatBinary' 
Breakpoint 1 at 0x403180
(gdb) run
Starting program: /home/talonmies/a.out 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Scalar Field
[New Thread 0x7ffff5a63700 (LWP 10774)]
Class A
Kernel : invalid device function 
[Thread 0x7ffff5a63700 (LWP 10774) exited]
[Inferior 1 (process 10771) exited with code 0377]

以下是相同的程序,此時用A內實例化main (這是保證它們執行懶惰設置的對象已被初始化后發生的):

talonmies@box:~$ cat main.cu
#include "classA.h"


int main() {
    A a_object;
    std::cout << "Main" << std::endl;
    return 0;
}

talonmies@box:~$ nvcc --keep -arch=sm_30 -g main.cu
talonmies@box:~$ gdb a.out 
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/talonmies/a.out...done.
(gdb) break '__cudaRegisterFatBinary' 
Breakpoint 1 at 0x403180
(gdb) run
Starting program: /home/talonmies/a.out 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000000000403180 in __cudaRegisterFatBinary ()
(gdb) cont
Continuing.
Scalar Field
[New Thread 0x7ffff5a63700 (LWP 11084)]
Class A
Main
[Thread 0x7ffff5a63700 (LWP 11084) exited]
[Inferior 1 (process 11081) exited normally]

如果這確實對您來說是一個嚴重的問題,我建議您與NVIDIA開發人員支持聯系並提出錯誤報告。

暫無
暫無

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

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