CUDA C编程6 - 内存管理之内存分配、传输与释放

系列文章目录



前言

这里开始跟大家分享CUDA内存管理相关的知识。


一、内存管理相关概念

这里主要介绍如何使用CUDA函数来显示管理内存和数据移动。

CUDA提供了在主机端准备设备内存的函数,并且显示的向设备传输数据和从设备中获取数据。

1. 内存分配和释放

在主机上使用如下函数分配全局内存:
c u d a E r r o r t c u d a M a l l o c ( v o i d ∗ ∗   d e v P t r , s i z e _ t   c o u n t ) ; cudaError_t cudaMalloc(void**\ devPtr, size\_t\ count); cudaErrortcudaMalloc(void devPtr,size_t count);

c u d a M a l l o c cudaMalloc cudaMalloc函数执行失败则返回 c u d a E r r o r M e m o r y A l l o c a t i o n cudaErrorMemoryAllocation cudaErrorMemoryAllocation,在已分配的全局内存中的值不会被清除,需要从主机上传输的数据来填充所分配的全局内存,或用下列函数将其初始化:
c u d a E r r o r t c u d a M e m s e t ( v o i d   ∗ d e v P t r , i n t   v a l u e , s i z e _ t   c o u n t ) ; cudaError_t cudaMemset(void\ *devPtr, int\ value, size\_t\ count); cudaErrortcudaMemset(void devPtr,int value,size_t count);

一旦已分配的设备全局内存不再被使用,可用如下函数释放该内存空间:
c u d a E r r o r t c u d a F r e e ( v o i d   ∗ d e v P t r ) ; cudaError_t cudaFree(void\ *devPtr); cudaErrortcudaFree(void devPtr);

该函数释放的内存必须由 c u d a M a l l o c cudaMalloc cudaMalloc函数分配,否则,将返回一个错误 c u d a E r r o r I n v a l i d D e v i c e P o i n t e r cudaErrorInvalidDevicePointer cudaErrorInvalidDevicePointer;如果地址空间已被释放, c u d a F r e e cudaFree cudaFree函数也返回一个错误。

这里有一点要特别注意,设备内存的分配和释放操作成本较高,所以应用程序应该重利用设备内存,以减少对整体性能的影响。

2. 内存传输

一旦全局内存分配好了,可用如下函数从主机向设备传输数据:
c u d a E r r o r _ t   c u d a M e m c p y ( v o i d   ∗ d s t , c o n s t   v o i d   ∗ s r c ,   s i z e _ t   c o u n t , e n u m   c u d a M e m c p y K i n d   k i n d ) ; cudaError\_t\ cudaMemcpy(void\ *dst, const\ void\ *src,\ size\_t\ count, enum\ cudaMemcpyKind\ kind); cudaError_t cudaMemcpy(void dst,const void src, size_t count,enum cudaMemcpyKind kind);

这个函数从内存位置src复制count字节到内存位置dst。kind指定了复制方向,取值如下:
c u d a M e m c p y H o s t T o H o s t cudaMemcpyHostToHost cudaMemcpyHostToHost
c u d a M e m c p y H o s t T o D e v i c e cudaMemcpyHostToDevice cudaMemcpyHostToDevice
c u d a M e m c p y D e v i c e T o H o s t cudaMemcpyDeviceToHost cudaMemcpyDeviceToHost
c u d a M e m c p y D e v i c e T o D e v i c e cudaMemcpyDeviceToDevice cudaMemcpyDeviceToDevice

如果指针dst和src与kind指定的复制方向不一致,那么 c u d a M e m c p y cudaMemcpy cudaMemcpy函数的行为就是未定义行为,该函数在大多数情况下都是同步的。

下图显示了从GPU内存与CPU内存间的连接性能。从图中可以看出,GPU芯片和板载GDDR5 GPU内存间的理论峰值带宽非常高,CPU和GPU间通过PCIe Gen2总线相连,这种连接的理论带宽要低得多。因此,主机和设备间的数据传输会降低应用程序的整体性能。
在这里插入图片描述CUDA编程的一个基本原则:应尽可能地减少主机与设备间的传输。

二、内存分配、传输与释放示例

#include <iostream>
#include <cuda.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <device_functions.h>

int main()
{
	//set up device
	int dev = 0;
	cudaSetDevice(dev);

	//memory size
	unsigned int isize = 1 << 22;
	unsigned int nbytes = isize * sizeof(float);

	//get device information
	cudaDeviceProp stDeviceProp;
	cudaGetDeviceProperties(&stDeviceProp, dev);
	printf("starting at ");
	printf("device %d: %s memory size %d nbyte %5.2fMB\n", dev,
		stDeviceProp.name, isize, nbytes / (1024.0f * 1024.0f));

	//allocate the host memory
	float* h_a = (float*)malloc(nbytes);

	//allocate the device memory
	float* d_a;
	cudaMalloc(&d_a, nbytes);

	//initialize the host memory
	for (unsigned int i = 0; i < isize; i++)
		h_a[i] = 0.5f;

	//transfer data from the host to the device
	cudaMemcpy(d_a, h_a, nbytes, cudaMemcpyHostToDevice);

	//tansfer data from the device to the host
	cudaMemcpy(h_a, d_a, nbytes, cudaMemcpyDeviceToHost);

	//free memory
	cudaFree(d_a);
	free(h_a);

	//reset device
	cudaDeviceReset();

	system("pause");
	return 0;
}

总结

这篇内容比较基础,算是入门级别,很适合向本人这样的小白,希望对大家有用!

参考资料

《CUDA C编程权威指南》

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值