6

cuda カーネルでいくつかの仮想メソッドを実行したいのですが、同じカーネルでオブジェクトを作成する代わりに、ホストで作成して gpu メモリにコピーしたいと考えています。

カーネルでオブジェクトを正常に作成し、仮想メソッドを呼び出しています。オブジェクトをコピーするときに問題が発生します。明らかに仮想関数ポインターが偽物であるため、これは理にかなっています。何が起こるかは、単に「Cuda グリッドの起動に失敗しました」です。少なくともこれは Nsight の言うことです。しかし、SASS を見ると、仮想関数ポインターの逆参照でクラッシュします。これは理にかなっています。

もちろん、私は Cuda 4.2 を使用しており、適切なカードで「compute_30」を使用してコンパイルしています。

では、おすすめの行き方は?それとも、この機能は単にサポートされていないのでしょうか?

最初に別のカーネルを実行してダミーオブジェクトを作成し、仮想関数ポインターを抽出してオブジェクトをコピーする前に「パッチ」するという考えがありました。悲しいことに、これは実際には機能していません (まだ理解していません)。

PS これは実際にはこの質問の再実行であり、残念ながら完全には回答されていません。

編集 :

だから私は自分がやりたいことをする方法を見つけました。しかし、明確にするために:これはまったく答えや解決策ではありません。答えはすでに提供されています。これは単なる楽しみのためのハックです。

まず、仮想メソッドを呼び出すときに Cuda が何をしているかを見てみましょう。以下はデバッグ SASS です。

//R0 is the address of our object
LD.CG R0, [R0];  
IADD R0, R0, 0x4;  
NOP;  
MOV R0, R0;  
LD.CG R0, [R0];
...
IADD R0, RZ, R9;  
MOV R0, R0;  
LDC R0, c[0x2][R0];
...
BRX R0 - 0x5478

したがって、「c[0x2][INDEX]」がすべてのカーネルで一定であると仮定すると、カーネルを実行してこれを行うだけで、クラスのインデックスを取得できます。ここで、obj は、クラスの新しく作成されたオブジェクトです。

unsigned int index = *(unsigned int*)(*(unsigned int*)obj + 4);

次に、次のようなものを使用します。

struct entry
{
    unsigned int vfptr;// := &vfref, thats our value to store in an object
    int dummy;// := 1234, great for debugging
    unsigned int vfref;// := &dummy
    unsigned int index;
    char ClassName[256];//use it as a key for a dict
};

これをホストとデバイスのメモリ (メモリの場所はデバイスの場所) に保存し、ホストでは ClassName をオブジェクトのルックアップとして使用して「パッチを当てる」ことができます。

しかし、繰り返しになりますが、パフォーマンスに関しては、仮想関数はまったく優れていないため、これを深刻なものには使用しません。

4

1 に答える 1

6

あなたがやろうとしていることは、現在、CUDA コンパイラとランタイム (CUDA 5.0 の時点) ではサポートされていません。CUDA C Programming Guide v5.0 のセクション D.2.6.3 には次のように書かれています。

D.2.6.3 仮想機能

派生クラスの関数が基底クラスの仮想関数をオーバーライドする場合、オーバーライドされる関数とオーバーライドする関数の実行空間修飾子 (つまり、__host____device__) が一致する必要があります。

__global__仮想関数を持つクラスのオブジェクトを関数に引数として渡すことはできません。

仮想関数テーブルは、コンパイラによってグローバル メモリまたは定数メモリに配置されます。

クラスの機能とは別に、クラスのデータをカプセル化することをお勧めします。たとえば、データを構造体に格納します。これらのオブジェクトの配列を操作する予定がある場合は、データを配列の構造に格納します (パフォーマンスのために、この質問の範囲外)。を使用してホストにデータ構造を割り当て、cudaMalloc仮想メソッドでクラスを渡すのではなく、データを引数としてカーネルに渡します。

次に、デバイス上の仮想メソッドを使用してオブジェクトを構築します。仮想メソッドを持つクラスのコンストラクターは、デバイス ポインターのカーネル パラメーターを引数として受け取ります。その後、仮想デバイスメソッドは、デバイス データに対して操作できます。

デバイス上の 1 つのカーネルにデータを割り当て、デバイス上の別のカーネルでデータにアクセスできるようにするために、同じアプローチが機能します (繰り返しますが、仮想関数を持つクラスはカーネルへのパラメーターになることはできません)。

于 2012-10-03T07:46:34.663 に答える