靜態聲明的全局內存變量聲明在全局作用域,不能在主機端代碼中直接用&取值,所以不能用cudaMemcpy進行內存複製
__device__ Type deviceData; __global__ void kernelFunc() { data = ... } int main() { Type hostData; cudaMemcpyToSymbol(deviceData,&hostData,sizeof(Type); kernelFunc <<<1,1>>>(); cudaMemcpyFromSymbol(&value,deviceData,sizeof(Type));
}
動態聲明
__global__ void kernelFunc(Type * deviceData) { ... } int main() { Type * deviceData; cudaMalloc(&deviceData,nBytes); cudaMemcpy(deviceData,hostData,nBytes,cudaMemcpyHostToDevice); kernekFunc(deviceData); cudaMemcpy(hostData,deviceData,nBytes,cudaMemcpyDeviceToHost); cudaFree(deviceData); }
主機到設備的內存傳輸實際經過兩個步驟:
Pageable Memory -> Pinned Memory
Pinned Memory -> device memory
Pinned Memory是主機中不會被換到虛擬內存中的內存,在數據複製時隱式創建,複製完成後會自動銷燬。爲了提高主機到設備內存複製的速度,可以手動申請一段Pinned Memory,但也必須手動地釋放。cudaError_t cudaMallocHost(void **devPtr, size_t count); cudaError_t cudaFreeHost(void *ptr);
零複製內存是主機上一段Pinned Memory,設備端可以直接通過PCI-E總線訪問並會緩存在Cache中。由於主機和設備地址空間不同,零複製內存在主機上的地址需要進行地址映射後才能在設備端使用
//零複製內存申請 cudaError_t cudaHostAlloc(void **pHost, size_t count, unsigned int flags); //主機到設備的地址映射 cudaError_t cudaHostGetDevicePointer(void **pDevice, void *pHost, unsigned int flags);
零內存複製的使用注意點:
只有當計算足夠密集以掩蓋PCI-E總線讀取的延遲時才使用零複製內存
使用零複製內存時要在主機和設備間進行同步動態分配的內存可以是linear memory(線性內存不一定是一維的,也可以是二維或三維的)或CUDA arrays,後者主要用於存儲紋理)
//分配linear memory cudaMalloc cudaMallocPitch cudaMalloc3D cudaHostAlloc //分配CUDA array cudaMallocArray cudaMalloc3DArray
cudaMallocPitch一般用於二維線性數組,當width小於k * 128(k爲整數)時,cuda會自動爲每一行填充內存,實際每行的長度通過pitch返回。所以分配的總內存爲height * (width + pitch)
cudaError_t cudaMallocPitch(void ** devPtr, size_t * pitch, size_t width, size_t height)
- 全局內存傳輸
cudaArray
- cudaArray是專門用於作爲紋理內存的一種全局內存,對GPU而言只讀,可以是一維,二維或三維的。kernel不能直接訪問cudaArray,需要將紋理對象或紋理引用與cudaArray綁定後,訪問紋理對象或紋理引用
計算能力2.0以上的顯卡架構能夠利用surfaces,在gpu端修改cudaArray
創建CUDAMallocArray
cudaError_t cudaMallocArray(struct cudaArray ** array, const struct cudaChannelFormatDesc * desc, size_t width, size_t height = 0, unsigned int flags = 0); struct cudaChannelFormatDesc { int x, y, z, w; //每個通道的位數 enum cudaChannelFormatKind f; //通道的數據類型 };