不可访问的设备内存2017

原文网址:https://lwn.net/Articles/717614/

原文题目:Unaddressable device memory

原文作者:Jake Edge

原文时间:2017年3月22日

不可访问的设备内存

在2017年Linux存储、文件系统和内存管理会议的第一天早上全体大会上,Glisse发起了一场关于“CPU不可访问的、设备上的内存”的讨论,在GPUs和FPGA的系统中常常会配置这种设备内存。在设备上确实存在这样的内存;与系统主存相比,设备访问设备内存的延迟会更短。Glisse开发了异构内存管理HMM补丁,其设计目标就是方便应用程序开发者能透明地使用这些设备内存。

在GPUs和FPGAs的板卡上有大量这样的设备内存,容量通常为8G~64GB;当前这种设备内存一般是通过mmap()映射设备文件的方式来访问。这种访问方式在OpenGL等图像处理和第一版OpenCL异构计算框架中获得很好的应用,但这种方式会导致“地址空间”碎片化。设备既能访问系统主存也能访问自己本地的设备内存;因为这种设备内存不支持一致性协议和原子操作,所以CPU不能真正使用设备内存。

运行在这些设备上的程序要用到malloc()为数据结构分配的系统内存;GPU和FPGA在访问这些数据结构之前,对应的系统内存单元还需要被钉住(PINed),这样一来,这些数据结构的物理内存单元在被设备访问时就不会被换出。另一种不钉住系统内存的使用方式是,将这些数据结构拷贝到设备内存中,但这种方式比较缓慢而且容易出错。

Glisse说,需要一种共享地址空间机制,实现系统主存可以透明地迁移到设备内存上【这句话有待进一步理解】。

共享地址空间机制逐步成为业界标准;Windows操作系统实现了这种机制,C++标准规定在使用设备内存时也需要用这种机制。和CUDA并行编程框架一样,OpenCL2.0及更高版本也需要这种机制。一旦实现了内存的透明迁移,程序员在编码时就不要考虑代码究竟是在GPU上运行还是在CPU上运行。 当前GPU内存带宽为1TB/s,而PCIe总线带宽为32GB/s,四通道DDR系统主存的带宽为80GB/s。GPU能以更快的速度访问数据,而从内存访问来看,CPU端反而成为了瓶颈。

虽然说存在硬件解决方案的可能性,但是对于普通硬件提供的设备内存并不是常规内存【regular memory:同时支持设备端和CPU端的一致性和原子操作】。因此Glisse说需要软件解决方案。

HMM采用了ZONE_DEVICE分配区域类型,但与以前在全体会议上说的使用方式上有些不同。设备内存虽被标注为ZONE_DEVICE,但同时允许系统主存的数据能往上迁移。从CPU角度来看,这类似于内存被换页到磁盘;如果CPU端需要访问这些内存,就触发页故障,又将数据从设备内存迁移回到系统主存。

Glisse认为共享地址空间机制要解决两个问题。首先要保护系统主存页不能被读或写。然后将页内容复制到设备端,所有来自CPU的读写都会被异常捕获(应该是触发CPU页故障异常)。

有人问道迁移的数据量规模,并说一次做4KB的迁移没有什么意义。Glisse回应说,典型场景至少是几百万字节,通常会迁移10GB数据给到设备内存。GPU对这些数据要进行长时间的计算处理,然后将计算结果迁移回来。在结果返回之前,CPU一般不会访问这些数据。这要视工作负载具体情况而定,要避免一次迁移4KB页大小,这点很重要。

在CPU内存和设备内存之间还可能存在页来来回回迁移的情况【文中称这种情况为pages ping-ponging,这种情况也要避免。Glisse意识到这个问题,但是他认为驱动程序只要运行时间足够长就可以跟踪这类访问,在这种情况下如果发生CPU访问,页就不会被迁移到设备端。Mel Gorman提醒说,如果发生页来回迁移的情况,这可能是应用程序的BUG。

