粒子輸送の簡単なモンテカルロ シミュレーションを書いています。私のアプローチは、CUDA 用のカーネルを作成し、それを Mathematica 関数として実行することです。
カーネル:
#include "curand_kernel.h"
#include "math.h"
extern "C" __global__ void monteCarlo(Real_t *transmission, mint seed, mint pathN) {
curandState rngState;
int index = threadIdx.x + blockIdx.x*blockDim.x;
curand_init(seed, index, 0, &rngState);
if (index < pathN) {
//-------------start one packet run----------------------
float packetWeight = 1.0;
int m = 0;
while(packetWeight > 0.0){
//MONTE CARLO CODE
// Test: still in the sample?
if(z_coordinate > sampleThickness){
packetWeight = 0;
z_coordinate = sampleThickness;
transmission[index]=1;
}
}
}
//-------------end one packet run------------------------
}
}
Mathematica コード:
Needs["CUDALink`"];
cudaBM = CUDAFunctionLoad[code,
"monteCarlo", {{_Real, "Output"}, _Integer, _Integer}, 256,
"UnmangleCode" -> False];
pathN = 100000;
result = 0; (*count for transmitted particles*)
For[j = 0, j < 10, j++,
buffer = CUDAMemoryAllocate["Float", 100000];
cudaBM[buffer, 1490, pathN];
resultOneRun = Total[CUDAMemoryGet[buffer]];
result = result + resultOneRun;
];
これまでのところすべてが機能しているように見えますが、CUDA を使用しない純粋な C コードと比較した速度の向上はごくわずかです。2 つの問題があります。
- curand_init() 関数は、すべての計算ステップの開始時にすべてのスレッドによって実行されます -> すべてのスレッドに対してこの関数を 1 回呼び出すことはできますか?
- カーネルはMathematica に非常に大きな実数の配列(100 000)を返します.CUDA のボトルネックは、GPU と CPU 間のチャネル帯域幅であることはわかっています。リストのすべての要素の合計のみが必要なため、GPU でリスト要素の合計を計算し、実数を 1 つだけ CPU に送信する方が効率的です。