在 GPU 上实现全规模文件系统加速

摘要
现代高性能计算和人工智能计算解决方案经常使用 GPU 作为其主要计算能力来源。这就为 GPU 应用程序的存储操作造成了严重的不平衡,因为每一个此类存储操作都必须向 CPU 发出信号并由 CPU 处理。在 GPU4FS 中,我们针对这种不平衡提出了一个彻底的解决方案:将文件系统的实现转移到应用程序中,并在 GPU 上运行完整的文件系统。这需要对从实际存储布局到文件系统接口的整个文件系统栈进行多次更改。此外,这种方法还能将 CPU 从文件系统管理任务中解放出来,从而更有效地利用 CPU。在我们的预极限实现中,我们展示了在 GPU 上运行一个功能齐全的文件系统是可能的,只需与 CPU 进行最少的交互,根据底层存储介质的不同,带宽甚至具有竞争力。

关键词

文件系统、GPU、直接存储访问、GPU 加速、GPU 卸载

注:本文为翻译文章,原文为:Full-Scale File System Acceleration on GPU

原文作者:(All from Karlsruhe Institute of Technology Germany)

Peter MaucherGregor Lucka Lennard Kittner Lukas Werling Nico Rath Yussuf Khalil Thorsten Gröninger Frank Bellosa 

1、引言

图形处理器(GPU)为数据并行应用提供了大规模并行性。这些数据需要以某种方式加载到 GPU 内存中。目前,数据管理主要由 CPU 处理,GPU 只向 CPU 发送进度信号。假设这些数据来自存储器,则请求必须通过互联总线到达 CPU。在 CPU 实际开始处理该请求后,CPU 必须通过文件系统 (FS) 实现,直到到达存储设备,并在收到响应后向 GPU 发出完成信号。其中有些延迟是不可避免的,尤其是存储延迟,但如果 GPU 直接访问存储设备,则可以避免很多延迟。即使是 CPU 文件系统,Volos 等人[26]认为,最初为硬盘设计的旧式 FS 接口也会增加一些开销。

在本文中,我们将会介绍GPU4FS。这是一种功能齐全的现代 GPU 端 FS,旨在解决 FS 接口以及通过互连线路所引起的延迟问题。GPU4FS 在 GPU 上运行,与实际的 GPU 端应用程序并行,从而实现了应用程序与 FS 之间的低延迟访问和共享内存通信。由于 GPU 上缺乏系统调用指令,这种通信是通过共享显存(VRAM),利用并行工作队列实现的。我们还将工作队列放在 DRAM 中,这样 CPU 端应用就能快速、并行地访问 FS 的用户空间。

我们设计的文件系统具有紧跟现代文件系统的功能集,因为文件系统接口已被程序员广泛使用并熟知。我们不必对每个应用程序进行移植,而是将实现细节完全隐藏起来,不让未感知的应用程序看到,但让 CPU 端应用程序能够选择从更改的语义中获益。在 GPU 上,应用程序需要针对任何类型的存储访问进行修改。Silberstein 等人[24]利用 GPUfs 证明,为 CPU FS 提供库接口可简化 GPU 程序员对存储的访问,但 GPUfs 只能调用 CPU 端文件系统。GPU4FS 提供与 GPUfs 类似的接口,但在 GPU 上运行文件系统。

在我们的初步实现中,我们展示了 GPU 对英特尔 Optane 持久内存(PMem)[19] 的访问,并表明我们的写带宽与同时代的 Optane 文件系统相比具有竞争力。我们还演示了 GPU 优化文件夹结构的实现方法和 RAID 实现方法。我们认为这表明了全功能的 GPU 端文件系统是有用的,而且可以运行得很好。

2、方法

GPU4FS 是一个新颖的想法,它试图将实现从 CPU 转移到 GPU 上,因此在实现过程中,GPU4FS 显示出与当代文件系统的重大差异。为了与现有的 CPU 端应用程序兼容,同时也为了让新的 GPU 端应用程序熟悉 GPU4FS,这些差异需要被 GPU4FS 的界面所隐藏。

2.1 接口

在兼容性方面,最令人感兴趣的是文件系统接口。在 POSIX [17]中,访问通常使用系统调用(syscalls)来处理,而这在 GPU4FS 中是不可行的,原因有以下几点:GPU 上没有经典的系统调用指令,即使有这样的指令,CPU 也肯定无法使用。相反,我们选择了使用共享内存缓冲区进行通信的常见方法(如 FUSE [6])。请求进程将为每个预定的文件系统操作插入一条命令,而 GPU4FS 进程则可以解析这些信息并处理请求。

GPU4FS 计划提供两套命令:一套与 POSIX 接口紧密结合,另一套是高级接口,旨在减少请求数量,从而减少延迟并增加带宽。Volos 等人[26]的研究表明,通过减少交互次数可以实现重大改进:使用 POSIX 接口将单个文件读入内存需要 5 次操作系统交互:调用 open() 获取文件描述符,调用 fstatat() 获取文件长度,然后调用 malloc() 分配内存,接着调用一次或多次 read() 获取实际数据,最后调用 close() 释放文件描述符。使用 mmap()后,这种情况并没有明显改善,因为唯一不需要调用的就是 malloc()。在 read() 和 mmap() 两种情况下,由于其他任务可能会随时更改文件内容和长度等元数据,因此处理过程本身就比较复杂。相反,我们提供了一个加载完整文件的接口,并在命令处理程序中为加载的文件分配内存。结果数据被写入共享缓冲区,并返回指针/长度对。这样,操作可以原子方式处理,只需要一个请求。我们希望在 GPU 应用中混合使用这两种接口:对于文件夹的并行读取,可以使用 POSIX 接口,这样每个项目只需加载一次,但每个文件都可以使用原子请求加载。尽管如此,POSIX 接口仍是兼容性所必需的。

