1

Halide で extern 関数を使用しようとしています。私の文脈では、GPUでやりたいです。

opencl ステートメントを使用して AOT コンパイルでコンパイルします。もちろん、opencl は引き続き CPU を使用できるので、これを使用します。

halide_set_ocl_device_type("gpu");

今のところ、すべてが compute_root() でスケジュールされています。

最初の質問ですが、compute_root() と OpenCL gpu を使用した場合、私のプロセスは CopyHtoD と DtoH を使用してデバイス上で計算されますか? (または、ホスト バッファ上にあります)

2 番目の質問は、extern 関数に関連しています。一部のアルゴリズムが Halide にないため、一部の extern 呼び出しを使用します。外部呼び出し:

foo.define_extern("cool_foo", args, Float(32), 4);

外部取得: extern "C" int cool_foo(buffer_t * in, int w, int h, int z, buffer_t * out){ .. }

しかし、cool_foo 関数では、私の buffer_t はホスト メモリにのみロードされます。dev アドレスは 0 (デフォルト) です。

アルゴリズムの前にメモリをコピーしようとすると:

halide_copy_to_dev(NULL, &in);

それは何もしません。

デバイスメモリのみを利用可能にする場合:

in.host = NULL;

ホスト ポインタは null ですが、デバイス アドレスはまだ 0 です。

(私の場合、dev_dirty は true で、host_dirty は false)

何か案が?

EDIT(dshaletに答えるために)

私のコードの構造は次のとおりです。

CPU でデータを正しく解析します。--> GPU にバッファを送信 (halode_copy_to_dev を使用...) --> Halide 構造体に入力し、パラメータを読み取り、境界条件を追加 --> extern 関数に移動 -->...

extern 関数に有効な buffer_t がありません。すべてを compute_root() でスケジュールしますが、HL_TARGET=host-opencl を使用し、ocl を gpu に設定します。Halide に入る前に、デバイスのアドレスを読み取ることができ、問題ありません。

これが私のコードです:

Halide の前は、すべてが CPU のもの (ポインター) であり、それを GPU に転送しました。

buffer_t k = { 0, (uint8_t *) k_full, {w_k, h_k, num_patch_x * num_patch_y * 3}, {1, w_k, w_k * h_k}, {0}, sizeof(float), };
#if defined( USEGPU )
    // Transfer into GPU
    halide_copy_to_dev(NULL, &k);
    k.host_dirty = false;
    k.dev_dirty = true;
    //k.host = NULL; // It's k_full
#endif
halide_func(&k)

インサイド ハライド:

ImageParam ...
Func process;
process = halide_sub_func(k, width, height, k.channels());
process.compute_root();

...

Func halide_sub_func(ImageParam k, Expr width, Expr height, Expr patches)
{
    Func kBounded("kBounded"), kShifted("kShifted"), khat("khat"), khat_tuple("khat_tuple");
    kBounded = repeat_image(constant_exterior(k, 0.0f), 0, width, 0, height, 0, patches);
    kShifted(x, y, pi) = kBounded(x + k.width() / 2, y + k.height() / 2, pi);

    khat = extern_func(kShifted, width, height, patches);
    khat_tuple(x, y, pi) = Tuple(khat(0, x, y, pi), khat(1, x, y, pi));

    kShifted.compute_root();
    khat.compute_root();

    return khat_tuple;
}

外側のハライド (Extern 関数):

inline .... 
{
   //The buffer_t.dev and .host are 0 and null. I expect a null from the host, but the dev..
}
4

2 に答える 2

0

外部配列関数の境界推論プロトコルを知っていますか? これは、任意のバッファのホスト ポインタが NULL の場合に発生します。(簡単に言うと、この場合、NULL ホスト ポインターを持つ buffer_t 構造体のエクステント フィールドに入力する必要があり、それ以外は何もしません。) 既にそれを処理している場合は、上記を無視してください。

すべてのバッファでホスト ポインタが非 NULL であることをテストした場合は、halide_copy_to_dev の呼び出しが機能するはずです。バッファがどこから来たかに応じて、コピー部分を発生させるために、事前に host_dirty を明示的に true に設定する必要がある場合があります。(Halide がこれを正しく取得し、バッファーが CPU の前のパイプライン ステージから取得された場合は既に設定されていることを願っています。しかし、バッファーが Halide の外部の何かから取得された場合、ダーティ ビットはおそらく初期化から false であると思われます。halide_dev_malloc を設定する必要があるようです。デバイスメモリを割り当てる場合は dev_dirty ですが、現在は割り当てていません。)

ハライド_コピー_to_devが最初に行うことはハライド_dev_mallocを呼び出すことであるため、ハライド_コピー_to_devの呼び出し後にdevフィールドが入力されることを期待します。ハライド_dev_malloc を自分で明示的に呼び出し、host_dirty を設定してからハライド_コピー_to_dev を呼び出してみてください。

前のステージはホスト上にありますか、それとも GPU 上にありますか? GPU 上にある場合は、入力バッファーも GPU 上にあると思います。

この API には作業が必要です。私は役立つ何かの最初のリファクタリングの最中ですが、最終的には buffer_t 構造を変更する必要があります。ほとんどの機能を動作させることは可能ですが、host_dirty および dev_dirty ビットを変更し、halide_dev* API を正しい方法で呼び出す必要があります。お待ちいただいてありがとうございます。

于 2014-10-08T22:25:52.683 に答える