2016-04-26 102 views
2

我想學習如何使用CUDA與推力,我已經看到了一些代碼,其中的printf函數似乎從設備使用。使用推力與printf/cout

考慮以下代碼:

#include <thrust/host_vector.h> 
#include <thrust/device_vector.h> 
#include <cstdio> 

struct functor 
{ 
    __host__ __device__ 
    void operator()(int val) 
    { 
     printf("Call for value : %d\n", val); 
    } 
}; 

int main() 
{ 
    thrust::host_vector<int> cpu_vec(100); 
    for(int i = 0 ; i < 100 ; ++i) 
     cpu_vec[i] = i; 
    thrust::device_vector<int> cuda_vec = cpu_vec; //transfer to GPU 
    thrust::for_each(cuda_vec.begin(),cuda_vec.end(),functor()); 
} 

這看上去一切正常,並打印100次消息「的價值呼喚:」後跟一個數字。

現在如果我有iostream的,用C++基於流的等效

std::cout << "Call for value : " << val << std::endl; 

我得到合輯NVCC警告和編譯程序將不打印任何東西取代的printf線。

warning: address of a host variable "std::cout" cannot be directly taken in a device function 
warning: calling a __host__ function from a __host__ __device__ function is not allowed 
warning: calling a __host__ function("std::basic_ostream<char, std::char_traits<char> >::operator <<") from a __host__ __device__ function("functor::operator()") is not allowed 
  1. 爲什麼它與printf的工作嗎?
  2. 爲什麼它不是與cout一起工作?
  3. 實際在GPU上運行的是什麼?我猜想,至少發送到標準輸出需要一些CPU的工作。
+1

'printf'作爲'__device__'函數「重載」,而'cout'不是。您需要明確的「重載」打印功能,因爲您需要正確處理輸出緩衝區。看一看'simplePrintf'的例子,你會感覺到你爲什麼需要顯式重載以及如何做到這一點。由於'cout'只是'__host__'函數,'nvcc'不能編譯它。 – JackOLantern

回答

8
  1. 爲什麼它與printf的工作嗎?

由於NVIDIA添加運行時支持用於在內核printf進行支撐裝置ABI(計算能力> = 2.0)中的所有硬件。設備代碼中存在主機printf的模板過載,該設備代碼提供(幾乎)標準C風格printf功能。您必須在設備代碼中包含cstdiostdio.h以使此機制生效。

  1. 爲什麼它不適用於cout?

因爲NVIDIA還沒有實施任何形式的C++的iostream式I/O的CUDA設備運行時間內的支持。

  1. 實際在GPU上運行的是什麼?

的裝置運行時保持用於內核代碼寫入到內核執行期間經由printf的調用一個FIFO緩衝器。設備緩衝區由CUDA驅動程序複製並在內核執行結束時回顯給stdout。確切的啓發式和機制沒有記錄,但我會假設格式字符串和輸出存儲到FIFO緩衝區,然後由CPU驅動程序解析,然後通過內核啓動API的某種回調打印。運行時API提供了一個function用於控制printf FIFO的大小。