0_Simple__simpleZeroCopy
两种方法使用零拷贝内存做简单的向量加和,并评估 GPU 计算结果与 CPU 计算结果的差。
▶ 源代码
#include <stdio.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <helper_functions.h>
#include <helper_cuda.h> #define MEMORY_ALIGNMENT 4096
#define ALIGN_UP(x,size) ( ((size_t)x+(size-1))&(~(size-1)) ) __global__ void vectorAddGPU(float *a, float *b, float *c, int N)
{
int idx = blockIdx.x*blockDim.x + threadIdx.x;
if (idx < N)
c[idx] = a[idx] + b[idx];
} int main(int argc, char **argv)
{
printf("\n\tStart.\n"); // 设备检查
bool bMac;
cudaDeviceProp deviceProp;
cudaSetDevice();
cudaGetDeviceProperties(&deviceProp, );
if (CUDART_VERSION < || !deviceProp.canMapHostMemory)// CUDART_VERSION 为 CUDA Runtime API 版本,CUDA9.0 对应 9000
{
printf("\n\t CUDA Runtime API not support MapHostMemory.\n");
getchar();
return ;
}
cudaSetDeviceFlags(cudaDeviceMapHost);// MapHostFlag 功能正常,设置标志
#if defined(__APPLE__) || defined(MACOSX)// MacOS 系统不支持将普通堆内存设置为页锁定内存
bMac = true;
#else
bMac = false;
#endif
if (CUDART_VERSION < && !bMac)// 既不是 MacOS 系统,Runtime API 版本还不够高
{
printf("\n\tCUDA Runtime API not support cudaHostRegister function.\n");
getchar();
return ;
}
// 总体逻辑:
// CUDA Runtime version < 2200,不支持 MApHostMamory,退出
// CUDA Runtime version ∈[2200, 4000),且为 MAcOS 系统,使用 cudaHostAlloc() + cudaHostAllocMapped
// CUDA Runtime version ∈[2200, 4000),且不是 MAcOS 系统,退出
// CUDA Runtime version ≥ 4000,使用 malloc() + cudaHostRegister() // 内存申请
int nelem = ;
int bytes = nelem * sizeof(float);
float *a, *b, *c;
float *a_UA, *b_UA, *c_UA;
float *d_a, *d_b, *d_c;
if (CUDART_VERSION >= || bMac)
{
a_UA = (float *) malloc(bytes + MEMORY_ALIGNMENT); // 申请时多 4KB,用于滑动对齐,释放内存时以该指针为准
b_UA = (float *) malloc(bytes + MEMORY_ALIGNMENT);
c_UA = (float *) malloc(bytes + MEMORY_ALIGNMENT);
a = (float *) ALIGN_UP(a_UA, MEMORY_ALIGNMENT); // 指针指到 4K 对齐的位置上去,用于计算
b = (float *) ALIGN_UP(b_UA, MEMORY_ALIGNMENT);
c = (float *) ALIGN_UP(c_UA, MEMORY_ALIGNMENT);
cudaHostRegister(a, bytes, CU_MEMHOSTALLOC_DEVICEMAP); // 设置页锁定内存
cudaHostRegister(b, bytes, CU_MEMHOSTALLOC_DEVICEMAP);
cudaHostRegister(c, bytes, CU_MEMHOSTALLOC_DEVICEMAP);
}
else
{
cudaHostAlloc((void **)&a, bytes, cudaHostAllocMapped); // 使用函数 cudaHostAlloc() 一步到位
cudaHostAlloc((void **)&b, bytes, cudaHostAllocMapped);
cudaHostAlloc((void **)&c, bytes, cudaHostAllocMapped);
} // 初始化和内存映射
for (int n = ; n < nelem; n++)
{
a[n] = rand() / (float)RAND_MAX;
b[n] = rand() / (float)RAND_MAX;
}
cudaHostGetDevicePointer((void **)&d_a, (void *)a, );
cudaHostGetDevicePointer((void **)&d_b, (void *)b, );
cudaHostGetDevicePointer((void **)&d_c, (void *)c, ); // 调用内核
dim3 block(, , );
dim3 grid((unsigned int)ceil(nelem / (float)block.x));
vectorAddGPU << <grid, block >> > (d_a, d_b, d_c, nelem);
cudaDeviceSynchronize(); // 检查结果
float errorNorm, refNorm, ref, diff;
errorNorm = .f;
refNorm = .f;
for (int n = ; n < nelem; n++)
{
diff = c[n] - (ref = a[n] + b[n]);// ref 为 CPU 计算的和,diff 为 GPU 计算结果与 CPU 计算结果的差
errorNorm += diff*diff; // 向量 a + b 的两种计算结果的差的平方
refNorm += ref*ref; // 向量 a 与向量 b 的和的平方
}
errorNorm = (float)sqrt((double)errorNorm);
refNorm = (float)sqrt((double)refNorm);
printf("\n\tDifference between GPU and CPU is %f, %f%%\n", errorNorm, errorNorm / refNorm); // 清理工作
if (CUDART_VERSION >= || bMac)
{
cudaHostUnregister(a);
cudaHostUnregister(b);
cudaHostUnregister(c);
free(a_UA);
free(b_UA);
free(c_UA);
}
else
{
cudaFreeHost(a);
cudaFreeHost(b);
cudaFreeHost(c);
}
printf("\n\tFinish.\n");
getchar();
return ;
}
▶ 输出结果:
Start.
Difference between GPU and CPU is 0.000000, 0.000000% Finish.
▶ 涨姿势
● 两种使用零拷贝内存的方法,在代码的逻辑部分进行了说明
● 向上取整的宏函数,只对分母(size)为 2 的整数次幂的情况有效。
#define ALIGN_UP(x,size) ( ((size_t)x+(size-1))&(~(size-1)) )
e.g. size == 4096,则 ~ (size - 1) == 11111111 11111111 11110000 000000002,将其作为模板进行按位且操作,等价于取不低于 4096 的高位。
0_Simple__simpleZeroCopy的更多相关文章
随机推荐
- 51Nod 1009:1009 数字1的数量 (思维)
1009 数字1的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 收藏 关注 给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的 ...
- Python3中 sys.argv的用法
sys.avgr 是一个Python的引用模块.刚好做一个作业需要用到它,在sublime上编辑后运行,试图从结果发现它的用途,然而结果一直都是没结果. 后面在网上查了资料,才明白过来.sys.arg ...
- 实习第二天-String对象的不可变性-未解决
public class Reverse { public static void main(String[] args) { String c1=new String("abc" ...
- FastAdmin 如何用 composer bower 安装
FastAdmin 如何安装 composer bower 众所周知的原因,compower bower 安装并不怎么稳定. 刚开始安装时还有侥幸,用软件安装里的设置端口代理,composer 倒是可 ...
- dell support
部門營業時間 電話號碼訂單支援中小型企業 (員工不多於 500名 )00852-3416-0910 9:00 - 18:00 訂單編號: 810607806 訂單日期: 26/11/2014 客戶 ...
- JUC集合之 CopyOnWriteArraySet
CopyOnWriteArraySet介绍 它是线程安全的无序的集合,可以将它理解成线程安全的HashSet.有意思的是,CopyOnWriteArraySet和HashSet虽然都继承于共同的父类A ...
- nginx定制header返回信息模块ngx_headers_more
http://www.ttlsa.com/nginx/nginx-custom-header-to-return-information-module-ngx_headers_more/ 一. 介绍n ...
- FineUI Grid中WindowField根据列数据决定是否Enalble
前台页面Grid控件中设置OnPreRowDataBound属性,windowFile控件设置ID protected void Grid1_PreRowDataBound(object sender ...
- 【python】字符串函数
1.String模块中的常量: string.digits:数字0~9 string.letters:所有字母(大小写) string.lowercase:所有小写字母 string.printabl ...
- hyperledger fabric各类节点及其故障分析
1.Client节点 client代表由最终用户操作的实体,它必须连接到某一个peer节点或者orderer节点上与区块链网络通信.客户端向endorser提交交易提案,当收集到足够背书后,向排序服务 ...