统一内存(unified memory)是一种逻辑上的概念,它既不是显存、也不是主机内存,而是CPU和GPU都可以访问并能保证一致性的虚拟存储器。使用统一内存对硬件有较高的要求:

  • 对于所有功能,GPU架构都必须不低于Kepler架构,主机应用程序必须为64位。
  • 对于一些较新的功能,至少需要Pascal架构的GPU,且主机必须是Linux系统。

使用统一内存编程的优势如下:

  • 统一内存使编程更加简单。不需要手动将数据在主机和设备之间传输,也不需要针对同一组数据定义两个指针并分别分配主机内存和设备内存。对于某个统一内存变量,可以直接从CPU或GPU中访问。
  • 可能会提供比手工移动数据更好的性能。统一内存的底层实现,可能会自动将一部分数据放到离某个处理器更近的位置,比如部分放到显存中,部分放到主存中,从而让相关数据尽量靠近对应的处理器。虽然统一内存机制可以部分地做到这些,但很多情况下还是需要手动给编译器一些提示,这部分功能需要Linux系统且不低于Pascal架构的GPU。
  • 允许GPU在使用统一内存的情况下,进行超量分配。超出GPU内存额度的部分可能存放在主机上。该功能也要求Linux系统且不低于Pascal架构的GPU。

动态分配统一内存使用的CUDA运行时API函数如下:

cudaError_t cudaMallocManaged(void **devPtr, size_t size, unsigned int flags = cudaMemAttachGlobal);

相比于cudaMalloc函数,该函数多个一个可选参数flags,其默认值cudaMemAttachGlobal代表分配的全局内存可由任何设备通过任何CUDA流进行访问。只能在主机端使用该函数分配统一内存,不能在核函数中使用该函数。分配了统一内存的变量既可以被设备访问,也可以被主机访问。从核函数的角度看,统一内存和普通设备内存在使用上没有任何区别,性能也基本相同。使用动态统一内存改写的数组相加例程如下:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cmath>
#include <cstdio> const double EPSILON = 1.0e-15;
const double a = 1.23;
const double b = 2.34;
const double c = 3.57; void __global__ add(const double* x, const double* y, double* z)
{
const int n = blockDim.x * blockIdx.x + threadIdx.x;
z[n] = x[n] + y[n];
} void check(const double* z, const int N)
{
bool has_error = false;
for (int n = 0; n < N; ++n)
{
if (fabs(z[n] - c) > EPSILON)
{
has_error = true;
}
}
printf("%s\n", has_error ? "Has errors" : "No errors");
} int main(void)
{
const int N = 100000000;
const int M = sizeof(double) * N;
double* x, * y, * z;
cudaMallocManaged((void**)&x, M);
cudaMallocManaged((void**)&y, M);
cudaMallocManaged((void**)&z, M); for (int n = 0; n < N; ++n)
{
x[n] = a;
y[n] = b;
} const int block_size = 128;
const int grid_size = N / block_size;
add << <grid_size, block_size >> > (x, y, z); cudaDeviceSynchronize();
check(z, N); cudaFree(x);
cudaFree(y);
cudaFree(z);
return 0;
}

统一内存也可以静态分配,只要在修饰符的__device__的基础上再加上修饰符__managed__即可。这样的变量是在任何函数外部定义的,可见范围是所在源文件(更准确地说是所在翻译单元)。官方文档《CUDA C++ Programming Guide》中的示例如下:

__device__ __managed__ int ret[1000];
__global__ void AplusB(int a, int b) {
ret[threadIdx.x] = a + b + threadIdx.x;
}
int main() {
AplusB<<< 1, 1000 >>>(10, 100);
cudaDeviceSynchronize();
for(int i = 0; i < 1000; i++)
printf("%d: A+B = %d\n", i, ret[i]);
return 0;
}

