私はスラストの初心者です。すべての Thrust のプレゼンテーションと例は、ホスト コードのみを示しています。
自分のカーネルに device_vector を渡すことができるかどうか知りたいですか? どのように?はいの場合、カーネル/デバイス コード内で許可されている操作は何ですか?
もともと書かれていたように、Thrustは純粋にホスト側の抽象化です。カーネル内では使用できません。次のように、内部にカプセル化されたデバイスメモリthrust::device_vector
を独自のカーネルに渡すことができます。
thrust::device_vector< Foo > fooVector;
// Do something thrust-y with fooVector
Foo* fooArray = thrust::raw_pointer_cast( fooVector.data() );
// Pass raw array and its size to kernel
someKernelCall<<< x, y >>>( fooArray, fooVector.size() );
また、裸のcudaデバイスメモリポインタを使用してthrust :: device_ptrをインスタンス化することにより、thrustアルゴリズム内でthrustによって割り当てられていないデバイスメモリを使用することもできます。
@JackOLanternの回答に従って、4年半後に編集され、thrust 1.8は順次実行ポリシーを追加します。これは、デバイス上でスラストのアルゴリズムのシングルスレッドバージョンを実行できることを意味します。推力デバイスベクトルをカーネルに直接渡すことはまだ不可能であり、デバイスベクトルをデバイスコードで直接使用することはできないことに注意してください。
thrust::device
場合によっては、実行ポリシーを使用して、カーネルによって子グリッドとして並列推力実行を開始することも可能であることに注意してください。これには、個別のコンパイル/デバイスリンケージと、動的並列処理をサポートするハードウェアが必要です。これがすべての推力アルゴリズムで実際にサポートされているかどうかはわかりませんが、一部のアルゴリズムでは確かに機能します。
この質問に対する最新の回答を提供したいと思います。
Thrust 1.8 以降では、CUDA Thrust プリミティブをthrust::seq
実行ポリシーと組み合わせて、単一の CUDA スレッド内で (または単一の CPU スレッド内で) 順次実行できます。以下、一例を報告する。
スレッド内で並列実行が必要な場合は、カードが動的並列処理を有効にしていれば、スレッドブロック内から呼び出すことができるリダクション ルーチンを提供するCUBの使用を検討できます。
これがスラストの例です
#include <stdio.h>
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>
/********************/
/* CUDA ERROR CHECK */
/********************/
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
__global__ void test(float *d_A, int N) {
float sum = thrust::reduce(thrust::seq, d_A, d_A + N);
printf("Device side result = %f\n", sum);
}
int main() {
const int N = 16;
float *h_A = (float*)malloc(N * sizeof(float));
float sum = 0.f;
for (int i=0; i<N; i++) {
h_A[i] = i;
sum = sum + h_A[i];
}
printf("Host side result = %f\n", sum);
float *d_A; gpuErrchk(cudaMalloc((void**)&d_A, N * sizeof(float)));
gpuErrchk(cudaMemcpy(d_A, h_A, N * sizeof(float), cudaMemcpyHostToDevice));
test<<<1,1>>>(d_A, N);
}
はい、推力によって割り当て/処理されたデータを使用する場合は、割り当てられたデータの生のポインタを取得するだけです。
int * raw_ptr = thrust::raw_pointer_cast(dev_ptr);
カーネルに推力ベクトルを割り当てたい場合、私は試したことはありませんが、うまくいくとは思いません。また、うまくいく場合は、何のメリットもないと思います。