私は現在 CUDA を使い始めており、C API に少しがっかりしていることを認めなければなりません。C を選択した理由は理解できますが、代わりに言語が C++ に基づいていた場合、デバイス メモリの割り当て (経由cudaMalloc
) など、いくつかの側面がより単純になったはずです。
operator new
私の計画は、オーバーロードされた配置new
と RAII (2 つの選択肢)を使用して、これを自分で行うことでした。今まで気付かなかった注意点があるのではないかと思っています。コードは機能しているように見えますが、メモリ リークの可能性についてまだ疑問に思っています。
RAIIコードの使用法は次のようになります。
CudaArray<float> device_data(SIZE);
// Use `device_data` as if it were a raw pointer.
おそらく、このコンテキストではクラスがやり過ぎなので(特に、cudaMemcpy
RAIIをカプセル化するだけのクラスを使用する必要があるため)、他のアプローチは配置new
になります:
float* device_data = new (cudaDevice) float[SIZE];
// Use `device_data` …
operator delete [](device_data, cudaDevice);
ここでは、cudaDevice
単にオーバーロードをトリガーするタグとして機能します。ただし、通常の配置でnew
はこれは配置を示しているため、構文が奇妙に一貫しており、おそらくクラスを使用するよりも好ましいとさえ思います。
あらゆる種類の批判をいただければ幸いです。この方向の何かがCUDAの次のバージョンで計画されているかどうか誰かがおそらく知っていますか(私が聞いたように、それが意味するものは何でも、C++サポートが改善されます)。
したがって、私の質問は実際には 3 つあります。
- プレースメントの
new
オーバーロードは意味的に正しいですか? それはメモリをリークしますか? - この一般的な方向に進む将来の CUDA 開発に関する情報を誰かが持っていますか (それに直面しましょう: C++ s*ck の C インターフェイス)?
- これを一貫した方法でさらに進めるにはどうすればよいですか (他にも考慮すべき API があります。たとえば、デバイス メモリだけでなく、定数メモリ ストアとテクスチャ メモリもあります)。
// Singleton tag for CUDA device memory placement.
struct CudaDevice {
static CudaDevice const& get() { return instance; }
private:
static CudaDevice const instance;
CudaDevice() { }
CudaDevice(CudaDevice const&);
CudaDevice& operator =(CudaDevice const&);
} const& cudaDevice = CudaDevice::get();
CudaDevice const CudaDevice::instance;
inline void* operator new [](std::size_t nbytes, CudaDevice const&) {
void* ret;
cudaMalloc(&ret, nbytes);
return ret;
}
inline void operator delete [](void* p, CudaDevice const&) throw() {
cudaFree(p);
}
template <typename T>
class CudaArray {
public:
explicit
CudaArray(std::size_t size) : size(size), data(new (cudaDevice) T[size]) { }
operator T* () { return data; }
~CudaArray() {
operator delete [](data, cudaDevice);
}
private:
std::size_t const size;
T* const data;
CudaArray(CudaArray const&);
CudaArray& operator =(CudaArray const&);
};
ここで採用されているシングルトンについて: はい、その欠点は認識しています。ただし、これらはこのコンテキストには関係ありません。ここで必要だったのは、コピーできない小さなタイプのタグだけでした。他のすべて (つまり、マルチスレッドの考慮事項、初期化の時間) は適用されません。