zoukankan      html  css  js  c++  java
  • CUDA_主机内存



    主机内存

    系统中被CPU访问的内存,分为两种类型:可分页内存(pageable memory,一般应用中默认使用)和页锁定内存(page-locked或者pinned)。

    可分页内存即为通过操作系统api(malloc(), new())分配的存储器空间;而页锁定内存始终不会被分配到低速的虚拟内存中,能够保证存在于物理内存中,并且能够通过DMA加速与设备端的通信。

    为了让硬件使用DMA,操作系统允许主机内存进行页锁定,并且因为性能原因,CUDA包含了开发者使用这些操作系统工具的API。页锁定后的且映射为cuda直接访问的锁定的内存允许以下几点:

    • 更快的传输性能;
    • 异步的复制操作(在必要的内存复制结束之前内存复制返回控制给调用者;GPU复制操作与cpu并行的执行);
    • 映射锁页内存可以被cuda内核直接访问

    主机端锁页内存

    使用pinned memory有很多好处:可以达到更高的主机-设备端的数据传送带宽,如果页锁定内存以write-commbined方式分配,带宽更高;某些设备支持DMA功能,在执行内核函数的同时利用pinned memory进行主机端与设备端之间的通信;在某些设备上,pinned memory还可以通过zero-copy功能映射到设备地址空间,从GPU直接访问,这样就不用在主存和显存之间进行数据传输。

    分配锁页内存

    通过cudaHostAlloc()和cudaFreeHost()来分配和释放pinned memory。


    portable memory/可共享锁页内存

    在使用cudaHostAlloc分配页锁定内存时,加上cudaHostAllocPortable标志,可以使多个CPU线程通过共享一块页锁定内存,从而实现cpu线程间的通信。在默认情况下,pinned memory由哪个cpu线程分配,就只有该CPU线程才能访问这块空间。而通过portable memory则可以让控制不同GPU的几个CPU线程共享同一块pinned memory,减少CPU线程间的数据传输和通信。


    write-combined memory/写结合锁页内存

    当CPU对一块内存中的数据进行处理时,会将这块内存上的数据缓存到CPU的L1、L2 Cache中,并且需要监视这块内存中数据的更改,以保证缓存的一致性。

    一般情况下,这种机制可以减少CPU对内存的访问,但在“CPU生产数据,GPU消费数据”模型中,CPU只需要写这块内存数据即可。此时不需要维护缓存一致性,对内存的监视反而会降低性能。

    通过write-combined memory,就可以不使用CPU的L1、L2 Cache对一块pinned memory中的数据进行缓冲,而将Cache资源留给其他程序使用。

    write-combined memory在PCI-e总线传输期间不会被来自CPU的监视打断,可以将主机端-设备端传输带宽提高多达40%。

    在调用cudaHostAlloc()时加上cudaHostAllocWriteCombined标志,就可以将一块pinned memory声明为write-combined memory.

    由于对write-combined memory的访问没有缓存,CPU从write-combined memory上读数据时速度会有所下降。因最好只将CPU端只写的数据存放在write-combined memory中。


    mapped memory/映射锁页内存

    mapped memory拥有两个地址:主机端地址(内存地址)和设备地址(显存地址),可以在kernel中直接访问mapped memory中的数据,而不必再在内存和显存间进行数据拷贝,即zero-copy功能。如果内核程序只需要对mapped memory进行少量读写,这样做可以减少分配显存和数据拷贝的时间。

    mapped memory在主机端的指针可以由cudaHostAlloc()函数获得;它的设备端指针可以通过cudaHostGetDevicePointer()获得,从kernel中访问页锁定内存,需要将设备端指针作为参数传入。

    并不是所有的设备都支持内存映射,通过cudaGetDeviceProperties()函数返回的cudaMapHostMemory属性,可以知道当前设备是否支持mapped memory。如果设备提供支持,可以在调用cudaHostAlloc()时加上cudaHostAllocMapped标志,将pinned memory映射到设备地址空间。

    由于mapped memory可以在CPU端和GPU端访问,所以必须通过同步来保证CPU和GPU对同一块存储器操作的顺序一致性。可以使用流和事件来防止读后写,写后读,以及写后写等错误。

    对mapped memory的访问应该满足与global memory相同的合并访问要求,以获得最佳性能。

    注意:

    • 在执行cuda操作之前,先调用cudaSetDeviceFlags()(加cudaDeviceMapHost标志)进行锁页内存映射。否则,调用cudaHostGetDevicePointer()函数会返回一个错误。
    • 多个主机端线程操作的一块portable memory同时也是mapped memory时,每一个主机线程都必须调用cudaHostGetDevicePointer()获得这一块pinned memory的设备端指针。此时,这一块内存在每个主机端线程中都有一个设备端指针。

    注册锁页内存

    锁页内存注册将内存分配与页锁定和主机内存映射分离。可以实现操作一个已分配的虚拟地址范围,并页锁定它。然后,将其映射给GPU,正如cudaHostAlloc()可以根据需要让内存映射到cuda地址空间或变成可共享的(所有GPU可访问)。

    函数cuMemHostRegister()/cudaHostRegister()cuMemHostUnregister()/cudaHostUnregister()分别实现吧主机内存注册为锁页内存和移除注册的功能。

    注册的内存范围必须是页对齐的;无论是基地址还是大小,都必须是可被操作系统页面大小整除。

    注意:

    当UVA(同一虚拟寻址)有效,所有的锁页内存分配均是映射的和可共享的。这一规则的例外是写结合内存和注册的内存。对于这二者,设备指针可能不同于主机指针,应用程序需要使用cudaHostGetDevicePointer()/cuMemHostGetDevicePointer()查询设备指针。
    
    专注搬砖,擅长搬砖砸自己的脚~~~ Email: ltwbuaa@163.com
  • 相关阅读:
    LPC2478中断控制器以及串口详解
    有效三角形的个数
    小于K的两数之和
    和至少为K的最短子数组
    docker: 构建自己的镜像
    判断字符串是否是异位词
    找出字符串中的最长回文
    knuth洗牌算法
    使用adb命令控制anroid手机
    bitmap以及异或运算法
  • 原文地址:https://www.cnblogs.com/TonvyLeeBlogs/p/13951385.html
Copyright © 2011-2022 走看看