2017-11-20 11 views
0

私は、CUDAのデバイスポインタでstd :: unique_ptrを使用して遊んでいることを考えていました。現在のC++ 11のunique_ptrをcudaMallocと組み合わせて使用​​できるかどうか疑問に思っていました。私はそれが通常のmalloc(Is it possible to use a C++ smart pointers together with C's malloc?)で使用できることを知っていますが、cudaMallocは関数のreturn文でポインタを返しません。代わりに、エラーコードを返します。ポインタは参照で返されます。unique_ptrとcudaMallocの使用

このblog postは、次のような手法をお勧めします。

auto deleter=[&](float* ptr){ cudaFree(ptr); }; 
std::unique_ptr<float[], decltype(deleter)> d_in(new float[size], deleter); 
cudaMalloc((void **) &d_in, size * sizeof(float)); 

質問:はしかし、私はこれが(つまりd_in(new float[size], deleter);)削除されることは決してありませんホストメモリを作成することを心配しますか? new float[size]が実際にホストメモリを生成しないか、またはオーバーライドされていないかぎりですか?上記が実際に動作しない場合、私自身のcudaMallocラッパーの動作を定義できますか? - ポインタをunique_ptrに渡す?

何かのように:

void* myCudaMalloc(size_t mySize){ 
    void * p; 
    checkCUDAerrorMacro(cudaMalloc((void**) &p, size);) 
    return p; 
} 

... 

auto deleter=[](float* ptr){ cudaFree(ptr); }; 
std::unique_ptr<float[], decltype(deleter)> d_in(myCudaMalloc(size_t mySize), deleter); 

答えて

1

いくつかの作業の後、私はそれの3つのバージョンをテストする方法を考え出した - TL; DRのブログ記事のバージョン(V1)がリーク確かにありませんが、それはdoesnのように微調整することができます「T(V2)と改善(V3):

共通コード:

template <typename Deleter> 
using unique_p = std::unique_ptr<float[], Deleter>; 

constexpr int length = 20; 

V1:(ブログ記事で推奨されているもの)

void version1(){ 
    auto deleter = [](float* ptr) { cudaFree(ptr); std::cout<<"\nDeleted1\n"; }; 
    unique_p<decltype(deleter)> d_in(new float[length],deleter); 
    cudaMalloc((void **) &d_in, length * sizeof(float)); 

    ... 
} 

V2:

void version2(){ 
    auto deleter = [](float* ptr) { cudaFree(ptr); std::cout<<"\nDeleted2\n"; }; 
    unique_p<decltype(deleter)> d_in(nullptr,deleter); 
    cudaMalloc((void **) &d_in, length * sizeof(float)); 

    ... 
} 

V3(上記と同様、しかしnullptrとD_IN初期化):(cudaMallocで初期化ポインタを "採用" D_IN)

void version3(){ 
    auto myCudaMalloc = [](size_t mySize) { void* ptr; cudaMalloc((void**)&ptr, mySize); return ptr; }; 
    auto deleter = [](float* ptr) { cudaFree(ptr); std::cout<<"\nDeleted3\n"; }; 
    unique_p<decltype(deleter)> d_in((float*)myCudaMalloc(length*sizeof(float)),deleter); 

    ... 
} 

すべて3適切なデバイスのポインタを作成します。しかし、バージョン1では、確実にホストメモリがリークします(valgrindを使用し、cuda警告が表示されないでテストされました:Valgrind and CUDA: Are reported leaks real?)。 v2もv3もホストメモリをリークしません。 cuda-memcheckはまた、いずれのバージョンのデバイス側メモリリークもないことを確認しました。

バージョン2と3の間では、unique_ptrがポインターを所有していることを明確にし、unique_ptrコンストラクターのnewmallocのイディオムに従います。また、構築関数/ lambdaを一度定義してから何度も繰り返し使用することができるので、コード行が少なくなります。 (NVCC -std = C++ 14でコンパイル)

========================

完全なテストコード:

#include <cuda_runtime.h> 
#include <memory> 
#include <iostream> 

template <typename Deleter> 
using unique_p = std::unique_ptr<float[], Deleter>; 

__global__ void printArray(float * d_in, int num){ 
    for(int i = 0; i < num; i++){ printf("%f\t",d_in[i]); } 
    printf("\n"); 

} 

struct myDeleter{ 
    void operator()(float* ptr){ cudaFree(ptr); std::cout<<"\nDeleted\n"; } 
}; 

constexpr int length = 20; 

void version1(){ 
    auto deleter = [](float* ptr) { cudaFree(ptr); std::cout<<"\nDeleted1\n"; }; 
    unique_p<decltype(deleter)> d_in(new float[length],deleter); 
    cudaMalloc((void **) &d_in, length * sizeof(float)); 

    std::unique_ptr<float[]> h_out(new float[length]); 

    for(int i = 0; i < length; i++){ h_out[i] = i; } 

    cudaMemcpy(d_in.get(), h_out.get(),length*sizeof(float),cudaMemcpyHostToDevice); 


    printArray<<<1,1>>>(d_in.get(),length); 
} 

void version2(){ 
    auto deleter = [](float* ptr) { cudaFree(ptr); std::cout<<"\nDeleted2\n"; }; 
    unique_p<decltype(deleter)> d_in(nullptr,deleter); 
    cudaMalloc((void **) &d_in, length * sizeof(float)); 

    std::unique_ptr<float[]> h_out(new float[length]); 

    for(int i = 0; i < length; i++){ h_out[i] = i; } 

    cudaMemcpy(d_in.get(), h_out.get(),length*sizeof(float),cudaMemcpyHostToDevice); 


    printArray<<<1,1>>>(d_in.get(),length); 
} 


void version3(){ 
    auto myCudaMalloc = [](size_t mySize) { void* ptr; cudaMalloc((void**)&ptr, mySize); return ptr; }; 
    auto deleter = [](float* ptr) { cudaFree(ptr); std::cout<<"\nDeleted3\n"; }; 
    unique_p<decltype(deleter)> d_in((float*)myCudaMalloc(length*sizeof(float)),deleter); 
    //unique_p<myDeleter> d_in((float*)myCudaMalloc(20*sizeof(float))); 

    std::unique_ptr<float[]> h_out(new float[length]); 
    for(int i = 0; i < length; i++){ h_out[i] = i; } 

    cudaMemcpy(d_in.get(), h_out.get(),length*sizeof(float),cudaMemcpyHostToDevice); 

    printArray<<<1,1>>>(d_in.get(),length); 
} 

int main(){ 

    version1(); 
    version2(); 
    version3(); 

    cudaDeviceReset(); 
    return 0; 
} 
関連する問題