Dave Hansen指出,malloc()分配的内存数据可能面临这种情况,一方面被要求和其他数据一起迁移,另一方面其他数据本身还不能被迁移。Glisse承认这一点,但是也提到,因为设备可以直接访问系统主存,所以可以允许某些页绝不会迁移到设备上,这也不是什么大问题。还有一些分配工具有助于避免这个问题。

将将数据拷贝到设备内存还存一个问题就是,数据存在两份【One problem with mirroring data on the device is that the memory is duplicated】。另一个方法是,将内存数据完全迁移到设备端的ZONE_DEVICE页上,这样CPU根本就访问不到。CPU对设备端ZONE_DEVICE页数据进行读写就会触发回迁。这要求能捕获所有可能的读写,包括系统调用或者直接IO。

AI Viro指出系统调用或直接IO不应该触发回迁操作;相反,应该在调用get_user()和put_user()这两个函数被调用时触发回迁操作【内核态函数get_user从用户空间获取单个数据,内核态函数put_user向用户空间传递单个数据】。他接着说,如果能够捕获用户空间所有的访问操作,就可以确保对内存的所有读写得到处理。

Dan Williams表达了Glisse对ZONE_DEVICE使用的担心,因为ZONE_DEVICE常规用于持久内存【persistent-memory即掉电后数据依然存在的内存】。他想知道这两种用法如何区分的。Glisse说,他提交的补丁对两种用途进行了区分。

Glisse接着建议到,采用通用KSM机制来保护页不被读写【KSM内存共享机制,合并具有相同内容的物理主存页面以减少页面冗余,内核设计了KSM守护进程,定期扫描用户向它申请的内存区域,寻找相同的页面就会将其合并,并用一个写保护的页面来替代】。对于需要保护的页,page->mapping入口项可以用一个指针替换一下,这个指针指向一个保护结构体,所有对page->mapping的逆向引用都可以封装在帮助函数中【逆向引用指针的意思:通过修改指针变量的值,来动态访问数据结构的方法】。

经过Coccinelle工具的检查和修改,补丁本质上并没有变化【Coccinelle:Linux静态代码检查工具】。这些修改对重用KSM机制有好处,但这些修改是否会带来其他影响还不清楚。参会者中有人说,封装也会带来其他好处。Glisse说,他会将补丁用到其他使用场景。

设备内存页也需要回写到系统主存【There is a need to do writeback from the device memory pages】,Glisse建议在面对这种需求时,采用ISA块队列回弹缓冲机制【ISA block queue bounce buffer】,这种机制是上世纪九十年代提出的,现在内核还有相关代码实现【/kernel/block/bounce.c】。James Bottomley指出回弹缓冲机制不仅仅用于ISA设备;不对齐的struct bio结构体也会用到。回弹缓冲代码最终被Glisse用于HMM补丁。Glisse还会给系统管理员提供一些控制方法【knob】,从而帮助将设备内存数据回写到系统主存,这样一来,通过这些控制方法可以获取最后一点的性能提升,这种性能提升可能会损坏文件系统完整性。

一位参会成员建议,内核开发者要就内核引用不可直接访问内存达成共享协议。尽管内核不能直接访问这种类型内存,这种类型的内存可能也需要page结构来管理。这样才会获得普遍认可。

William还对涉及内核其他代码的若干问题表示担心,他依然不确信HMM使用ZONE_DEVICE是否明智。Glisse说,如果有必要他可以新增一个zone类型。Gorman现在到不是特别担心上述问题;Glisse表示同意,他说如果出现问题,他会及时关注。

当前HMM功能还没有上游用户,AMD GPU驱动和各种FPGA驱动在未来会用到HMM,Glisse希望Nouveau驱动也能用到HMM。Gormna说,用户一般认为系统主存要比可用的(或者使用的)设备内存大很多;否则,在数据从设备内存回迁时导致系统活锁。Glisse认同上述观点,认为这可能是一个问题,具体问题还要看补丁的实际应用情况。

Gorman认为现在可以聚焦在kernel接纳HMM补丁问题上;这个补丁对文件系统的影响(例如,回写)可以以后处理。Glisse同意说到,他正在做的工作就是将HMM移植到kernel中,同时也想讨论其他议题,从而确保对文件系统的影响不会导致很大的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值