2016-10-27 5 views
1

Quelle serait la manière la plus simple de vérifier quelles entités (et leur taille) qui ont été allouées avec cudaMalloc() résident actuellement sur un périphérique GPU? Je veux trouver une fuite de mémoire dans une fonction, que si elle est juste appelée une fois et sortie, il n'y a pas de fuite de mémoire (vérifiée via cuda-memcheck), mais si elle est appelée plusieurs fois, l'empreinte mémoire devient de plus en plus grande. Nsight Visual Profiler semble trop complexe pour ce que je demande et cuda-memcheck ne trouve aucune fuite!Vérification des entités résidant actuellement dans la mémoire GPU

+2

L'API CUDA runtime ne fournit pas de méthode pour obtenir une liste des allocations en cours. Si c'est ce que vous voulez, vous devrez construire une fonction wrapper (pour 'cudaMalloc') qui les enregistre pour vous dans une table gérée par l'utilisateur. Cette question ressemble à un problème X-Y pour moi. Vous pourriez obtenir une meilleure aide si vous décrivez le problème réel que vous rencontrez plus en détail. Par exemple, s'agit-il d'une fonction hôte ou d'une fonction de périphérique que vous appelez? Quelle méthode utilisez-vous pour déterminer l'empreinte mémoire? Encore mieux si vous pouvez fournir un [mcve] qui démontre le problème. –

Répondre

2

Il n'existe aucun moyen de le faire avec les API CUDA. Si vous voulez le faire, vous devrez créer votre propre système d'instrumentation qui enveloppe les API d'allocation/désallocation de mémoire CUDA que votre code appelle. pourrait ressembler à la mise en œuvre plus simple ceci:

#include <iostream> 
#include <vector> 
#include <algorithm> 

typedef std::pair<void*, size_t> mrecord; 
struct mymemory 
{ 
    std::vector<mrecord> mstack; 

    mymemory() {}; 

    cudaError_t cudaMalloc(void** p, size_t sz); 
    cudaError_t cudaFree(void* p); 
    void print_stack(); 

}; 

cudaError_t mymemory::cudaMalloc(void** p, size_t sz) 
{ 
    cudaError_t ret = ::cudaMalloc(p, sz); 

    if (ret == cudaSuccess) { 
     mstack.push_back(mrecord(*p,sz)); 
    } 
    return ret; 
}; 


cudaError_t mymemory::cudaFree(void* p) 
{ 
    cudaError_t ret = ::cudaFree(p); 

    if (ret == cudaSuccess) { 
     auto rit = std::find_if(mstack.begin(), mstack.end(), 
           [&](const mrecord& r){ return r.first == p; }); 
     if (rit != mstack.end()) { 
      mstack.erase(rit); 
     } 
    } 
    return ret; 
}; 

void mymemory::print_stack() 
{ 
    auto it = mstack.begin(); 
    for(; it != mstack.end(); ++it) { 
     mrecord rec = *it; 
     std::cout << rec.first << " : " << rec.second << std::endl; 
    } 
} 


int main(void) 
{ 
    const int nallocs = 10; 
    void* pointers[nallocs]; 

    mymemory mdebug; 
    for(int i=0; i<nallocs; ++i) { 
     mdebug.cudaMalloc(&pointers[i], 4<<i); 
    } 
    std::cout << "After Allocation" << std::endl; 
    mdebug.print_stack(); 

    mdebug.cudaFree(pointers[1]); 
    mdebug.cudaFree(pointers[7]); 
    mdebug.cudaFree(pointers[8]); 
    mdebug.cudaFree(0); 

    std::cout << "After Deallocation" << std::endl; 
    mdebug.print_stack(); 

    return 0; 
} 

[Attention: seulement très légèrement testé et nécessaire 11 C++ soutien du compilateur]

qui ferait ceci:

~/SO$ nvcc -std=c++11 -g -arch=sm_52 instrumentation.cu 
~/SO$ ./a.out 
After Allocation 
0x705e40000 : 4 
0x705e40200 : 8 
0x705e40400 : 16 
0x705e40600 : 32 
0x705e40800 : 64 
0x705e40a00 : 128 
0x705e40c00 : 256 
0x705e40e00 : 512 
0x705e41000 : 1024 
0x705f40000 : 2048 
After Deallocation 
0x705e40000 : 4 
0x705e40400 : 16 
0x705e40600 : 32 
0x705e40800 : 64 
0x705e40a00 : 128 
0x705e40c00 : 256 
0x705f40000 : 2048 

Cela pourrait suffire à comprendre quelles allocations de mémoire fuient. Mais sachez que la gestion de la mémoire sur le GPU n'est pas aussi prévisible que vous pourriez le croire, et vous devez être prudent lors du diagnostic d'une fuite de mémoire sur la base de la quantité de mémoire libre que le périphérique signale à un moment donné instant. Voir this question pour plus de détails.