cudaMemcpy函数说明
·
1. 函数作用
cudaMemcpy 是CUDA中用于 内存数据复制 的核心函数,主要功能包括:
- 主机(CPU)↔ 设备(GPU):在CPU内存和GPU显存之间传输数据。
- 设备(GPU)↔ 设备(GPU):在GPU显存的不同区域之间复制数据。
类比理解:就像快递员在不同仓库(CPU内存和GPU显存)之间搬运货物(数据)。
2. 函数原型
cudaError_t cudaMemcpy(
void* dst, // 目标地址(指向复制目的地的指针)
const void* src, // 源地址(指向数据源的指针)
size_t count, // 复制的字节数
cudaMemcpyKind kind // 传输方向标识
);
3. 参数详解
(1)dst
- 类型:
void* - 作用:目标内存地址(数据复制的目的地)
- 注意事项:
- 如果方向是
Host→Device,dst必须是设备端指针(通过cudaMalloc分配)。 - 如果方向是
Device→Host,dst必须是主机端指针(如malloc分配)。
- 如果方向是
(2)src
- 类型:
const void* - 作用:源内存地址(数据复制的来源)
- 注意事项:
- 如果方向是
Host→Device,src必须是主机端指针。 - 如果方向是
Device→Host,src必须是设备端指针。
- 如果方向是
(3)count
-
类型:
size_t -
作用:需要复制的字节数
-
计算示例:
int N = 1024; size_t size = N * sizeof(float); // 计算总字节数
(4)kind
- 类型:
cudaMemcpyKind(枚举类型) - 作用:指定数据传输方向
| 传输方向标识 | 说明 |
|---|---|
cudaMemcpyHostToHost | 主机内存 → 主机内存(通常不使用) |
cudaMemcpyHostToDevice | 主机内存 → 设备显存 |
cudaMemcpyDeviceToHost | 设备显存 → 主机内存 |
cudaMemcpyDeviceToDevice | 设备显存 → 设备显存 |
cudaMemcpyDefault | 自动判断方向(需统一内存支持) |
4. 使用示例
场景1:主机→设备(上传数据)
int *h_data = (int*)malloc(1024 * sizeof(int)); // 主机内存
int *d_data;
cudaMalloc(&d_data, 1024 * sizeof(int)); // 设备内存
// 初始化主机数据
for(int i=0; i<1024; i++) h_data[i] = i;
// 拷贝到设备
cudaMemcpy(d_data, h_data, 1024*sizeof(int), cudaMemcpyHostToDevice);
场景2:设备→主机(取回结果)
int *h_result = (int*)malloc(1024 * sizeof(int));
// 拷贝回主机
cudaMemcpy(h_result, d_data, 1024*sizeof(int), cudaMemcpyDeviceToHost);
// 打印结果
for(int i=0; i<5; i++) printf("%d ", h_result[i]); // 输出:0 1 2 3 4
5. 常见错误及处理
错误1:指针类型错误
int *h_data = (int*)malloc(1024 * sizeof(int));
int *d_data;
cudaMalloc(&d_data, 1024 * sizeof(int));
// 错误示例:方向标识错误
cudaMemcpy(d_data, h_data, 1024*sizeof(int), cudaMemcpyDeviceToHost); // ❌
- 错误原因:方向标识与指针类型不匹配。
- 解决方法:检查传输方向和指针类型。
错误2:内存未分配
int *h_data; // 未分配内存
int *d_data;
cudaMalloc(&d_data, 1024 * sizeof(int));
cudaMemcpy(d_data, h_data, 1024*sizeof(int), cudaMemcpyHostToDevice); // ❌
- 错误原因:主机指针
h_data未分配内存。 - 解决方法:使用
malloc或new分配内存。
错误3:字节数错误
int N = 1024;
int *h_data = (int*)malloc(N * sizeof(int));
int *d_data;
cudaMalloc(&d_data, N * sizeof(int));
// 错误示例:少复制了数据
cudaMemcpy(d_data, h_data, 512*sizeof(int), cudaMemcpyHostToDevice); // ❌
- 错误原因:复制的字节数小于实际数据大小。
- 解决方法:准确计算
count参数。
6. 最佳实践
-
始终检查返回值:
cudaError_t err = cudaMemcpy(...); if(err != cudaSuccess) { printf("Error: %s\n", cudaGetErrorString(err)); exit(1); } -
使用
CHECK宏简化代码:#define CHECK(call) { \ cudaError_t err = call; \ if(err != cudaSuccess) { \ printf("Error: %s:%d\n", __FILE__, __LINE__); \ printf("Code:%d, Reason:%s\n", err, cudaGetErrorString(err)); \ exit(1); \ } \ } CHECK(cudaMemcpy(d_data, h_data, size, cudaMemcpyHostToDevice)); -
优先使用
cudaMemcpyDefault(需统一内存):// 自动判断方向(需配置统一内存) cudaMemcpy(dst, src, size, cudaMemcpyDefault);
7. 性能提示
- 减少传输次数:合并多次小数据传输为单次大数据传输。
- 异步传输:使用
cudaMemcpyAsync实现数据传输与计算重叠。 - 固定内存(Pinned Memory):使用
cudaMallocHost分配主机内存可加速传输。
总结
cudaMemcpy 是连接主机与设备数据的桥梁,正确使用时需注意:
- 指针类型:严格区分主机和设备指针。
- 传输方向:明确标识
HostToDevice或DeviceToHost。 - 错误检查:始终验证返回值,避免静默失败。
更多推荐


所有评论(0)