当前位置: 首页 > news >正文

CUDA编程学习(四)内存拷贝

本篇文章介绍如何把存储在主机内存上的数据拷贝到存储到设备显卡的内存上。

我们将逐步分析代码,完整代码如下

#include <cuda_runtime.h> #include "../common/common.h" #include <stdio.h> void initialData(float *ip,int size) { time_t t; srand((unsigned)time(&t)); printf("Matrix is :"); for (int i=0;i<size;i++) { ip[i]=(float)(rand() & 0xFF) / 10.0f; printf("%.2f",ip[i]); } printf("\n"); return; } int main(int argc, char **argv) { int nDeviceNumber =0; cudaError_t error = ErrorCheck(cudaGetDeviceCount(&nDeviceNumber),__FILE__,__LINE__); if(error != cudaSuccess || nDeviceNumber == 0) { printf("No CUDA campatable GPU found!\n"); return -1; } int dev=0; error = ErrorCheck(cudaSetDevice(dev),__FILE__,__LINE__); if(error!=cudaSuccess) { printf("fail to set GPU 0 for computing\n"); return -1; } else{ printf("Set GPU 0 for computing\n"); } int nElem = 16; size_t nBytes = nElem * sizeof(float); float *h_A,*h_B,*gpuRef; h_A =(float *)malloc(nBytes); h_B =(float *)malloc(nBytes); gpuRef =(float *)malloc(nBytes); if(NULL != h_A &&NULL != h_B &&NULL !=gpuRef) { printf("allocate memory successfully\n"); } else{ printf("fail to allocate memory\n"); return -1; } initialData(h_A,nElem); initialData(h_B,nElem); memset(gpuRef,0,nBytes); float *d_A,*d_B,*d_C; cudaMalloc((float **)&d_A,nBytes); cudaMalloc((float **)&d_B,nBytes); cudaMalloc((float **)&d_C,nBytes); if(d_A == NULL || d_B == NULL || d_C==NULL) { printf("fail to allocate memory for GPU\n"); free(h_A); free(h_B); free(gpuRef); return -1; } else { printf("successfully allocate memory for GPU\n"); } if(cudaSuccess == cudaMemcpy(d_A,h_A,nBytes,cudaMemcpyHostToDevice) && cudaSuccess == cudaMemcpy(d_B,h_B,nBytes,cudaMemcpyHostToDevice) && cudaSuccess == cudaMemcpy(d_C,gpuRef,nBytes,cudaMemcpyHostToDevice)) { printf("Successfully copy data from CPU to GPU!\r\n"); } else { printf("fail to copy data from CPU to GPU!\r\n"); } free(h_A); free(h_B); free(gpuRef); cudaFree(d_A); cudaFree(d_B); cudaFree(d_C); cudaDeviceReset(); return 0; }

common.h中定义了一个函数,用于检测CUDA程序运行中的状态是否正确。

#include<sys/time.h> #include<cuda_runtime.h> #include<stdio.h> cudaError_t ErrorCheck(cudaError_t status, const char* filename,int lineNumber) { if (status != cudaSuccess) { printf("CUDA API error:\r\ncode=%d,name=%s,description=%s\r\nfile=%s,line=%d\r\n", status,cudaGetErrorName(status),cudaGetErrorString(status),filename,lineNumber); return status; } return status; }

首先看第一段代码,定义了初始化矩阵的函数