《CUDA编程:基础与实践》读书笔记(5):统一内存编程的更多相关文章

  1. 《Essential C++》读书笔记 之 基于对象编程风格

    <Essential C++>读书笔记 之 基于对象编程风格 2014-07-13 4.1 如何实现一个class 4.2 什么是Constructors(构造函数)和Destructor ...

  2. 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理

    二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...

  3. 《编写可维护的javascript》读书笔记(中)——编程实践

    上篇读书笔记系列之:<编写可维护的javascript>读书笔记(上) 上篇说的是编程风格,记录的都是最重要的点,不讲废话,写的比较简洁,而本篇将加入一些实例,因为那样比较容易说明问题. ...

  4. 《jQuery基础教程》读书笔记

    最近在看<jQuery基础教程>这本书,做了点读书笔记以备回顾,不定期更新. 第一章第二章比较基础,就此略过了... 第三章 事件 jQuery中$(document).ready()与j ...

  5. 《Java并发编程的艺术》读书笔记:一、并发编程的目的与挑战

    发现自己有很多读书笔记了,但是一直都是自己闷头背,没有输出,突然想起还有博客圆这么个好平台给我留着位置,可不能荒废了. 此文读的书是<Jvava并发编程的艺术>,方腾飞等著,非常经典的一本 ...

  6. 【读书笔记】C#高级编程 第十三章 异步编程

    (一)异步编程的重要性 使用异步编程,方法调用是在后台运行(通常在线程或任务的帮助下),并不会阻塞调用线程.有3中不同的异步编程模式:异步模式.基于事件的异步模式和新增加的基于任务的异步模式(TAP, ...

  7. 【读书笔记】iOS-GCD-多线程编程

    一,现在一个物理的CPU芯片实际上有64个(64核)CPU,如果1个CPU核虚拟为两个CPU核工作,那么一台计算机上使用多个CPU核就是理所当然的事了.尽管如此,“1个CPU核执行的CPU命令为一条无 ...

  8. 《深入java虚拟机》读书笔记之Java内存区域

    前言 该读书笔记用于记录在学习<深入理解Java虚拟机--JVM高级特性与最佳实践>一书中的一些重要知识点,对其中的部分内容进行归纳,主要是方便之后进行复习. 运行时数据区域 Java虚拟 ...

  9. 《深入分析Java Web技术内幕》读书笔记之JVM内存管理

    今天看JVM的过程中收获颇丰,但一想到这些学习心得将来可能被遗忘,便一阵恐慌,自觉得以后要开始坚持做读书笔记了. 操作系统层面的内存管理 物理内存是一切内存管理的基础,Java中使用的内存和应用程序的 ...

  10. Java并发编程实践读书笔记(2)多线程基础组件

    同步容器 同步容器是指那些对所有的操作都进行加锁(synchronize)的容器.比如Vector.HashTable和Collections.synchronizedXXX返回系列对象: 可以看到, ...

随机推荐

  1. C240731B

    B 游戏类问题 先假设一瓶毒药都不用, 先把治疗的贡献加进答案里面,这样治疗.毒药.攻击的贡献分别是独立的. 如果 \(i\) 位置本来是治疗, 那么用毒药多扣的血是 \(a[i]=(p+r) \ti ...

  2. 在美国和以色列的技术支持下BP机可以爆炸,那么苹果手机是否也可以被远程引爆

    要知道,这一切在技术上都是可以实现的. 由此可见,带电池的产品,最为稳妥的办法就是购买在中国组装的产品,否则其安全性是无法保证的.有人可能会说美国政府不会单独的通过这种方法去定向的杀害某个中国普通人, ...

  3. 安卓微信小程序开发之“蓝牙”

    一.写在前面 在微信当中是支持两种蓝牙模式,分别是"经典蓝牙--BT"和"低功耗蓝牙--BLE".通常在和外围单片机设备进行连接的时候用的是低功耗蓝牙这个模式, ...

  4. getPropByPath:根据字符串路径获取对象属性 : 'obj[0].count'

    function getPropByPath(obj, path, strict) { let tempObj = obj; path = path.replace(/\[(\w+)\]/g, '.$ ...

  5. ubuntu卸载php8后在命令行终端上面还是显示8的版本

    使用apt install了php8然后卸载后发现php -v还是8的版本,找来找去,最后发现是需要卸载sudo apt remove php8.0-cli才行 然后使用 sudo apt autor ...

  6. Linux下二维码识别库Zbar的安装与使用

    1. 安装Zbar sudo apt-get install libzbar-dev 2. 识别流程 读取图像并转换为Zbar内建图像类型 创建Zbar扫描器 设置扫描参数 扫描图像并获取结果 #in ...

  7. MongoDB学习笔记之 第1章 MongoDB的安装

    MongoDB学习笔记之 第1章 MongoDB的安装 MongoDB学习笔记之 第2章 MongoDB的增删改查 MongoDB学习笔记之 第3章 MongoDB的Java驱动 MongoDB学习笔 ...

  8. Java 网页浏览器组件介绍

    王 凯迪, 软件工程师, Convergys 上海研发中心 简介: 使用 Java 开发客户端应用有时会需要使用到浏览器组件,本文将介绍在 Java 用户界面中使用浏览器的四种方法,并且比较它们各自的 ...

  9. 2019GPLT

    2019GPLT 7-2 6翻了 从左到右扫描输入的句子:如果句子中有超过 3 个连续的 6,则将这串连续的 6 替换成 9:但如果有超过 9 个连续的 6,则将这串连续的 6 替换成 27.其他内容 ...

  10. feign 使用

    feign 是netflix 提供的申明式的httpclient调用框架 整合方法 1.添加依赖 <dependency> <groupId>org.springframewo ...