考虑兼容应用程序的一个重要原因是因为其支持 mmap()。在 Linux 中,可以使用私有映射或共享映射,这两种映射有两个独立的特性:共享映射意味着修改后的内存会写回磁盘,但也允许与其他进程共享内存通信。我们假定,大多数应用程序使用共享映射来持久化它们的更改,而不是进行共享内存通信。在只有 CPU 和 DRAM 页面缓存的文件系统中,实现这两种功能相对容易,但如果多个设备都有自己的内存,就会增加复杂性,而且数据必须保存在 DRAM 中,以便所有设备都能访问。为了实现高带宽的 VRAM 侧mmap,我们增加了一个附加的回写模式,只有在未映射时才将数据刷新到磁盘。此外,这还能让我们避免代价高昂的页表更改。我们希望这种模式能广泛应用于与其他文件系统不兼容的 GPU 端应用。

2.2 GPU 实现

概括地说,运行 GPU4FS 的系统至少有两个相应的进程在运行:一个负责处理整个文件系统的 GPU 端 GPU4FS 主进程,另一个是负责设置 GPU 进程和建立通信的 CPU 端进程。此外,CPU 和 GPU 上还可能运行着多个额外进程,与两个 GPU4FS 进程对接。在本节中,我们将介绍 GPU 侧的实现,它负责使用上述共享命令缓冲区与请求进程通信,并与存储后端通信。垃圾回收和碎片整理等文件系统管理任务也由 GPU 控制和运行。

对文件系统的请求总是通过其中一个命令缓冲区发出,或者通过另一个 GPU 端进程发出的 VRAM 中的缓冲区,或者通过 DRAM 中的缓冲区发出任何其他请求。此类请求通常会导致对磁盘或 PMem 的访问,无论是加载还是存储。此外,即使是数据加载请求也会导致存储介质上的数据变化,因为元数据需要更新。

读取请求。首先,我们描述一个没有任何数据变化的读取请求:请求解析后,GPU 会尝试从其缓存(VRAM 或 DRAM)中加载数据。我们同时采用了这两种缓存级别,因为 VRAM 通常要小得多,而 DRAM 比 NVMe 和 PMem 等当代存储设备要快得多,而且早期的一篇论文也指出了 Compute Express Link (CXL) 实现的相同行为[25]。如果请求的数据没有缓存,则会从存储中获取数据。GPU4FS 的主要目标是绕过 CPU 进行存储访问:PMem 直接映射到 GPU,而 NVMe 内存则通过点对点 DMA(P2PDMA)进行访问,正如 Qureshi 等人[21] 为其 BaM 系统架构所建议的那样。数据获取后,可能会根据应用提示进行缓存。我们添加了缓存提示,因为有些应用只需要文件一次,这样就可以释放缓存容量,用于重复访问。除了在共享 mmap 映射中,我们还会在共享内存区域为结果分配空间,并将获取的数据存储在那里。为了发出完成信号,我们会将数据指针和长度存储到初始命令结构中,并通过原子存储完成标志结束交互。

写入请求。与此相反,当需要写入数据时,还需要几个步骤来保证数据的一致性并为新文件分配空间。尽管减少 GPU 端应用的延迟是 GPU4FS 的主要目标,但 CPU 端应用的总体延迟预计会增加。这将增加飞行中的数据量,从而增加一致性系统的压力。我们打算结合使用日志结构化(log-structuring)[23] 和日志(journaling)[20] 来解决这个问题:数据写入采用日志结构化方式,元数据更新则采用日志方式。因此,日志是一个主要的争议点。为了解决这个问题,我们为日志预留了一大块持久存储空间,并为每个独立的 GPU 工作组分配了这一大块存储空间中的一个较小的子区域。为避免同一对象出现多个冲突的日志条目,我们限制每个文件系统对象在运行时最多只能被一个工作组使用。日志条目大小固定,并通过一个原子存储分配给一个标志变量。另一个原子存储标志着日志条目设置的完成。这样,一旦发生崩溃,就能扫描整个日志区域,并验证操作是否完成。要提交数据写入,需要修改 inode 结构,以添加指向新文件系统块的指针。与块设备上的文件系统相比,PMem 只允许较小粒度的数据持久性,这意味着我们无法原子式地就地更改 inode。相反,即使我们使用就地修改,日志也允许恢复新旧状态。

GPU4FS 旨在提供两套命令:其中一套与 POSIX 接口紧密结合,另一套则是高级接口,旨在减少请求数量,从而减少延迟并增加带宽。Volos 等人[26]的研究表明,通过减少交互次数可以实现重大改进:使用 POSIX 接口将单个文件读入内存需要 5 次操作系统交互:调用 open() 获取文件描述符,调用 fstatat() 获取文件长度,然后调用 malloc() 分配内存,接着调用一次或多次 read() 获取实际数据,最后调用 close() 释放文件描述符。使用 mmap()后,这种情况并没有明显改善,因为唯一不需要调用的就是 malloc()。在 read() 和 mmap() 两种情况下,由于其他任务可能会随时更改文件内容和长度等元数据,因此处理过程本身就比较复杂。相反,我们提供了一个加载完整文件的接口,并在命令

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达坦科技DatenLord

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值