私は基本的なコードを書くことによって CUDA を学ぼうとしています。うまくいけば、既存の C++ コードを (研究用に) CUDA に変換するためのより良い立場に立つことができます。
かなりの数の複素数操作を行う必要があるため、GPU カーネルで複素数の配列を実数で乗算するこの非常に基本的なコードを作成しました。
#include <complex>
#include <iostream>
#include <cmath>
#include "cuda.h"
#include "math.h"
#include "cuComplex.h"
#define n 5
using namespace std;
#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 func( double *s, cuDoubleComplex *j, cuDoubleComplex *calc ) {
int tid = blockIdx.x;
calc[tid] = cuCmul(j[tid], make_cuDoubleComplex(*s, 0));
}
int main( void ) {
cuDoubleComplex calc[n+1], *dev_j, *dev_calc;
double *dev_s, s[n+1] = { 2.0, 2.0, 2.0, 2.0, 2.0 };
//complex<double> j[n+1]
cuDoubleComplex j[n+1];
for (int i = 1; i <= n; i++) {
j[i] = make_cuDoubleComplex(0, 5);
cout << "\nJ cout = " << cuCreal(j[i]) << ", " << cuCimag(j[i]);
}
// allocate the memory on the GPU
cudaMalloc( (void**)&dev_s, (n+1) * sizeof(double) );
cudaMalloc( (void**)&dev_j, (n+1) * sizeof(double) );
cudaMalloc( (void**)&dev_calc, (n+1) * sizeof(double) );
cudaMemcpy( dev_s, s, (n+1) * sizeof(double), cudaMemcpyHostToDevice );
cudaMemcpy( dev_j, j, (n+1) * sizeof(double), cudaMemcpyHostToDevice );
func<<<n,1>>>( dev_s, dev_j, dev_calc );
//kernel<<<1,1>>>(a_d);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaMemcpy(calc, dev_calc, (n+1) * sizeof(double), cudaMemcpyDeviceToHost) );
//cudaMemcpy( calc, dev_calc, (n+1) * sizeof(double), cudaMemcpyDeviceToHost );
for (int i = 1; i <= n; i++) {
cout << "\nCALC cout = " << cuCreal(calc[i]) << ", " << cuCimag(calc[i]);
}
return 0;
}
最終的な答えは間違っています。期待値が得られない他のいくつかの場所も特定しました。
1) 次のコード行の後に、'j' のすべての要素に対して (0, 5i) の複雑な double 配列が必要でした。しかし、私はすべて0を取得しています。何故ですか?
j[i] = make_cuDoubleComplex(0, 5);
2) cout を使用して配列を印刷できないのはなぜですか? 以下に示すコード行では、次のエラーが発生します。これらのオペランドに一致する演算子 "<<" はありません。printfを使用せずにこれを修正するにはどうすればよいですか?
cout << "\nJ = " << j[i];
3) GPU 関数 'func' は、最終的な答えとして (0, 10i) の配列を提供する必要があり、次のようなランダムな値を提供します。
CALC = -1.#QNAN0
CALC = -1.#QNAN0
CALC = -9255963134931783100000000...000.. etc
CALC = -9255963134931783100000000...000.. etc
4) 私の実際の研究では、複素数配列 'j' は cuDoubleComplex ではなく、complex(double) の形式で与えられます。関数 'func' を使用して、複合 (double) の 'j' 配列に同様の操作を行うことはできますか? そうでない場合、どのような選択肢がありますか?
よく説明できたと思いますが、追加の質問があれば遠慮なくお尋ねください。C++ だけでなく CUDA も初めてなので、よろしくお願いします :D