2017-03-22 87 views
1

在CUDA文檔中,我發現cudaDeviceGetAttribute是__host__ __device__函數。所以我想我可以在我的__global__函數中調用它來獲取我的設備的一些屬性。可悲的是,它似乎意味着一些不同,因爲如果我將它放入__device__函數並從我的全局函數中調用此函數,我會收到一個編譯錯誤事件。我無法從__device__函數調用__host__ __device__函數嗎?

是否可以在我的GPU上調用cudaDeviceGetAttribute?或者__host__ __device__是什麼意思?

這裏是我的源代碼:

__device__ void GetAttributes(int* unique) 
{ 
    cudaDeviceAttr attr = cudaDevAttrMaxThreadsPerBlock; 
    cudaDeviceGetAttribute(unique, attr, 0); 
} 


__global__ void ClockTest(int* a, int* b, long* return_time, int* unique) 
{ 
    clock_t start = clock(); 

    //some complex calculations 

    *a = *a + *b; 
    *b = *a + *a; 

    GetAttributes(unique); 

    *a = *a + *b - *a; 

    clock_t end = clock(); 
    *return_time = end - start; 
} 

int main() 
{ 
    int a = 2; 
    int b = 3; 
    long time = 0; 
    int uni; 

    int* dev_a; 
    int* dev_b; 
    long* dev_time; 
    int* unique; 

    for (int i = 0; i < 10; ++i) { 

     cudaMalloc(&dev_a, sizeof(int)); 
     cudaMalloc(&dev_b, sizeof(int)); 
     cudaMalloc(&dev_time, sizeof(long)); 
     cudaMalloc(&unique, sizeof(int)); 

     cudaMemcpy(dev_a, &a, sizeof(int), cudaMemcpyHostToDevice); 
     cudaMemcpy(dev_b, &b, sizeof(int), cudaMemcpyHostToDevice); 

     ClockTest <<<1,1>>>(dev_a, dev_b, dev_time, unique); 

     cudaMemcpy(&a, dev_a, sizeof(int), cudaMemcpyDeviceToHost); 
     cudaMemcpy(&time, dev_time, sizeof(long), cudaMemcpyDeviceToHost); 
     cudaMemcpy(&uni, unique, sizeof(int), cudaMemcpyDeviceToHost); 

     cudaFree(&dev_a); 
     cudaFree(&dev_b); 
     cudaFree(&dev_time); 
     cudaFree(&unique); 

     printf("%d\n", time); 
     printf("unique: %d\n", uni); 

     cudaDeviceReset(); 
    } 

    return 0; 
} 
+0

爲什麼要在CUDA代碼中獲取該信息?爲什麼你不能從CPU調用並傳遞到GPU? –

+0

我知道我可以從CPU傳遞它,但是對於我的項目,出於安全原因,必須將信息收集在設備中。 –

回答

6

編輯:對不起,我以前的答案是不正確的。在nvcc似乎有問題(見下文)。

cudaDeviceGetAttribute可以在設備代碼中正常工作,這裏是K20X,CUDA 8.0.61一個樣例:

$ cat t1305.cu 
#include <stdio.h> 

__global__ void tkernel(){ 

    int val; 
    cudaError_t err = cudaDeviceGetAttribute(&val, cudaDevAttrMaxThreadsPerBlock, 0); 
    printf("err = %d, %s\n", err, cudaGetErrorString(err)); 
    printf("val = %d\n", val); 

} 


int main(){ 

    tkernel<<<1,1>>>(); 
    cudaDeviceSynchronize(); 
} 


$ nvcc -arch=sm_35 -o t1305 t1305.cu -rdc=true -lcudadevrt 
$ cuda-memcheck ./t1305 
========= CUDA-MEMCHECK 
err = 0, no error 
val = 1024 
========= ERROR SUMMARY: 0 errors 
$ 

various runtime API functions supported for use in device code。 對於支持的運行時的API函數,這是通常必要的:

  1. 編譯用於CC 3.5或更高的器件
  2. 與重定位裝置代碼編譯針對CUDA設備運行庫
  • 鏈路

    此外,您的代碼還有一些其他編碼錯誤,因爲我們不會將指針的地址傳遞給cudaFree,而只是指針本身。

    對於該特定功能注意事項:

    1. 似乎有在,如果該設備運行時的API調用,而不在內核代碼的任何其它運行時API調用中使用的CUDA編譯器的一個問題,則代碼世代不會正確發生。此時的解決方法是確保您的內核至少包含一個其他cuda運行時API調用。在我上面的示例中,我使用cudaGetErrorString,但您可以使用cudaDeviceSynchronize()或其他任何東西,我想。我提交了一個內部的NVIDIA錯誤報告這個問題。

    2. 在編程指南的CDP部分支持的設備運行時API調用列表中似乎存在文檔錯誤(上面的鏈接)。函數cudaGetDeviceProperty不存在,但我相信它應該參考cudaDeviceGetAttribute。我已經提交了一個內部NVIDIA錯誤的文檔錯誤。

  • +1

    我已經更新了我的答案 - 它有一些錯誤。 –

    +0

    羅伯特,我認爲你的答案應該分解成一個單獨的問題+回答關於從設備代碼調用運行時API函數的一般問題,在這裏你應該只提及bug和一般問題的鏈接+答案。這也將允許我們重新命名該問題來具體提及cudaDeviceGetAttribute()。如果你願意,我不介意自己做。 – einpoklum

    +0

    由於OP:1.沒有證明正確的CUDA錯誤檢查(在任何情況下都會標記問題)2.未提供實際的編譯命令3.未指示它們在哪個設備上運行4.未指示是否我的最新消息解決了他們遇到的問題,我不同意以這個答案的不同方向。你提到的兩個目的就足夠了。當然,歡迎您提出您希望在SO上提出的任何問題。在* nvcc中似乎*確實是一個錯誤,但實際上並不清楚它是OP問題的根源。 –

    相關問題