主机内存分为 可分页内存(Pagable) 和 页锁定内存(固定内存Pinned Memory)
CPU向GPU传输数据时是通过直接内存访问(DMA,Direct Memory Access)传输的。
但是主机虚拟内存中分配的数据在物理内存中是随时可能被移动的,所以当数据在可分页内存时,系统随时可能会移动数据,此时将该数据传输给GPU时,需要将可分页内存复制到一块“临时的”页锁定内存,然后再从这块“临时的页锁定内存“复制到GPU
因此使用页锁定内存会一定程度上加快数据在GPU与CPU之间的传输速度,虽然可能会涉及CPU内存之间的copy,但是CPU内存之间的拷贝速度是大于CPU–>GPU的速度的。
但是,页锁定内存是占用系统的物理内存的,并不能交换到磁盘上,当机器的物理内存比较少时程序运行会受到影响。
因此页锁定内存在不再使用时需要立刻释放。
分配页锁定内存:
①由cudaHostAlloc( )
来进行分配
②在opencv的GPU模块中,申请固定内存存储图片时,可以使用下面的函数来申请
CudaMem img_host(cols,rows, CV_8UC1, CudaMem::ALLOC_PAGE_LOCKED)
释放页锁定内存:
cudaFreeHost ( )
下面是一个将图片传到页锁定内存的应用示例,其中还有相应的CUDA测试运行时间的代码
float feature_match_pl()
{
//数据导入
Mat img1 = imread("D:/Images/14.jpg", CV_LOAD_IMAGE_GRAYSCALE);
CV_Assert(!img1.empty());//CV_Assert()若括号中的表达式值为false,则返回一个错误信息。
Mat img2 = imread("D:/Images/15.jpg", CV_LOAD_IMAGE_GRAYSCALE);
CV_Assert(!img2.empty());
//耗时统计
cudaEvent_t start, stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop);
//计时开始
cudaEventRecord(start, 0);
//申请页锁定内存
CudaMem img1_host(img1.cols, img1.rows, CV_8UC1, CudaMem::ALLOC_PAGE_LOCKED);
CudaMem img2_host(img2.cols, img2.rows, CV_8UC1, CudaMem::ALLOC_PAGE_LOCKED);
memcpy(img1_host.datastart, img1.datastart, img1_host.cols * img1_host.rows);
memcpy(img2_host.datastart, img2.datastart, img2_host.cols * img2_host.rows);
GpuMat img1_gpu, img2_gpu;
//图像传输到设备
img1_gpu.upload(img1_host);
CV_Assert(!img1_gpu.empty());
img2_gpu.upload(img2_host);
CV_Assert(!img2_gpu.empty());
//释放
cudaFreeHost(&img1_host);
cudaFreeHost(&img2_host);
//计时结束
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop);
cudaEventDestroy(start);
cudaEventDestroy(stop);
return (float)elapsedTime / 1000;
}
int main(int argc, char* argv[])
{
//检查CUDA能否正常使用
if (getCudaEnabledDeviceCount() == 0) {
cerr << "此OpenCV编译的时候没有启用CUDA模块" << endl;
return -1;
}
//输出所使用的GPU信息
//cv::gpu::printShortCudaDeviceInfo(cv::gpu::getDevice());
//for (int i = 0; i < 3; i++)
//{
float time2 = feature_match_pl();
printf("使用页锁定内存耗时: %.6f s\n", time2);
//}
waitKey(0);
return 0;
}