2016-04-26 13 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; 

とprintfのラインを交換する場合

は、今私はNVCCからコンパイル警告を取得し、コンパイルされたプログラムは、何も印刷されません。

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デバイスABI(計算能力> = 2.0)をサポートするすべてのハードウェアのために、カーネルのprintfのランタイムサポートを追加したので。 (ほとんど)標準Cスタイルのprintf機能を提供するデバイスコードにホストprintfのテンプレートオーバーロードがあります。このメカニズムを動作させるには、デバイスコードにまたはstdio.hを含める必要があります。

  1. なぜそれがcoutで動作しないのですか?

NVIDIAがCUDAデバイスランタイム内のC++のiostreamスタイルI/Oサポートの任意のフォームを実装していないので。

  1. 実際にGPUで実行されるのは何ですか?

デバイスランタイムは、カーネル実行中のprintfコールを介しに書き込むカーネルコードのFIFOバッファを維持します。デバイスバッファはCUDAドライバによってコピーされ、カーネルの実行終了時にstdoutにエコーされます。正確なヒューリスティックスとメカニズムは説明されていませんが、フォーマット文字列と出力はFIFOバッファに格納され、CPUドライバによって解析され、カーネル起動APIからある種のコールバックを介して出力されると仮定します。ランタイムAPIは、printf FIFOのサイズを制御するためのfunctionを提供します。

関連する問題