2012-05-01 18 views
8

Sto tentando di allocare memoria del dispositivo, copiare su di esso, eseguire i calcoli sulla GPU, copiare i risultati indietro e quindi liberare la memoria del dispositivo che ho assegnato. Volevo essere sicuro di non andare oltre il limite e volevo vedere se avrei avuto abbastanza memoria nello spazio di memoria condiviso per scaricare alcuni array.Perché CudaFree non sembra liberare memoria?

Quando alloco memoria del dispositivo, non vengono restituiti errori. Quando uso cudaMemGetInfo per verificare la quantità di memoria allocata, sembra che uno cudaMalloc non abbia allocato memoria. Anche quando provo a liberare la memoria, sembra che sia stato liberato solo un puntatore.

Sto usando l'interfaccia MATLAB Mexfunction per impostare la memoria della GPU e avviare il kernel. A questo punto, non sto nemmeno chiamando nel kernel e sto solo ritornando indietro una matrice unitaria per i risultati.

cudaError_t cudaErr; 
size_t freeMem = 0; 
size_t totalMem = 0; 
size_t allocMem = 0; 
cudaMemGetInfo(&freeMem, &totalMem); 
mexPrintf("Memory avaliable: Free: %lu, Total: %lu\n",freeMem, totalMem); 

/* Pointers for the device memory */ 
double *devicePulseDelay, *deviceTarDistance, *deviceScattDistance, *deviceScatterers; 
double *deviceReceivedReal, *deviceReceivedImag; 

/* Allocate memory on the device for the arrays. */ 
mexPrintf("Allocating memory.\n"); 
cudaErr = cudaMalloc((void **) &devicePulseDelay, sizeof(double)*512); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not allocate memory to devicePulseDelay\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("devicePulseDelay: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMalloc((void **) &deviceTarDistance, sizeof(double)*512); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not allocate memory to deviceTarDistance\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceTarDistance: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMalloc((void **) &deviceScattDistance, sizeof(double)*999*512); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not allocate memory to deviceScattDistance\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceScattDistance: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMalloc((void **) &deviceScatterers, sizeof(double)*999); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not allocate memory to deviceScatterers\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceScatterers: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMalloc((void **) &deviceReceivedReal, sizeof(double)*999*512); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not allocate memory to deviceReceivedReal\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceReceivedReal: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMalloc((void **) &deviceReceivedImag, sizeof(double)*999*512); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not allocate memory to deviceReceivedImag\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceReceivedImag: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n", allocMem, totalMem,(freeMem - allocMem)); 

