我现在开始使用CUDA并且不得不承认我对C API有点失望。我理解选择C的原因但是语言基于C ++而不是,有几个方面会更简单,例如:设备内存分配(通过cudaMalloc
)。
我的计划是自己这样做,使用带有展示位置operator new
的重载new
和RAII(两个备选方案)。我想知道到目前为止我是否有任何警告。代码似乎可以工作,但我仍然想知道潜在的内存泄漏。
RAII 代码的用法如下:
CudaArray<float> device_data(SIZE);
// Use `device_data` as if it were a raw pointer.
也许一个类在这种情况下是过度的(特别是因为你仍然必须使用cudaMemcpy
,这个类只包含RAII)所以另一种方法是 placement new
:
float* device_data = new (cudaDevice) float[SIZE];
// Use `device_data` …
operator delete [](device_data, cudaDevice);
此处,cudaDevice
仅用作触发重载的标记。但是,由于在正常位置new
这表示放置,我发现语法奇怪地一致,甚至可能更适合使用类。
我很欣赏各种批评。是否有人知道是否计划在下一版本的CUDA中使用这个方向(正如我所听到的那样,它将改进其C ++支持,无论它们的意思是什么)。
所以,我的问题实际上有三个:
new
在语义上是否正确?它会泄漏内存吗?// 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&);
};
关于这里使用的单身人士:是的,我知道它的缺点。但是,这些与此无关。我在这里需要的只是一个不可复制的小型标签。其他所有内容(即多线程注意事项,初始化时间)都不适用。
答案 0 :(得分:7)
与此同时,还有一些进一步的发展(在CUDA API方面没有那么多,但至少在尝试类似STL的CUDA数据管理方法的项目方面)。
最值得注意的是NVIDIA研究项目:thrust
答案 1 :(得分:5)
我会选择新的方法。然后我将定义一个符合std :: allocator&lt;&gt;的类。接口。理论上,您可以将此类作为模板参数传递给std :: vector&lt;&gt;和std :: map&lt;&gt;等等。
请注意,我听说做这些事情充满困难,但至少你会以这种方式学习更多关于STL的知识。而且您不需要重新发明容器和算法。
答案 2 :(得分:2)
有几个项目尝试类似的东西,例如CUDPP。
然而,与此同时,我已经实现了自己的分配器,它运行良好且直截了当(> 95%样板代码)。
答案 3 :(得分:1)
有没有人有关于未来CUDA发展的信息,这是朝着这个方向发展的(让我们面对它:C ++ s * ck中的C接口)?
是的,我做过类似的事情:
https://github.com/eyalroz/cuda-api-wrappers/
nVIDIA的CUDA运行时API适用于C和C ++代码。因此,它使用C风格的API,较低的公分母(除了模板化函数重载之外还有一些值得注意的例外)。
这个围绕Runtime API的包装器库旨在让我们拥抱C ++的许多功能(包括一些C ++ 11)来使用运行时API - 但不会降低表达性或提高抽象级别(如在例如Thrust库中)。使用cuda-api-wrappers,你仍然拥有你的设备,流,事件等等 - 但是用更多的C ++ - 习惯的方式来使用它们会更方便。