2012-05-01 109 views
8

我想分配設備內存,複製到它,在GPU上執行計算,將結果複製回來,然後釋放我分配的設備內存。我想確保我沒有超過極限,我想看看是否在共享內存空間中有足夠的內存來轉儲一些數組。爲什麼CudaFree似乎沒有釋放內存?

當我分配設備內存時,不會返回任何錯誤。當我使用cudaMemGetInfo來檢查分配的內存量時,它看起來像一個cudaMalloc尚未分配任何內存。 當我嘗試釋放內存時,它看起來只有一個指針被釋放。

我正在使用matlab Mexfunction接口來設置GPU內存並啓動內核。在這一點上,我甚至沒有調用內核,只是返回一個單位矩陣的結果。

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)); 

下面是從這個輸出:

 
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 

我覺得有一些明顯的我失蹤。任何人都可以幫助解釋發生了什麼?

編輯:平臺是Windows 7與特斯拉C2050 GPu卡。

+0

你在哪個平臺上運行這個代碼? – talonmies

+0

嘗試在每次調用cudaMemGetInfo()之前將allocMem和totalMem的值清零並檢查cudaMemGetInfo()的返回值。 –

+0

在每次調用cudaMemGetInfo()之前清零allocMem和totalMem沒有任何區別。此外,cudaMemGetInfo調用沒有返回任何錯誤。僅供參考,我的平臺是Tesla C2050 GPU卡上的Windows 7。 –

回答

11

當被調用時,malloc直接從主機操作系統獲取內存分配,free直接將它們釋放回主機在調用時運行,這是相當常見的誤解。但他們幾乎總是不這樣工作,而是標準庫維護一個free'd和malloc'd內存的循環列表,這是通過與主機操作系統進行交互來機會擴展和收縮的(有關更多信息,請參閱How do malloc() and free() work?的一些答案)詳情如果你有興趣)。不管它是如何工作的,這會導致一些非直觀的結果,包括通常不可能分配儘可能多的內存,因爲操作系統說它是免費的,分配有時似乎不會改變可用內存的數量,並且free有時對OS所釋放的內存量沒有影響。

儘管我除了經驗證據以外都支持這一點,但我相信CUDA的工作方式完全相同。上下文維護它自己的malloc'd和free'd內存列表,並且將擴展和收縮列表中作爲主機驅動程序/窗口管理器和GPU本身允許的內存。所有硬件都具有特有的MMU頁面大小,並且有證據表明NVIDIA GPU上的頁面大小相當大。這意味着在cudaMalloc調用中存在相當粗的粒度,並且意味着有時malloc似乎不會影響可用內存量或消耗比請求更多的內存,有時free調用似乎沒有效果(如果您有興趣,您可以找到一個小工具來幫助說明CUDA驅動程序here的頁面大小行爲,儘管它是爲CUDA API的早期版本編寫的,並且可能需要使用現代版本進行一些更改才能編譯)。我相信這是你正在觀察的行爲的最可能的解釋。順便說一句,如果我運行你在MacOS 10上發佈的代碼的簡化版本。6與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; 
} 

我得到了不同的結果,也是一個顯示相同的現象:

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 

這表明行爲依賴,以及硬件/主機操作系統。