CURANDライブラリを使う [Device API]

CUDA Toolkit 3.2から,CURANDという疑似乱数ジェネレータライブラリが導入されました.GPUによる乱数の生成を行えるライブラリです.

CURANDは,2つのAPIカテゴリから構成されています.

Host API
ホストからの使用を目的としたAPI群.Device APIの上に構築されている.
Device API
バイスからの使用を目的としたAPI群.要するに__device__修飾された関数群.

Host APIについてはCURANDライブラリを使う [Host API] - fjnlの生存記録のような何かを参照してください.

以下,サンプルコード.モンテカルロ法による円周率を求めるプログラムです.エラー処理の類は省略しています.

// -*- c++ -*-
#include <numeric>
#include <iostream>
#include <curand_kernel.h>

__global__
void monte_pi(unsigned long seed, int n_try, float* out) {
    int id = blockIdx.x * blockDim.x + threadIdx.x;
    curandState s;

    curand_init(seed, id, 0, &s);

    int inside = 0;
    for (int i = 0; i < n_try; ++i) {
        float x = curand_uniform(&s);
        float y = curand_uniform(&s);
        if (x * x + y * y < 1) {
            inside++;
        }
    }

    out[id] = inside / static_cast<float>(n_try);
}

int main() {
    cudaSetDeviceFlags(cudaDeviceMapHost);

    int const n_thread = 256;
    int const n_block = 256;
    int const n = n_thread * n_block;
    int const n_try = 1000;

    float* out;
    float* d_out;

    cudaHostAlloc(&out, n * sizeof(float), cudaHostAllocMapped);
    cudaHostGetDevicePointer(&d_out, out, 0);

    monte_pi<<<n_block, n_thread>>>(0, n_try, d_out);

    cudaThreadSynchronize();

    std::cout
        << 4.0 * std::accumulate(out, out + n, 0.0) / n
        << std::endl;

    cudaFreeHost(out);

    return 0;
}