有没有更好/更清洁/更优雅的方式来malloc和免费在cuda?

时间:2016-09-08 15:58:23

标签: c++ cuda malloc free

我正在尝试cudaMalloc一堆设备指针,如果任何mallocs没有工作,请优雅地退出。我有正常运行的代码 - 但是因为我必须cudaFreeFree所有以前我所做过的事情,如果一个人失败了。所以现在我想知道是否有更简洁的方法来实现这一目标。显然,我无法释放一些没有马洛克风格的东西 - 这肯定会引发问题。

下面是我想要使代码变得更优雅的代码片段。

    //define device pointers
    float d_norm, *d_dut, *d_stdt, *d_gamma, *d_zeta;

    //allocate space on the device for the vectors and answer
    if (cudaMalloc(&d_norm, sizeof(float)*vSize) != cudaSuccess) {
            std::cout << "failed malloc";
            return;
    };

    if (cudaMalloc(&d_data, sizeof(float)*vSize) != cudaSuccess) {
            std::cout << "failed malloc";
            cudaFree(d_norm);
            return;
    };

    if (cudaMalloc(&d_stdt, sizeof(float)*wSize) != cudaSuccess) {
            std::cout << "failed malloc";
            cudaFree(d_norm);
            cudaFree(d_data);
            return;
    };

    if (cudaMalloc(&d_gamma, sizeof(float)*vSize) != cudaSuccess) {
            std::cout << "failed malloc";
            cudaFree(d_norm);
            cudaFree(d_dut);
            cudaFree(d_stdt);
            return;
    };

    if (cudaMalloc(&d_zeta, sizeof(float)*w) != cudaSuccess) {
            std::cout << "failed malloc";
            cudaFree(d_norm);
            cudaFree(d_dut);
            cudaFree(d_stdt);
            cudaFree(d_gamma);
            return;
    };

这是一个缩短版本,但您可以看到它是如何继续构建的。实际上我试图malloc约15个阵列。它开始变得丑陋 - 但它正常工作。

思考?

5 个答案:

答案 0 :(得分:4)

  • 您可以使用自定义删除器将它们包装到unique_ptr中。 (C ++ 11)

  • 或者只是在成功分配并释放向量中的所有指针时添加到一个向量。

关于unique_ptr的例子:

#include <iostream>
#include <memory>
using namespace std;

void nativeFree(float* p);
float* nativeAlloc(float value);

class NativePointerDeleter{
public:
   void operator()(float* p)const{nativeFree(p);}
};


int main(){
   using pointer_type = unique_ptr<float,decltype(&nativeFree)>;
   using pointer_type_2 = unique_ptr<float,NativePointerDeleter>;

   pointer_type ptr(nativeAlloc(1),nativeFree);
   if(!ptr)return 0;

   pointer_type_2 ptr2(nativeAlloc(2));//no need to provide deleter
   if(!ptr2)return 0;

   pointer_type ptr3(nullptr,nativeFree);//simulate a fail alloc
   if(!ptr3)return 0;

   /*Do Some Work*/

   //now one can return without care about all the pointers
   return 0;
}

void nativeFree(float* p){
   cout << "release " << *p << '\n';
   delete p;
}
float* nativeAlloc(float value){
   return new float(value);
}

答案 1 :(得分:2)

一些可能性:

  1. cudaDeviceReset()将释放所有设备分配,而无需运行指针列表。

  2. 如果您打算退出(应用程序),则无论如何都会在应用程序终止时自动释放所有设备分配。 cuda运行时检测与应用程序的设备上下文相关联的进程的终止,并在该点擦除该上下文。因此,如果您只是要退出,那么不执行任何cudaFree()操作应该是安全的。

答案 2 :(得分:2)

最初在所有指针中存储nullptrfree对空指针没有任何影响。

int* p1 = nullptr;
int* p2 = nullptr;
int* p3 = nullptr;

if (!(p1 = allocate()))
  goto EXIT_BLOCK;
if (!(p2 = allocate()))
  goto EXIT_BLOCK;
if (!(p3 = allocate()))
  goto EXIT_BLOCK;

EXIT_BLOCK:
free(p3); free(p2); free(p1);

答案 3 :(得分:1)

问题标记为C ++,因此这是一个C ++解决方案

通常的做法是在构造函数中获取资源并在析构函数中释放。这个想法是,在任何情况下都可以保证通过调用析构函数来释放资源。整洁的副作用是在范围的最后自动调用析构函数,因此当不再使用资源时,您根本不需要做任何事情来释放资源。见RAII

在资源角色中,可能有各种内存类型,文件句柄,套接字等.CUDA设备内存也不例外。

我也不鼓励你编写自己的资源拥有类,并建议使用库。 thrust::device_vector可能是使用最广泛的设备内存容器。 Thrust库是CUDA工具包的一部分。

答案 4 :(得分:1)

是。如果你使用(我的)CUDA Modern-C++ API wrapper library,你可以使用唯一的指针,它们将在它们的生命周期结束时释放。您的代码将仅变为以下内容:

auto current_device = cuda::device::current::get();
auto d_dut   = cuda::memory::device::make_unique<float[]>(current_device, vSize);
auto d_stdt  = cuda::memory::device::make_unique<float[]>(current_device, vSize);
auto d_gamma = cuda::memory::device::make_unique<float[]>(current_device, vSize);
auto d_zeta  = cuda::memory::device::make_unique<float[]>(current_device, vSize);

但请注意,您可以只分配一次,然后将其他指针放在适当的偏移处。