/* copy the input arrays across to the device */ 
mexPrintf("\nCopying memory.\n"); 
cudaErr = cudaMemcpy(devicePulseDelay, pulseDelay, sizeof(double)*512,cudaMemcpyHostToDevice); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not copy to devicePulseDelay\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("devicePulseDelay: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMemcpy(deviceTarDistance, tarDistance, sizeof(double)*512,cudaMemcpyHostToDevice); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not copy to deviceTarDistance\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceTarDistance: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMemcpy(deviceScattDistance, scattDistance, sizeof(double)*999*512,cudaMemcpyHostToDevice); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not copy to deviceScattDistance\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceScattDistance: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMemcpy(deviceScatterers, scatterers, sizeof(double)*999,cudaMemcpyHostToDevice); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not copy to deviceScatterers\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceScatterers: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 

/* call the kernel */ 
// launchKernel<<<1,512>>>(........); 

/* retireve the output */ 
cudaErr = cudaMemcpy(receivedReal, deviceReceivedReal, sizeof(double)*512*512,cudaMemcpyDeviceToHost); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not copy to receivedReal\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("receivedReal: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 
cudaErr = cudaMemcpy(receivedImag, deviceReceivedImag, sizeof(double)*512*512,cudaMemcpyDeviceToHost); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could not copy to receivedImag\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("receivedImag: Memory avaliable: Free: %lu, Total: %lu, Consumed: %lu\n",allocMem, totalMem,(freeMem - allocMem)); 

/* free the memory. */ 
mexPrintf("\nFree'ing memory.\n"); 
cudaMemGetInfo(&freeMem, &totalMem); 
mexPrintf("Before freeing: Free %lu, Total: %lu\n", freeMem, totalMem); 
cudaErr = cudaFree(devicePulseDelay); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could free devicePulseDelay\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("devicePulseDelay: Memory avaliable: Free: %lu, Total: %lu, Free'd: %lu\n",allocMem, totalMem,(allocMem - freeMem)); 
cudaErr = cudaFree(deviceTarDistance); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could free deviceTarDistance\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceTarDistance: Memory avaliable: Free: %lu, Total: %lu, Free'd: %lu\n",allocMem, totalMem,(allocMem - freeMem)); 
cudaErr = cudaFree(deviceScattDistance); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could free deviceScattDistance\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceScattDistance: Memory avaliable: Free: %lu, Total: %lu, Free'd: %lu\n",allocMem, totalMem,(allocMem - freeMem)); 
cudaErr = cudaFree(deviceScatterers); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could free deviceScatterers\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceScatterers: Memory avaliable: Free: %lu, Total: %lu, Free'd: %lu\n",allocMem, totalMem,(allocMem - freeMem)); 
cudaErr = cudaFree(deviceReceivedReal); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could free deviceReceivedReal\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceReceivedReal: Memory avaliable: Free: %lu, Total: %lu, Free'd: %lu\n",allocMem, totalMem,(allocMem - freeMem)); 
cudaErr = cudaFree(deviceReceivedImag); 
if (cudaErr != cudaSuccess) 
{ 
    mexPrintf("could free deviceReceivedImag\n"); 
    mexPrintf("Error: %s\n",cudaGetErrorString(cudaErr)); 
} 
cudaMemGetInfo(&allocMem, &totalMem); 
mexPrintf("deviceReceivedImag: Memory avaliable: Free: %lu, Total: %lu, Free'd: %lu\n",allocMem, totalMem,(allocMem - freeMem)); 

Ecco l'output di questo:

 
Memory avaliable: Free: 2523959296, Total: 2818572288 
Allocating memory. 
devicePulseDelay: Memory avaliable: Free: 2522910720, Total: 2818572288, Consumed: 1048576 
deviceTarDistance: Memory avaliable: Free: 2522910720, Total: 2818572288, Consumed: 1048576 
deviceScattDistance: Memory avaliable: Free: 2518716416, Total: 2818572288, Consumed: 5242880 
deviceScatterers: Memory avaliable: Free: 2517667840, Total: 2818572288, Consumed: 6291456 
deviceReceivedReal: Memory avaliable: Free: 2515570688, Total: 2818572288, Consumed: 8388608 
deviceReceivedImag: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 

Copying memory. 
devicePulseDelay: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 
deviceTarDistance: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 
deviceScattDistance: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 
deviceScatterers: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 
receivedReal: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 
receivedImag: Memory avaliable: Free: 2513473536, Total: 2818572288, Consumed: 10485760 

Free'ing memory. 
Before freeing: Free 2513473536, Total: 2818572288 
devicePulseDelay: Memory avaliable: Free: 2513473536, Total: 2818572288, Free'd: 0 
deviceTarDistance: Memory avaliable: Free: 2513473536, Total: 2818572288, Free'd: 0 
deviceScattDistance: Memory avaliable: Free: 2513473536, Total: 2818572288, Free'd: 0 
deviceScatterers: Memory avaliable: Free: 2514522112, Total: 2818572288, Free'd: 1048576 
deviceReceivedReal: Memory avaliable: Free: 2514522112, Total: 2818572288, Free'd: 1048576 
deviceReceivedImag: Memory avaliable: Free: 2514522112, Total: 2818572288, Free'd: 1048576 

mi sento come se ci fosse qualcosa di ovvio che mi manca. Qualcuno può aiutare a spiegare cosa sta succedendo?

MODIFICA: la piattaforma è Windows 7 con una scheda GPu Tesla C2050.

+0

Su quale piattaforma è in esecuzione questo codice? – talonmies

+0

Provare a azzerare i valori di allocMem e totalMem prima di ogni chiamata a cudaMemGetInfo() e controllare il valore restituito da cudaMemGetInfo(). –

+0

azzerando l'allocMem e il totalMem prima di ogni chiamata a cudaMemGetInfo() non ha fatto alcuna differenza. Anche le chiamate cudaMemGetInfo non hanno restituito alcun errore. Cordiali saluti, la mia piattaforma è Windows 7 su una scheda GPU Tesla C2050. –

risposta

11

È un equivoco piuttosto comune che malloc riceva direttamente le allocazioni di memoria dal sistema operativo host quando viene chiamato, e free li rilasci direttamente all'host operativo quando chiamato. Ma quasi sempre non funzionano così, invece la libreria standard mantiene una lista circolare di memoria free-d e malloc'd che è opportunisticamente espansa e contratta interagendo con il sistema operativo host (vedere alcune delle risposte su How do malloc() and free() work? per maggiori informazioni dettagli se sei interessato). Indipendentemente dal modo in cui funziona, questo porta a una serie di risultati non intuitivi, incluso il fatto che è solitamente impossibile allocare tutta la memoria che il sistema operativo dice che è gratuita, a volte le allocazioni sembrano non modificare la quantità di memoria libera, e che free a volte non ha alcun effetto sulla quantità di memoria che il sistema operativo dice è gratuita.

Anche se non ho altro che prove empiriche a sostegno di questo, credo che CUDA funzioni esattamente allo stesso modo. Il contesto mantiene il proprio elenco di memoria malloc'd e free, e espanderà e contrarrà la memoria contenuta in tale elenco come driver host/window manager e la stessa GPU stessa. Tutto l'hardware ha una dimensione di pagina MMU caratteristica, e ci sono prove che suggeriscono che le dimensioni della pagina su GPU NVIDIA sono piuttosto grandi. Ciò implica che vi è una granularità piuttosto grossolana nelle chiamate cudaMalloc e che a volte un malloc sembra non influire sulla quantità di memoria libera o consumare molta più memoria di quella richiesta, e talvolta le chiamate free non sembrano avere alcun effetto (Se sei interessato, è possibile trovare un piccolo strumento che aiuta a illustrare il comportamento delle dimensioni della pagina del driver CUDA here, sebbene sia stato scritto per una versione iniziale dell'API CUDA e potrebbe richiedere un paio di modifiche da compilare con le versioni moderne). Credo che questa sia la spiegazione più probabile per il comportamento che stai osservando.

Per inciso, se eseguo una versione semplificata del codice che hai postato su MacOS 10.6 con un dispositivo famiglia GT200:

#include <cstdio> 

#define mexPrintf printf 

inline void gpuAssert(cudaError_t code, char *file, int line, 
       bool abort=true) 
{ 
    if (code != cudaSuccess) 
    { 
     mexPrintf("GPUassert: %s %s %d\n", cudaGetErrorString(code), 
      file, line); 
     if (abort) exit(code); 
    } 
} 

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); } 

inline void gpuMemReport(size_t * avail, size_t * total, 
     const char * title = 0, const size_t * free = 0, const bool sense = true) 
{ 
    char tstring[32] = { '\0' }; 
    gpuErrchk(cudaMemGetInfo(avail, total)); 

    if (free) { 
     if (title) { 
      strncpy(tstring, title, 31); 
     } 
     mexPrintf("%s Memory avaliable: Free: %zu, Total: %zu, %s: %zu\n", 
       tstring, *avail, *total, (sense) ? "Allocated\0" : "Freed\0", 
       (sense) ? (*free - *avail) : (*avail - *free)); 
    } else { 
     mexPrintf("Memory avaliable: Free: %zu, Total: %zu\n", *avail, *total); 
    } 
} 

int main() 
{ 
    size_t freeMem = 0; 
    size_t totalMem = 0; 
    size_t allocMem = 0; 

    gpuErrchk(cudaFree(0)); 
    gpuMemReport(&freeMem, &totalMem); 

    double *devicePulseDelay, *deviceTarDistance, *deviceScattDistance, *deviceScatterers; 
    double *deviceReceivedReal, *deviceReceivedImag; 

    mexPrintf("Allocating memory.\n"); 
    gpuErrchk(cudaMalloc((void **) &devicePulseDelay, sizeof(double)*512)); 
    gpuMemReport(&allocMem, &totalMem, "devicePulseDelay:", &freeMem); 

    gpuErrchk(cudaMalloc((void **) &deviceTarDistance, sizeof(double)*512)); 
    gpuMemReport(&allocMem, &totalMem, "deviceTarDistance:", &freeMem); 

    gpuErrchk(cudaMalloc((void **) &deviceScattDistance, sizeof(double)*999*512)); 
    gpuMemReport(&allocMem, &totalMem, "deviceScattDistance:", &freeMem); 

    gpuErrchk(cudaMalloc((void **) &deviceScatterers, sizeof(double)*999)); 
    gpuMemReport(&allocMem, &totalMem, "deviceScatterers:", &freeMem); 

    gpuErrchk(cudaMalloc((void **) &deviceReceivedReal, sizeof(double)*999*512)); 
    gpuMemReport(&allocMem, &totalMem, "deviceReceivedReal:", &freeMem); 

    gpuErrchk(cudaMalloc((void **) &deviceReceivedImag, sizeof(double)*999*512)); 
    gpuMemReport(&allocMem, &totalMem, "deviceReceivedImag:", &freeMem); 

    mexPrintf("\nFree'ing memory.\n"); 
    gpuMemReport(&freeMem, &totalMem); 

    gpuErrchk(cudaFree(devicePulseDelay)); 
    gpuMemReport(&allocMem, &totalMem, "devicePulseDelay:", &freeMem, false); 

    gpuErrchk(cudaFree(deviceTarDistance)); 
    gpuMemReport(&allocMem, &totalMem, "deviceTarDistance:", &freeMem, false); 

    gpuErrchk(cudaFree(deviceScattDistance)); 
    gpuMemReport(&allocMem, &totalMem, "deviceScattDistance:", &freeMem, false); 

    gpuErrchk(cudaFree(deviceScatterers)); 
    gpuMemReport(&allocMem, &totalMem, "deviceScatterers:", &freeMem, false); 

    gpuErrchk(cudaFree(deviceReceivedReal)); 
    gpuMemReport(&allocMem, &totalMem, "deviceReceivedReal:", &freeMem, false); 

    gpuErrchk(cudaFree(deviceReceivedImag)); 
    gpuMemReport(&allocMem, &totalMem, "deviceReceivedImag:", &freeMem, false); 

    return 0; 
} 

ottengo un risultato diverso, ma anche uno che mostra gli stessi fenomeni:

Allocating memory. 
devicePulseDelay: Memory avaliable: Free: 202870784, Total: 265027584, Allocated: 1048576 
deviceTarDistance: Memory avaliable: Free: 202870784, Total: 265027584, Allocated: 1048576 
deviceScattDistance: Memory avaliable: Free: 198778880, Total: 265027584, Allocated: 5140480 
deviceScatterers: Memory avaliable: Free: 197730304, Total: 265027584, Allocated: 6189056 
deviceReceivedReal: Memory avaliable: Free: 193638400, Total: 265027584, Allocated: 10280960 
deviceReceivedImag: Memory avaliable: Free: 189546496, Total: 265027584, Allocated: 14372864 

Free'ing memory. 
Memory avaliable: Free: 189546496, Total: 265027584 
devicePulseDelay: Memory avaliable: Free: 189546496, Total: 265027584, Freed: 0 
deviceTarDistance: Memory avaliable: Free: 190595072, Total: 265027584, Freed: 1048576 
deviceScattDistance: Memory avaliable: Free: 194686976, Total: 265027584, Freed: 5140480 
deviceScatterers: Memory avaliable: Free: 195735552, Total: 265027584, Freed: 6189056 
deviceReceivedReal: Memory avaliable: Free: 199827456, Total: 265027584, Freed: 10280960 
deviceReceivedImag: Memory avaliable: Free: 203919360, Total: 265027584, Freed: 14372864 

che suggerisce che il comportamento sia hardware/SO dipendente pure.

Problemi correlati