2012-09-14 20 views
11

私はC、C++、OpenCLが新しく、現時点でそれらを学ぶために最善を尽くしています。ここには、既存のC++関数があります。この関数は、CまたはC++バインディングのいずれかを使用してOpenCLに移植する方法を理解しようとしています。OpenCLカーネルにC++ベクタを渡してアクセスするには?

#include <vector> 

using namespace std; 

class Test { 

private: 

    double a; 
    vector<double> b; 
    vector<long> c; 
    vector<vector<double> > d; 

public: 

    double foo(long x, double y) { 
     // mathematical operations 
     // using x, y, a, b, c, d 
     // and also b.size() 
     // to calculate return value 
     return 0.0; 
    } 

}; 

私の質問は、この関数がバインディングとカーネルにアクセスするすべてのクラスメンバーを渡す方法です。私はスカラー値を渡す方法を理解していますが、わからないベクトル値はわかります。上記の各メンバーへのポインタを渡す方法や、OpenCLのビューがホストメモリと同期するようにそれらをメモリマップする方法はありますか?私の質問は以下の通りです。

  1. メンバーbとcを可変サイズのバインディングとカーネルに渡すにはどうすればよいですか?
  2. 2次元であるとすれば、どのようにメンバーdを渡すのですか?
  3. カーネル内からこれらのメンバーにアクセスするにはどうすればいいのですか?カーネルの引数のようにどのような型を宣言しますか?単に配列インデックス表記、つまりb [0]を使ってアクセスできますか?
  4. カーネル関数内でb.size()と同等の操作を呼び出すにはどうすればよいでしょうか?あるいは、余分な引数としてカーネルへのバインディングからサイズを渡すことはできませんか?それが変わるとどうなりますか?

私はCまたはC++のバインディングとカーネルコードのサンプルコードを参考にしていただきたいと思います。

多くのありがとうございます。

+10

'using namespace std;' - これをヘッダーではこれまでしないでください。 –

+0

@EdS。それはなぜでしょうか? – dominicbri7

+5

@ dominicbri7:ヘッダーを含む全員のグローバル名前空間を汚染しているためです。たぶん私は 'std'をグローバルな名前空間にインポートしたくないかもしれません。たぶんそこには正当な理由があります。あなたは私のために選択していません。 –

答えて

13
  1. OpenCLバッファを割り当ててCPUデータをコピーする必要があります。 OpenCLバッファのサイズは固定されているので、データサイズが変更された場合は再作成する必要があります。また、必要なメモリが少ない場合はサブセクションのみを使用します。例えば、bのためのバッファを作成し、同時にデバイスにすべてのデータをコピーします。

    cl_mem buffer_b = clCreateBuffer(
        context, // OpenCL context 
        CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, // Only read access from kernel, 
                  // copy data from host 
        sizeof(cl_double) * b.size(), // Buffer size in bytes 
        &b[0], // Pointer to data to copy 
        &errorcode); // Return code 
    

    直接ホストメモリ(CL_MEM_USE_HOST_PTR)をマッピングすることも可能であるが、これは上のいくつかの制限を課しバッファを作成した後のホストメモリへのアクセスを制御します。基本的に、ホストメモリには、現在マップしていないときにガベージが含まれている可能性があります。

  2. です。第2次元のベクトルのサイズは一貫して等しいか?次に、それらをOpenCLデバイスにアップロードするときにそれらを平坦化します。それ以外の場合は、より複雑になります。

  3. バッファ引数をカーネル内に__globalポインタとして宣言します。たとえば、__global double *bは、1で作成されたバッファに適しています。カーネル内の配列表記を使用して、バッファ内の個々の要素にアクセスできます。

  4. カーネル内からバッファサイズを問い合わせることができないため、手動で渡す必要があります。暗黙的にも起こりうる。作業項目の数がbのサイズと一致する場合あなたはまた、結果のためにメモリを割り当てる必要が

    __kernel void foo(long x, double y, double a, __global double* b, int b_size, 
            __global long* c, __global double* d, 
            __global double* result) { 
        // Here be dragons 
        *result = 0.0; 
    } 
    

    注:計算にすべてのデータにアクセスすることができ

カーネルは、次のようになります。必要な場合は、追加のサイズ引数を渡す必要があるかもしれません。

// Create/fill buffers 
// ... 

// Set arguments 
clSetKernelArg(kernel, 0, sizeof(cl_long), &x); 
clSetKernelArg(kernel, 1, sizeof(cl_double), &y); 
clSetKernelArg(kernel, 2, sizeof(cl_double), &a); 
clSetKernelArg(kernel, 3, sizeof(cl_mem), &b_buffer); 
cl_int b_size = b.size(); 
clSetKernelArg(kernel, 4, sizeof(cl_int), &b_size); 
clSetKernelArg(kernel, 5, sizeof(cl_mem), &c_buffer); 
clSetKernelArg(kernel, 6, sizeof(cl_mem), &d_buffer); 
clSetKernelArg(kernel, 7, sizeof(cl_mem), &result_buffer); 
// Enqueue kernel 
clEnqueueNDRangeKernel(queue, kernel, /* ... depends on your domain */); 

// Read back result 
cl_double result; 
clEnqueueReadBuffer(queue, result_buffer, CL_TRUE, 0, sizeof(cl_double), &result, 
        0, NULL, NULL); 
+0

ありがとうございます。それは大いに役立ちます。 2つの質問:(1)私の元のデータは、あなたが知っているようにすべてC++型である。しかし、上のコードではすべてのメモリ割り当てがcl_typesにあります。私は理由を理解する。しかし、b [1]にa [0]の値を加えるカーネルに2つの長いベクトルを渡すテストプログラムでは、これはすべての型が元のベクトル宣言を含むプログラム内のcl_typesである場合にのみ動作します。元のデータはC++型でなければなりません。私はここで何が欠けていますか? (2)上記のC++型として 'result'をどのように使うのですか? – junkie

+2

あなたは正しいです、私はそこにあるタイプに少しうんざりしていました。私のサンプルコードは、 'cl_long'が' long'と同じ型である場合にのみ機能します。同じでない場合は、デバイスにデータをアップロードする前に変換手順を実行する必要があります。 'cl_long'と' cl_double'は他のC++型であり、typedefです。おそらく既に 'double'であるので、' result'を直接使うことができます。 – reima

+0

Thx。私は私のテストプログラムでベクトルデータへのポインタを使用して動作しないことを確認することができます。変換の必要があるかもしれません(ベクトル/配列の2番目のセットを作成してそれにコピーしますか?)そして結果を長い変数に設定するとVSで "データの損失の可能性があります"という警告が表示されます。 cl_platform.hのcl_longは 'typedef signed __int64 cl_long;'に設定され、longは4バイトです。データを失うことなく長い間使用する方法はありませんか? – junkie

関連する問題