void initialData(float *ip,int size) { time_t t; //时间变量,用于获取系统现在的时间,它的值时刻都在改变 srand((unsigned)time(&t)); //与rand()函数搭配使用,利用t来生成不断变化的种子,使得rand()函数每次运行的结果都不一样 printf("Matrix is: "); for (int i=0; i<size;i++) { ip[i] = (float)(rand()&0xFF)/10.0f; //利用rand()函数生存随机数字给数组ip赋值 printf("%.2f",ip[i]); } printf("\n"); return; }

main函数中的第一部分代码,用于检测GPU是否可用

int nDeviceNumber = 0; //该变量用于存储可用GPU的数量,初始值为0 cudaError_t error = ErrorCheck(cudaGetDeviceCount(&nDeviceNumber),__FILE__,__LINE__); //用于检测可用GPU数量,以及其是否可用 if(error != cudaSuccess || nDeviceNumber == 0) { //如果可用显卡数为0或者cuda启动失败,退出进程 printf("No CUDA campatable GPU found!\n"); return -1; }
int dev=0; //GPU的编号,默认为0 error = ErrorCheck(cudaSetDevice(dev),__FILE__,__LINE__); //设置显卡状态,检测0号显卡是否可用 if(error != cudaSuccess) { printf("fail to set GPU 0 for computing\n"); return -1; } else { printf("Set GPU 0 for computing\n"); }

第二部分,开始分配内存。先分配主机内存,再分配设备内存

int nElem = 16; size_t nBytes = nElem * sizeof(float); //待分配的内存空间的大小 float *h_A,*h_B,*gpuRef; h_A =(float *)malloc(nBytes); h_B =(float *)malloc(nBytes); gpuRef =(float *)malloc(nBytes); //定义主机内存,利用malloc()函数分配指定大小内存 if(NULL != h_A &&NULL != h_B &&NULL !=gpuRef) { //检查是否分配成功 printf("allocate memory successfully\n"); } else{ printf("fail to allocate memory\n"); return -1; } initialData(h_A,nElem); initialData(h_B,nElem); //因为分配的内存空间上可能已经存储了数据,所以需要初始化 memset(gpuRef,0,nBytes); //这块内存上指定长度空间存储的数值都设定为0

分配设备内存

float *d_A,*d_B,*d_C; cudaMalloc((float **)&d_A,nBytes); cudaMalloc((float **)&d_B,nBytes); cudaMalloc((float **)&d_C,nBytes); //利用cuda专门用于分配内存的函数,给指定地址分配内存空间。 //由于C语言传参默认传的是数值,如果要对传参的值进行改变,必须传其指针(地址) if(d_A == NULL || d_B == NULL || d_C==NULL) { //如果分配GPU显存失败,退出,并释放掉已经分配的CPU内存 printf("fail to allocate memory for GPU\n"); free(h_A); free(h_B); free(gpuRef); return -1; } else { printf("successfully allocate memory for GPU\n"); }

第三部分,分配好了主机内存和设备显存以后,开始进行数据拷贝

if(cudaSuccess == cudaMemcpy(d_A,h_A,nBytes,cudaMemcpyHostToDevice) && cudaSuccess == cudaMemcpy(d_B,h_B,nBytes,cudaMemcpyHostToDevice) && cudaSuccess == cudaMemcpy(d_C,gpuRef,nBytes,cudaMemcpyHostToDevice)) { printf("Successfully copy data from CPU to GPU!\r\n"); } //判断数据拷贝是否成功。cudaMemcpy()函数的三个传参分别为设备地址、主机地址、内存大小、以及拷 贝方向(从设备到主机还是从主机到设备,这里是从主机到设备) else { printf("fail to copy data from CPU to GPU!\r\n"); } free(h_A); free(h_B); free(gpuRef); cudaFree(d_A); cudaFree(d_B); cudaFree(d_C); cudaDeviceReset(); //程序结束,释放所有内存 return 0;

使用nvcc进行编译,运行可执行文件,得到:

Set GPU 0 for computing allocate memory successfully Matrix is : Matrix is : successfully allocate memory for GPU Successfully copy data from CPU to GPU! [1] + Done "/usr/bin/gdb" --interpreter=mi --tty=${DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-cuqcf0bg.mrd" 1>"/tmp/Microsoft-MIEngine-Out-f3ch05dq.ck0"

说明拷贝成功

http://www.jsqmd.com/news/486360/

相关文章:

  • 基于FPGA的AM调制解调:包含ModelSim仿真、Quartus 18.1与Vivado ...
  • RFID读写器怎么选更适合企业现场?
  • 国内知名半导体核心部件论坛盘点,2026从业者必关注(附核心亮点) - 品牌2025
  • 2026贵阳室内装修数据出炉:本地口碑TOP5品牌权威盘点 - 精选优质企业推荐榜
  • 文件包含PHP_INCLUDE_TO_SHELL_CHAR_DICT工具详解
  • 2026贵阳装修公司5强名单公布,本地市场格局数据出炉 - 精选优质企业推荐榜
  • 4节点光储直流微网:多目标控制下的光伏MPPT与储能双向DCDC的二次优化与多智能体一致性研究
  • 2026贵阳室内设计5强名单出炉,权威机构发布行业现状 - 精选优质企业推荐榜
  • 2026年三防布批发TOP10企业揭晓,谁将领跑行业?
  • 虚拟机(Red Hat)部署后的优化
  • 2026高二生免高考留学新加坡全指南:避开内卷,直通世界名校 - 品牌2026
  • 超绝openclaw技能skill,herHug让AI更懂你
  • 计算机毕业设计 java 虚拟股票交易系统 Java+SpringBoot 模拟股票交易平台 Web 版股市虚拟交易实训系统
  • 【云藏山鹰代数信息系统】琴语言基础100讲之琴语言解析器梅开二度设计
  • 技术裸奔时代:软件测试行业的社交货币陷阱与专业重构
  • 制造知识断层:软件测试工程师的不可替代性构建策略
  • 基于MATLAB的Kmeans自动寻找最佳聚类中心App:‘手肘法‘确定k值与聚类结果可视化
  • 2026年最新完整java面试题(含答案)
  • 老牌智造,长效守护:2026全国风机五强赋能全场景通风安全能效新标杆 - 深度智识库
  • openYuanrong Agent 方向真实案例验证
  • 基于FPGA的DisplayPort Transmitter IP纯源码,使用fpga的gt收发器
  • 2026贵阳室内设计实惠排行榜发布,权威数据揭示本地格局 - 精选优质企业推荐榜
  • 数据仓库处理架构: lambda架构、kappa架构
  • 计算机毕业设计springboot基于Vue.js的臻品可可平台管理系统 基于SpringBoot与Vue.js的高端巧克力电商运营平台 采用前后端分离架构的精品可可产品在线销售管理系统
  • Coze自动化工作流+Agent智能体实战教程(0基础入门,附多场景实操)
  • 刷题篇-1
  • 基于FFT傅里叶变换的QPSK基带信号频偏估计与补偿算法的FPGA实现:从调制到补偿的完整流程...
  • 画说:一个开箱即用的白板录屏工具,专为知识讲解而生
  • 计算机毕业设计springboot基于Vue的北方消逝民族网站的设计与实现 基于SpringBoot与Vue.js的北方濒危民族文化数字化传承平台 采用前后端分离架构的北方少数民族历史文化在线展示系统
  • 和 AI 聊天不难,难的是长期协作:我做了一套三层机制